Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 andreas 1
/*
268 andreas 2
 * Copyright (C) 2020 to 2023 by Andreas Theofilu <andreas@theosys.at>
2 andreas 3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
3 andreas 18
 
19
#include <string>
20
#include <memory>
40 andreas 21
#include <algorithm>
67 andreas 22
#include <codecvt>
169 andreas 23
#include <fstream>
6 andreas 24
 
25
#include <include/core/SkPixmap.h>
3 andreas 26
#include <include/core/SkSize.h>
4 andreas 27
#include <include/core/SkColor.h>
7 andreas 28
#include <include/core/SkFont.h>
29
#include <include/core/SkTypeface.h>
8 andreas 30
#include <include/core/SkFontMetrics.h>
19 andreas 31
#include <include/core/SkTextBlob.h>
8 andreas 32
#include <include/core/SkRegion.h>
33
#include <include/core/SkImageFilter.h>
34
#include <include/effects/SkImageFilters.h>
35
#include <include/core/SkPath.h>
10 andreas 36
#include <include/core/SkSurfaceProps.h>
258 andreas 37
#ifndef __MACH__
26 andreas 38
#include <include/core/SkFilterQuality.h>
258 andreas 39
#endif
66 andreas 40
#include <include/core/SkMaskFilter.h>
169 andreas 41
#include <include/core/SkImageEncoder.h>
179 andreas 42
#include <include/core/SkRRect.h>
258 andreas 43
 
182 andreas 44
//#ifdef __ANDROID__
45
//#include <QtAndroidExtras/QAndroidJniObject>
46
//#include <QtAndroid>
47
//#endif
23 andreas 48
 
2 andreas 49
#include "tbutton.h"
94 andreas 50
#include "thttpclient.h"
3 andreas 51
#include "terror.h"
52
#include "tconfig.h"
4 andreas 53
#include "tresources.h"
8 andreas 54
#include "ticons.h"
14 andreas 55
#include "tamxnet.h"
56
#include "tpagemanager.h"
71 andreas 57
#include "tsystemsound.h"
97 andreas 58
#include "timgcache.h"
225 andreas 59
#include "turl.h"
291 andreas 60
#include "tlock.h"
332 andreas 61
#if TESTMODE == 1
62
#include "testmode.h"
63
#endif
2 andreas 64
 
15 andreas 65
using std::exception;
3 andreas 66
using std::string;
67
using std::vector;
68
using std::unique_ptr;
69
using std::map;
70
using std::pair;
15 andreas 71
using std::thread;
72
using std::atomic;
73
using std::mutex;
21 andreas 74
using std::bind;
2 andreas 75
using namespace Button;
76 andreas 76
using namespace Expat;
2 andreas 77
 
206 andreas 78
#define MAX_BUFFER          65536
21 andreas 79
 
192 andreas 80
#define RLOG_INFO           0x00fe
81
#define RLOG_WARNING        0x00fd
82
#define RLOG_ERROR          0x00fb
83
#define RLOG_TRACE          0x00f7
84
#define RLOG_DEBUG          0x00ef
85
#define RLOG_PROTOCOL       0x00f8
86
#define RLOG_ALL            0x00e0
87
 
8 andreas 88
extern TIcons *gIcons;
14 andreas 89
extern amx::TAmxNet *gAmxNet;
26 andreas 90
extern TPageManager *gPageManager;
8 andreas 91
 
21 andreas 92
THR_REFRESH_t *TButton::mThrRefresh = nullptr;
94 andreas 93
vector<BITMAP_CACHE> nBitmapCache;     // Holds the images who are delayed because they are external
21 andreas 94
 
110 andreas 95
SYSTEF_t sysTefs[] = {
96
    {  1, "Outline-S" },
97
    {  2, "Outline-M" },
98
    {  3, "Outline-L" },
99
    {  4, "Outline-X" },
100
    {  5, "Glow-S" },
101
    {  6, "Glow-M" },
102
    {  7, "Glow-L" },
103
    {  8, "Glow-X" },
104
    {  9, "Soft Drop Shadow 1" },
105
    { 10, "Soft Drop Shadow 2" },
106
    { 11, "Soft Drop Shadow 3" },
107
    { 12, "Soft Drop Shadow 4" },
108
    { 13, "Soft Drop Shadow 5" },
109
    { 14, "Soft Drop Shadow 6" },
110
    { 15, "Soft Drop Shadow 7" },
111
    { 16, "Soft Drop Shadow 8" },
112
    { 17, "Medium Drop Shadow 1" },
113
    { 18, "Medium Drop Shadow 2" },
114
    { 19, "Medium Drop Shadow 3" },
115
    { 20, "Medium Drop Shadow 4" },
116
    { 21, "Medium Drop Shadow 5" },
117
    { 22, "Medium Drop Shadow 6" },
118
    { 23, "Medium Drop Shadow 7" },
119
    { 24, "Medium Drop Shadow 8" },
120
    { 25, "Hard Drop Shadow 1" },
121
    { 26, "Hard Drop Shadow 2" },
122
    { 27, "Hard Drop Shadow 3" },
123
    { 28, "Hard Drop Shadow 4" },
124
    { 29, "Hard Drop Shadow 5" },
125
    { 30, "Hard Drop Shadow 6" },
126
    { 31, "Hard Drop Shadow 7" },
127
    { 32, "Hard Drop Shadow 8" },
128
    { 33, "Soft Drop Shadow 1 with outline" },
129
    { 34, "Soft Drop Shadow 2 with outline" },
130
    { 35, "Soft Drop Shadow 3 with outline" },
131
    { 36, "Soft Drop Shadow 4 with outline" },
132
    { 37, "Soft Drop Shadow 5 with outline" },
133
    { 38, "Soft Drop Shadow 6 with outline" },
134
    { 39, "Soft Drop Shadow 7 with outline" },
135
    { 40, "Soft Drop Shadow 8 with outline" },
136
    { 41, "Medium Drop Shadow 1 with outline" },
137
    { 42, "Medium Drop Shadow 2 with outline" },
138
    { 43, "Medium Drop Shadow 3 with outline" },
139
    { 44, "Medium Drop Shadow 4 with outline" },
140
    { 45, "Medium Drop Shadow 5 with outline" },
141
    { 46, "Medium Drop Shadow 6 with outline" },
142
    { 47, "Medium Drop Shadow 7 with outline" },
143
    { 48, "Medium Drop Shadow 8 with outline" },
144
    { 49, "Hard Drop Shadow 1 with outline" },
145
    { 50, "Hard Drop Shadow 2 with outline" },
146
    { 51, "Hard Drop Shadow 3 with outline" },
147
    { 52, "Hard Drop Shadow 4 with outline" },
148
    { 53, "Hard Drop Shadow 5 with outline" },
149
    { 54, "Hard Drop Shadow 6 with outline" },
150
    { 55, "Hard Drop Shadow 7 with outline" },
151
    { 56, "Hard Drop Shadow 8 with outline" },
152
    { 0,  "\0" }
153
};
154
 
3 andreas 155
TButton::TButton()
2 andreas 156
{
3 andreas 157
    DECL_TRACER("TButton::TButton()");
16 andreas 158
 
21 andreas 159
    mAniRunning = false;
16 andreas 160
    mLastBlink.clear();
2 andreas 161
}
162
 
3 andreas 163
TButton::~TButton()
2 andreas 164
{
3 andreas 165
    DECL_TRACER("TButton::~TButton()");
166
 
15 andreas 167
    if (ap == 0 && ad == 8)
168
    {
169
        if (gAmxNet)
170
            gAmxNet->deregNetworkState(mHandle);
171
    }
172
 
173
    if (ap == 0 && ((ad >= 141 && ad <= 143) || (ad >= 151 && ad <= 158)))
174
    {
175
        if (gAmxNet)
176
            gAmxNet->deregTimer(mHandle);
177
    }
178
 
36 andreas 179
    if (ap == 0 && ad == 81)    // Network state multi bargraph
180
    {
181
        if (gPageManager)
182
            gPageManager->unregCallbackNetState(mHandle);
183
    }
184
 
15 andreas 185
    if (mTimer)
186
    {
187
        mTimer->stop();
188
 
189
        while (mTimer->isRunning())
190
            usleep(50);
191
 
192
        delete mTimer;
193
    }
21 andreas 194
 
93 andreas 195
    if (mAniRunning)
196
    {
197
        ulong tm = nu * ru + nd * rd;
198
        mAniStop = true;
199
 
200
        while (mAniRunning)
201
            std::this_thread::sleep_for(std::chrono::milliseconds(tm * 100));
202
    }
203
 
21 andreas 204
    THR_REFRESH_t *next, *p = mThrRefresh;
205
 
206
    while (p)
207
    {
208
        if (p->mImageRefresh)
209
        {
210
            p->mImageRefresh->stop();
34 andreas 211
            int counter = 0;
21 andreas 212
 
34 andreas 213
            while (counter < 1000 && p->mImageRefresh->isRunning())
214
            {
21 andreas 215
                usleep(50);
34 andreas 216
                counter++;
217
            }
21 andreas 218
 
219
            delete p->mImageRefresh;
220
            p->mImageRefresh = nullptr;
221
        }
222
 
223
        next = p->next;
224
        delete p;
225
        p = next;
226
    }
35 andreas 227
 
228
    mThrRefresh = nullptr;
2 andreas 229
}
3 andreas 230
 
76 andreas 231
size_t TButton::initialize(TExpat *xml, size_t index)
3 andreas 232
{
78 andreas 233
    DECL_TRACER("TButton::initialize(TExpat *xml, size_t index)");
3 andreas 234
 
76 andreas 235
    if (!xml || index == TExpat::npos)
3 andreas 236
    {
237
        MSG_ERROR("Invalid NULL parameter passed!");
238
        TError::setError();
76 andreas 239
        return TExpat::npos;
3 andreas 240
    }
241
 
177 andreas 242
    mChanged = true;
76 andreas 243
    vector<ATTRIBUTE_t> attrs = xml->getAttributes(index);
244
    string stype = xml->getAttribute("type", attrs);
3 andreas 245
    type = getButtonType(stype);
246
    MSG_DEBUG("Button type: " << stype << " --> " << type);
76 andreas 247
    string ename, content;
248
    size_t oldIndex = index;
3 andreas 249
 
76 andreas 250
    while((index = xml->getNextElementFromIndex(index, &ename, &content, &attrs)) != TExpat::npos)
3 andreas 251
    {
252
        if (ename.compare("bi") == 0)
162 andreas 253
        {
76 andreas 254
            bi = xml->convertElementToInt(content);
162 andreas 255
            MSG_DEBUG("Processing button index: " << bi);
256
        }
193 andreas 257
        else if (ename.compare("na") == 0)          // Name
76 andreas 258
            na = content;
193 andreas 259
        else if (ename.compare("bd") == 0)          // Description
76 andreas 260
            bd = content;
193 andreas 261
        else if (ename.compare("lt") == 0)          // Left
76 andreas 262
            lt = xml->convertElementToInt(content);
193 andreas 263
        else if (ename.compare("tp") == 0)          // Top
76 andreas 264
            tp = xml->convertElementToInt(content);
193 andreas 265
        else if (ename.compare("wt") == 0)          // Width
76 andreas 266
            wt = xml->convertElementToInt(content);
193 andreas 267
        else if (ename.compare("ht") == 0)          // Height
76 andreas 268
            ht = xml->convertElementToInt(content);
193 andreas 269
        else if (ename.compare("zo") == 0)          // Z-Order
76 andreas 270
            zo = xml->convertElementToInt(content);
193 andreas 271
        else if (ename.compare("hs") == 0)          // bounding
76 andreas 272
            hs = content;
193 andreas 273
        else if (ename.compare("bs") == 0)          // border style
76 andreas 274
            bs = content;
193 andreas 275
        else if (ename.compare("fb") == 0)          // feedback type
76 andreas 276
            fb = getButtonFeedback(content);
193 andreas 277
        else if (ename.compare("ap") == 0)          // address port
76 andreas 278
            ap = xml->convertElementToInt(content);
193 andreas 279
        else if (ename.compare("ad") == 0)          // address code
76 andreas 280
            ad = xml->convertElementToInt(content);
193 andreas 281
        else if (ename.compare("ch") == 0)          // channel code
76 andreas 282
            ch = xml->convertElementToInt(content);
193 andreas 283
        else if (ename.compare("cp") == 0)          // channel port
76 andreas 284
            cp = xml->convertElementToInt(content);
193 andreas 285
        else if (ename.compare("lp") == 0)          // level port
76 andreas 286
            lp = xml->convertElementToInt(content);
193 andreas 287
        else if (ename.compare("lv") == 0)          // level code
76 andreas 288
            lv = xml->convertElementToInt(content);
193 andreas 289
        else if (ename.compare("dr") == 0)          // level direction
76 andreas 290
            dr = content;
193 andreas 291
        else if (ename.compare("co") == 0)          // command port
147 andreas 292
            co = xml->convertElementToInt(content);
193 andreas 293
        else if (ename.compare("cm") == 0)          // commands to send on button hit
149 andreas 294
            cm.push_back(content);
193 andreas 295
        else if (ename.compare("va") == 0)          // ?
76 andreas 296
            va = xml->convertElementToInt(content);
193 andreas 297
        else if (ename.compare("rm") == 0)          // State count
76 andreas 298
            rm = xml->convertElementToInt(content);
193 andreas 299
        else if (ename.compare("nu") == 0)          // Animate time up
76 andreas 300
            nu = xml->convertElementToInt(content);
193 andreas 301
        else if (ename.compare("nd") == 0)          // Animate time down
76 andreas 302
            nd = xml->convertElementToInt(content);
193 andreas 303
        else if (ename.compare("ar") == 0)          // Auto repeat state
76 andreas 304
            ar = xml->convertElementToInt(content);
193 andreas 305
        else if (ename.compare("ru") == 0)          // Animate time up (bargraph on click)
76 andreas 306
            ru = xml->convertElementToInt(content);
193 andreas 307
        else if (ename.compare("rd") == 0)          // Animate time down (bargraph on click)
76 andreas 308
            rd = xml->convertElementToInt(content);
193 andreas 309
        else if (ename.compare("lu") == 0)          // Animate time up (bargraph)
76 andreas 310
            lu = xml->convertElementToInt(content);
193 andreas 311
        else if (ename.compare("ld") == 0)          // Animate time down (bargraph)
76 andreas 312
            ld = xml->convertElementToInt(content);
193 andreas 313
        else if (ename.compare("rv") == 0)          // ?
76 andreas 314
            rv = xml->convertElementToInt(content);
193 andreas 315
        else if (ename.compare("rl") == 0)          // Bargraph range low
76 andreas 316
            rl = xml->convertElementToInt(content);
193 andreas 317
        else if (ename.compare("rh") == 0)          // Bargraph range high
76 andreas 318
            rh = xml->convertElementToInt(content);
193 andreas 319
        else if (ename.compare("ri") == 0)          // Bargraph inverted (0 = normal, 1 = inverted)
76 andreas 320
            ri = xml->convertElementToInt(content);
193 andreas 321
        else if (ename.compare("rn") == 0)          // Bargraph: Range drag increment
76 andreas 322
            rn = xml->convertElementToInt(content);
193 andreas 323
        else if (ename.compare("lf") == 0)          // Bargraph function
76 andreas 324
            lf = content;
193 andreas 325
        else if (ename.compare("sd") == 0)          // Name/Type of slider for a bargraph
76 andreas 326
            sd = content;
193 andreas 327
        else if (ename.compare("sc") == 0)          // Color of slider (for bargraph)
76 andreas 328
            sc = content;
193 andreas 329
        else if (ename.compare("mt") == 0)          // Length of text area
76 andreas 330
            mt = xml->convertElementToInt(content);
193 andreas 331
        else if (ename.compare("dt") == 0)          // Textarea multiple/single line
76 andreas 332
            dt = content;
193 andreas 333
        else if (ename.compare("im") == 0)          // Input mask of a text area
76 andreas 334
            im = content;
301 andreas 335
        else if (ename.compare("so") == 0)          // String output port
336
            so = xml->convertElementToInt(content);
193 andreas 337
        else if (ename.compare("op") == 0)          // String the button send
76 andreas 338
            op = content;
193 andreas 339
        else if (ename.compare("pc") == 0)          // Password character for text area (single line)
76 andreas 340
            pc = content;
193 andreas 341
        else if (ename.compare("ta") == 0)          // Listbox table channel
342
            ta = xml->convertElementToInt(content);
343
        else if (ename.compare("ti") == 0)          // Listbox table address channel of rows
344
            ti = xml->convertElementToInt(content);
345
        else if (ename.compare("tr") == 0)          // Listbox number of rows
346
            tr = xml->convertElementToInt(content);
347
        else if (ename.compare("tc") == 0)          // Listbox number of columns
348
            tc = xml->convertElementToInt(content);
349
        else if (ename.compare("tj") == 0)          // Listbox row height
350
            tj = xml->convertElementToInt(content);
351
        else if (ename.compare("tk") == 0)          // Listbox preferred row height
352
            tk = xml->convertElementToInt(content);
353
        else if (ename.compare("of") == 0)          // Listbox list offset: 0=disabled/1=enabled
354
            of = xml->convertElementToInt(content);
355
        else if (ename.compare("tg") == 0)          // Listbox managed: 0=no/1=yes
356
            tg = xml->convertElementToInt(content);
279 andreas 357
        else if (ename.compare("st") == 0)          // SubPageView index
358
            st = xml->convertElementToInt(content);
359
        else if (ename.compare("ws") == 0)          // SubPageView: Wrap subpages; 1 = YES
360
            ws = xml->convertElementToInt(content);
361
        else if (ename.compare("sa") == 0)          // SubPageView: Percent of space between items in list
362
            sa = xml->convertElementToInt(content);
363
        else if (ename.compare("dy") == 0)          // SubPageView: Allow dynamic reordering; 1 = YES
364
            dy = xml->convertElementToInt(content);
365
        else if (ename.compare("rs") == 0)          // SubPageView: Reset view on show; 1 = YES
366
            rs = xml->convertElementToInt(content);
367
        else if (ename.compare("on") == 0)          // SubPageView direction
368
            on = content;
300 andreas 369
        else if (ename.compare("ba") == 0)          // SubPageView scrollbar
370
            ba = xml->convertElementToInt(content);
371
        else if (ename.compare("bo") == 0)          // SubPageView scrollbar offset
372
            bo = xml->convertElementToInt(content);
373
        else if (ename.compare("we") == 0)          // SubViewPage Anchor position
374
            we = content;
193 andreas 375
        else if (ename.compare("hd") == 0)          // 1 = Hidden, 0 = Normal visible
76 andreas 376
            hd = xml->convertElementToInt(content);
193 andreas 377
        else if (ename.compare("da") == 0)          // 1 = Disabled, 0 = Normal active
76 andreas 378
            da = xml->convertElementToInt(content);
193 andreas 379
        else if (ename.compare("ac") == 0)          // Direction of text (guess)
51 andreas 380
        {
193 andreas 381
            ac_di = xml->getAttributeInt("di", attrs);  // 0 = left to right; 1 = right to left
51 andreas 382
        }
193 andreas 383
        else if (ename.compare("pf") == 0)          // Function call
3 andreas 384
        {
385
            PUSH_FUNC_T pf;
76 andreas 386
            pf.pfName = content;
387
            pf.pfType = xml->getAttribute("type", attrs);
3 andreas 388
            pushFunc.push_back(pf);
389
        }
193 andreas 390
        else if (ename.compare("sr") == 0)          // Section state resources
3 andreas 391
        {
392
            SR_T bsr;
193 andreas 393
            bsr.number = xml->getAttributeInt("number", attrs); // State number
76 andreas 394
            string e;
3 andreas 395
 
76 andreas 396
            while ((index = xml->getNextElementFromIndex(index, &e, &content, &attrs)) != TExpat::npos)
3 andreas 397
            {
193 andreas 398
                if (e.compare("do") == 0)           // Draw order
76 andreas 399
                    bsr._do = content;
193 andreas 400
                else if (e.compare("bs") == 0)      // Frame type
76 andreas 401
                    bsr.bs = content;
193 andreas 402
                else if (e.compare("mi") == 0)      // Chameleon image
76 andreas 403
                    bsr.mi = content;
193 andreas 404
                else if (e.compare("cb") == 0)      // Border color
76 andreas 405
                    bsr.cb = content;
193 andreas 406
                else if (e.compare("cf") == 0)      // Fill color
76 andreas 407
                    bsr.cf = content;
193 andreas 408
                else if (e.compare("ct") == 0)      // Text color
76 andreas 409
                    bsr.ct = content;
193 andreas 410
                else if (e.compare("ec") == 0)      // Text effect color
76 andreas 411
                    bsr.ec = content;
193 andreas 412
                else if (e.compare("bm") == 0)      // Bitmap image
3 andreas 413
                {
76 andreas 414
                    bsr.bm = content;
415
                    bsr.dynamic = ((xml->getAttributeInt("dynamic", attrs) == 1) ? true : false);
3 andreas 416
                }
193 andreas 417
                else if (e.compare("sd") == 0)      // Sound file
76 andreas 418
                    bsr.sd = content;
193 andreas 419
                else if (e.compare("sb") == 0)      // index external graphic
76 andreas 420
                    bsr.sb = xml->convertElementToInt(content);
193 andreas 421
                else if (e.compare("ii") == 0)      // Icon index
76 andreas 422
                    bsr.ii = xml->convertElementToInt(content);
193 andreas 423
                else if (e.compare("ji") == 0)      // Icon/bitmap orientation
76 andreas 424
                    bsr.ji = xml->convertElementToInt(content);
193 andreas 425
                else if (e.compare("jb") == 0)      // Bitmap orientation
76 andreas 426
                    bsr.jb = xml->convertElementToInt(content);
193 andreas 427
                else if (e.compare("bx") == 0)      // Absolute image position X
76 andreas 428
                    bsr.bx = xml->convertElementToInt(content);
193 andreas 429
                else if (e.compare("by") == 0)      // Absolute image position Y
76 andreas 430
                    bsr.by = xml->convertElementToInt(content);
193 andreas 431
                else if (e.compare("ix") == 0)      // Absolute Icon position X
76 andreas 432
                    bsr.ix = xml->convertElementToInt(content);
193 andreas 433
                else if (e.compare("iy") == 0)      // Absolute Icon position Y
76 andreas 434
                    bsr.iy = xml->convertElementToInt(content);
193 andreas 435
                else if (e.compare("fi") == 0)      // Font index
76 andreas 436
                    bsr.fi = xml->convertElementToInt(content);
193 andreas 437
                else if (e.compare("te") == 0)      // Text
76 andreas 438
                    bsr.te = content;
193 andreas 439
                else if (e.compare("jt") == 0)      // Text orientation
76 andreas 440
                    bsr.jt = (TEXT_ORIENTATION)xml->convertElementToInt(content);
193 andreas 441
                else if (e.compare("tx") == 0)      // Absolute text position X
76 andreas 442
                    bsr.tx = xml->convertElementToInt(content);
193 andreas 443
                else if (e.compare("ty") == 0)      // Absolute text position Y
76 andreas 444
                    bsr.ty = xml->convertElementToInt(content);
193 andreas 445
                else if (e.compare("ww") == 0)      // Word wrap
76 andreas 446
                    bsr.ww = xml->convertElementToInt(content);
193 andreas 447
                else if (e.compare("et") == 0)      // Text effects
76 andreas 448
                    bsr.et = xml->convertElementToInt(content);
193 andreas 449
                else if (e.compare("oo") == 0)      // Opacity
76 andreas 450
                    bsr.oo = xml->convertElementToInt(content);
3 andreas 451
 
76 andreas 452
                oldIndex = index;
3 andreas 453
            }
454
 
455
            sr.push_back(bsr);
456
        }
457
 
76 andreas 458
        if (index == TExpat::npos)
459
            index = oldIndex + 1;
460
    }
3 andreas 461
 
100 andreas 462
    visible = !hd;  // set the initial visibility
463
/*
83 andreas 464
    if (sr.size() > 0 && TStreamError::checkFilter(HLOG_DEBUG))
76 andreas 465
    {
466
        MSG_DEBUG("bi  : " << bi);
467
        MSG_DEBUG("na  : " << na);
468
        MSG_DEBUG("type: " << type);
469
        MSG_DEBUG("lt  : " << lt);
470
        MSG_DEBUG("tp  : " << tp);
471
        MSG_DEBUG("wt  : " << wt);
472
        MSG_DEBUG("ht  : " << ht);
473
 
474
        vector<SR_T>::iterator iter;
475
        size_t pos = 1;
476
 
477
        for (iter = sr.begin(); iter != sr.end(); ++iter)
3 andreas 478
        {
76 andreas 479
            MSG_DEBUG("   " << pos << ": id: " << iter->number);
480
            MSG_DEBUG("   " << pos << ": bs: " << iter->bs);
481
            MSG_DEBUG("   " << pos << ": cb: " << iter->cb);
482
            MSG_DEBUG("   " << pos << ": cf: " << iter->cf);
483
            MSG_DEBUG("   " << pos << ": ct: " << iter->ct);
484
            MSG_DEBUG("   " << pos << ": ec: " << iter->ec);
485
            MSG_DEBUG("   " << pos << ": bm: " << iter->bm);
486
            MSG_DEBUG("   " << pos << ": mi: " << iter->mi);
487
            MSG_DEBUG("   " << pos << ": fi: " << iter->fi);
488
            MSG_DEBUG("   " << pos << ": te: " << iter->te);
489
            pos++;
3 andreas 490
        }
491
    }
100 andreas 492
*/
162 andreas 493
    MSG_DEBUG("Added button " << bi << " --> " << na);
494
 
76 andreas 495
    if (index == TExpat::npos)
496
        return oldIndex + 1;
497
 
498
    return index;
3 andreas 499
}
500
 
43 andreas 501
bool TButton::createSoftButton(const EXTBUTTON_t& bt)
502
{
503
    DECL_TRACER("TButton::createSoftButton(const EXTBUTTON_t& bt)");
504
 
505
    if (bt.sr.size() < 2)
506
    {
507
        MSG_ERROR("Button " << bt.bi << ": " << bt.na << " has less than 2 states!");
508
        return false;
509
    }
510
 
511
    MSG_DEBUG("Adding soft button " << bt.bi << ": " << bt.na);
512
    type = bt.type;
513
    bi = bt.bi;
514
    na = bt.na;
515
    lt = bt.lt;
516
    tp = bt.tp;
517
    wt = bt.wt;
518
    ht = bt.ht;
519
    zo = bt.zo;
520
    hs = bt.hs;
521
    bs = bt.bs;
522
    fb = bt.fb;
523
    ap = bt.ap;
524
    ad = bt.ad;
525
    lp = bt.lp;
526
    lv = bt.lv;
527
    dr = bt.dr;
528
    lu = bt.lu;
529
    ld = bt.ld;
530
    rl = bt.rl;
531
    rh = bt.rh;
532
    rn = bt.rn;
533
    sc = bt.sc;
534
    sr = bt.sr;
177 andreas 535
    mChanged = true;
43 andreas 536
    return true;
537
}
538
 
50 andreas 539
BITMAP_t TButton::getLastImage()
540
{
541
    DECL_TRACER("TButton::getLastImage()");
542
 
285 andreas 543
    if (mLastImage.empty())
289 andreas 544
    {
285 andreas 545
        makeElement(mActInstance);
546
 
289 andreas 547
        if (mLastImage.empty())
548
            return BITMAP_t();
549
    }
550
 
50 andreas 551
    BITMAP_t image;
552
    image.buffer = (unsigned char *)mLastImage.getPixels();
553
    image.rowBytes = mLastImage.info().minRowBytes();
554
    image.width = mLastImage.info().width();
555
    image.height = mLastImage.info().height();
556
    return image;
557
}
558
 
289 andreas 559
TBitmap TButton::getLastBitmap()
560
{
561
    DECL_TRACER("TButton::getLastBitmap()");
562
 
563
    if (mLastImage.empty())
564
        makeElement(mActInstance);
565
 
566
    TBitmap bitmap((unsigned char *)mLastImage.getPixels(), mLastImage.info().width(), mLastImage.info().height());
567
    return bitmap;
568
}
569
 
50 andreas 570
FONT_T TButton::getFont()
571
{
572
    DECL_TRACER("TButton::getFont()");
573
 
574
    if (!mFonts)
575
    {
576
        MSG_ERROR("No fonts available!");
577
        return FONT_T();
578
    }
579
 
200 andreas 580
    if (type == LISTBOX && _getGlobalSettings)
581
    {
582
        _getGlobalSettings(this);
583
        mActInstance = 0;
584
    }
585
 
50 andreas 586
    return mFonts->getFont(sr[mActInstance].fi);
587
}
588
 
51 andreas 589
FONT_STYLE TButton::getFontStyle()
50 andreas 590
{
591
    DECL_TRACER("TButton::getFontStyle()");
592
 
593
    if (!mFonts)
594
    {
595
        MSG_ERROR("No fonts available!");
51 andreas 596
        return FONT_NONE;
50 andreas 597
    }
598
 
599
    return mFonts->getStyle(sr[mActInstance].fi);
600
}
601
 
268 andreas 602
void TButton::setBargraphLevel(int level)
603
{
604
    DECL_TRACER("TButton::setBargraphLevel(int level)");
605
 
606
    if (type != BARGRAPH && type != MULTISTATE_BARGRAPH && type != MULTISTATE_GENERAL)
607
        return;
608
 
609
    if (((type == BARGRAPH || type == MULTISTATE_BARGRAPH) && (level < rl || level > rh)) ||
610
        (type == MULTISTATE_GENERAL && (level < 0 || (size_t)level >= sr.size())))
611
    {
612
        MSG_WARNING("Level for bargraph " << na << " is out of range! (" << rl << " to " << rh << " or size " << sr.size() << ")");
613
        return;
614
    }
615
 
616
    if (((type == BARGRAPH || type == MULTISTATE_BARGRAPH) && mLastLevel != level) ||
617
        (type == MULTISTATE_BARGRAPH && mActInstance != level))
618
        mChanged = true;
269 andreas 619
 
620
    if (!mChanged)
621
        return;
622
 
268 andreas 623
    if (type == BARGRAPH)
624
    {
625
        mLastLevel = level;
626
        drawBargraph(mActInstance, level);
627
    }
628
    else if (type == MULTISTATE_BARGRAPH)
629
    {
630
        mLastLevel = level;
269 andreas 631
        mActInstance = level;
268 andreas 632
        drawMultistateBargraph(level);
633
    }
634
    else
635
        setActive(level);
636
}
637
 
271 andreas 638
bool TButton::invalidate()
639
{
640
    DECL_TRACER("TButton::invalidate()");
641
 
642
    if (prg_stopped)
643
        return true;
644
 
645
    ulong parent = mHandle & 0xffff0000;
646
    THR_REFRESH_t *tr = _findResource(mHandle, parent, bi);
647
 
648
    if (tr && tr->mImageRefresh)
649
    {
650
        if (tr->mImageRefresh->isRunning())
651
            tr->mImageRefresh->stop();
652
    }
653
 
654
    if (type == TEXT_INPUT)
655
    {
656
        if (gPageManager && gPageManager->getCallDropButton())
657
            gPageManager->getCallDropButton()(mHandle);
658
    }
659
 
660
    visible = false;
661
    return true;
662
}
663
 
332 andreas 664
string& TButton::getDrawOrder(int instance)
665
{
666
    DECL_TRACER("TButton::getDrawOrder(int instance)");
667
 
668
    if (instance < 0 || (size_t)instance > sr.size())
669
    {
670
        MSG_ERROR("Instance is out of range!");
671
        return dummy;
672
    }
673
 
674
    return sr[instance]._do;
675
}
676
 
3 andreas 677
BUTTONTYPE TButton::getButtonType(const string& bt)
678
{
679
    DECL_TRACER("TButton::getButtonType(const string& bt)");
680
 
300 andreas 681
    if (strCaseCompare(bt, "general") == 0)
3 andreas 682
        return GENERAL;
300 andreas 683
    else if (strCaseCompare(bt, "multi-state general") == 0 || strCaseCompare(bt, "multiGeneral") == 0)
3 andreas 684
        return MULTISTATE_GENERAL;
300 andreas 685
    else if (strCaseCompare(bt, "bargraph") == 0)
3 andreas 686
        return BARGRAPH;
300 andreas 687
    else if (strCaseCompare(bt, "multi-state bargraph") == 0 || strCaseCompare(bt, "multiBargraph") == 0)
3 andreas 688
        return MULTISTATE_BARGRAPH;
300 andreas 689
    else if (strCaseCompare(bt, "joistick") == 0)
3 andreas 690
        return JOISTICK;
300 andreas 691
    else if (strCaseCompare(bt, "text input") == 0 || strCaseCompare(bt, "textArea") == 0)
3 andreas 692
        return TEXT_INPUT;
300 andreas 693
    else if (strCaseCompare(bt, "computer control") == 0)
3 andreas 694
        return COMPUTER_CONTROL;
300 andreas 695
    else if (strCaseCompare(bt, "take note") == 0)
3 andreas 696
        return TAKE_NOTE;
300 andreas 697
    else if (strCaseCompare(bt, "sub-page view") == 0 || strCaseCompare(bt, "subPageView") == 0)
3 andreas 698
        return SUBPAGE_VIEW;
300 andreas 699
    else if (strCaseCompare(bt, "listBox") == 0)
192 andreas 700
        return LISTBOX;
3 andreas 701
 
702
    return NONE;
703
}
704
 
283 andreas 705
string TButton::buttonTypeToString()
706
{
707
    switch(type)
708
    {
709
        case NONE:                  return "NONE";
710
        case GENERAL:               return "GENERAL";
711
        case MULTISTATE_GENERAL:    return "MULTISTAE GENERAL";
712
        case BARGRAPH:              return "BARGRAPH";
713
        case MULTISTATE_BARGRAPH:   return "MULTISTATE BARGRAPH";
714
        case JOISTICK:              return "JOISTICK";
715
        case TEXT_INPUT:            return "TEXT INPUT";
716
        case COMPUTER_CONTROL:      return "COMPUTER CONTROL";
717
        case TAKE_NOTE:             return "TAKE NOTE";
718
        case SUBPAGE_VIEW:          return "SUBPAGE VIEW";
719
        case LISTBOX:               return "LISTBOX";
720
    }
721
 
722
    return "";
723
}
724
 
3 andreas 725
FEEDBACK TButton::getButtonFeedback(const string& fb)
726
{
727
    DECL_TRACER("TButton::getButtonFeedback(const string& fb)");
728
 
729
    if (fb.compare("channel") == 0)
730
        return FB_CHANNEL;
731
    else if (fb.compare("inverted channel") == 0)
732
        return FB_INV_CHANNEL;
733
    else if (fb.compare("always on") == 0)
734
        return FB_ALWAYS_ON;
735
    else if (fb.compare("momentary") == 0)
736
        return FB_MOMENTARY;
737
    else if (fb.compare("blink") == 0)
738
        return FB_BLINK;
739
 
740
    return FB_NONE;
741
}
742
 
40 andreas 743
bool TButton::createButtons(bool force)
3 andreas 744
{
177 andreas 745
    DECL_TRACER("TButton::createButtons(bool force)");
3 andreas 746
 
33 andreas 747
    if (prg_stopped)
748
        return false;
35 andreas 749
 
46 andreas 750
    if (force)
177 andreas 751
    {
752
        mChanged = true;
46 andreas 753
        MSG_TRACE("Creating of image is forced!");
177 andreas 754
    }
46 andreas 755
 
3 andreas 756
    // Get the images, if there any
757
    vector<SR_T>::iterator srIter;
758
 
118 andreas 759
    for (srIter = sr.begin(); srIter != sr.end(); ++srIter)
3 andreas 760
    {
761
        int number = srIter->number;
762
 
21 andreas 763
        if (srIter->sb > 0)
764
            continue;
765
 
165 andreas 766
        bool bmExistMi = false;
767
        bool bmExistBm = false;
768
        bool reload = false;
46 andreas 769
 
165 andreas 770
        if (!srIter->mi.empty())
771
        {
772
            if ((bmExistMi = TImgCache::existBitmap(srIter->mi, _BMTYPE_CHAMELEON)) == false)
177 andreas 773
            {
774
                mChanged = true;
165 andreas 775
                reload = true;
177 andreas 776
            }
165 andreas 777
        }
778
 
779
        if (!srIter->bm.empty())
780
        {
781
            if ((bmExistBm = TImgCache::existBitmap(srIter->bm, _BMTYPE_BITMAP)) == false)
177 andreas 782
            {
783
                mChanged = true;
165 andreas 784
                reload = true;
177 andreas 785
            }
165 andreas 786
        }
787
 
40 andreas 788
        if (!force)
789
        {
165 andreas 790
            if (!reload)   // If the image already exist, do not load it again.
40 andreas 791
                continue;
792
        }
793
 
165 andreas 794
        if (!bmExistMi && !srIter->mi.empty())        // Do we have a chameleon image?
3 andreas 795
        {
4 andreas 796
            sk_sp<SkData> image;
165 andreas 797
            SkBitmap bm;
4 andreas 798
 
799
            if (!(image = readImage(srIter->mi)))
3 andreas 800
                return false;
801
 
165 andreas 802
            DecodeDataToBitmap(image, &bm);
3 andreas 803
 
165 andreas 804
            if (bm.empty())
3 andreas 805
            {
806
                MSG_WARNING("Could not create a picture for element " << number << " on button " << bi << " (" << na << ")");
807
                return false;
808
            }
809
 
167 andreas 810
            TImgCache::addImage(srIter->mi, bm, _BMTYPE_CHAMELEON);
811
            srIter->mi_width = bm.info().width();
812
            srIter->mi_height = bm.info().height();
177 andreas 813
            mChanged = true;
3 andreas 814
        }
815
 
165 andreas 816
        if (!bmExistBm && !srIter->bm.empty())        // Do we have a bitmap?
3 andreas 817
        {
4 andreas 818
            sk_sp<SkData> image;
165 andreas 819
            SkBitmap bm;
4 andreas 820
 
821
            if (!(image = readImage(srIter->bm)))
3 andreas 822
                return false;
823
 
165 andreas 824
            DecodeDataToBitmap(image, &bm);
3 andreas 825
 
165 andreas 826
            if (bm.empty())
3 andreas 827
            {
828
                MSG_WARNING("Could not create a picture for element " << number << " on button " << bi << " (" << na << ")");
829
                return false;
830
            }
831
 
167 andreas 832
            TImgCache::addImage(srIter->bm, bm, _BMTYPE_BITMAP);
833
            srIter->bm_width = bm.info().width();
834
            srIter->bm_height = bm.info().height();
177 andreas 835
            mChanged = true;
3 andreas 836
        }
837
    }
838
 
4 andreas 839
    return true;
840
}
3 andreas 841
 
16 andreas 842
void TButton::refresh()
843
{
844
    DECL_TRACER("TButton::refresh()");
845
 
177 andreas 846
    mChanged = true;
16 andreas 847
    makeElement();
848
}
849
 
15 andreas 850
bool TButton::makeElement(int instance)
851
{
192 andreas 852
    DECL_TRACER("TButton::makeElement(int instance)");
15 andreas 853
 
33 andreas 854
    if (prg_stopped)
855
        return false;
35 andreas 856
 
15 andreas 857
    int inst = mActInstance;
858
 
46 andreas 859
    if (instance >= 0 && (size_t)instance < sr.size())
177 andreas 860
    {
861
        if (mActInstance != instance)
862
            mChanged = true;
863
 
15 andreas 864
        inst = instance;
177 andreas 865
    }
15 andreas 866
 
192 andreas 867
    bool isSystem = isSystemButton();
868
 
15 andreas 869
    if (type == MULTISTATE_GENERAL && ar == 1)
870
        return drawButtonMultistateAni();
192 andreas 871
    else if (type == BARGRAPH && isSystem && lv == 9)   // System volume button
141 andreas 872
        return drawBargraph(inst, TConfig::getSystemVolume());
15 andreas 873
    else if (type == BARGRAPH)
874
        return drawBargraph(inst, mLastLevel);
38 andreas 875
    else if (type == MULTISTATE_BARGRAPH)
46 andreas 876
        return drawMultistateBargraph(mLastLevel, true);
50 andreas 877
    else if (type == TEXT_INPUT)
878
    {
192 andreas 879
        if (isSystem && !mSystemReg)
51 andreas 880
            registerSystemButton();
881
 
310 andreas 882
        drawTextArea(inst);
883
        mActInstance = inst;
50 andreas 884
    }
193 andreas 885
    else if (type == LISTBOX)
886
    {
199 andreas 887
        if (_getListContent && !mSystemReg)
888
        {
200 andreas 889
            mListContent = _getListContent(mHandle, ap, ta, ti, tr, tc);
890
            mChanged = true;
199 andreas 891
        }
892
 
893
        if (isSystem)
894
            mSystemReg = true;
895
 
200 andreas 896
        drawList();
193 andreas 897
    }
192 andreas 898
    else if (isSystem && type == GENERAL)
71 andreas 899
    {
192 andreas 900
        TConfig::setTemporary(true);
71 andreas 901
 
195 andreas 902
        if (isSystemCheckBox(ch))
192 andreas 903
        {
195 andreas 904
            int in = getButtonInstance(0, ch);
905
 
906
            if (in >= 0)
907
            {
908
                inst = mActInstance = in;
909
#ifndef __ANDROID__
301 andreas 910
                if (ch == SYSTEM_ITEM_VIEWSCALEFIT && sr[0].oo < 0) // scale to fit disabled
195 andreas 911
                {
912
                    sr[0].oo = 128;
913
                    mChanged = true;
914
                }
915
#else
301 andreas 916
                if (ch == SYSTEM_ITEM_VIEWBANNER && sr[0].oo < 0)   // show banner disabled
195 andreas 917
                {
918
                    sr[0].oo = 128;
919
                    mChanged = true;
920
                }
921
#endif
301 andreas 922
                if (ch == SYSTEM_ITEM_VIEWTOOLBAR)  // Force toolbar is only available if toolbar is not suppressed
198 andreas 923
                {
924
                    if (TConfig::getToolbarSuppress() && sr[0].oo < 0)
925
                    {
926
                        sr[0].oo = 128;
927
                        mChanged = true;
928
                    }
929
                    else if (!TConfig::getToolbarSuppress() && sr[0].oo > 0)
930
                    {
931
                        sr[0].oo = -1;
932
                        mChanged = true;
933
                    }
934
                }
195 andreas 935
            }
192 andreas 936
        }
206 andreas 937
        else if (isSystemTextLine(ad) && ad != SYSTEM_ITEM_FTPSURFACE)
192 andreas 938
        {
195 andreas 939
            sr[0].te = sr[1].te = fillButtonText(ad, 0);
192 andreas 940
        }
141 andreas 941
 
198 andreas 942
        TConfig::setTemporary(false);
192 andreas 943
        MSG_DEBUG("Drawing system button " << ch << " with instance " << inst);
141 andreas 944
        return drawButton(inst);
945
    }
15 andreas 946
    else
310 andreas 947
    {
334 andreas 948
//        mActInstance = inst;
15 andreas 949
        return drawButton(inst);
310 andreas 950
    }
15 andreas 951
 
952
    return false;
953
}
954
 
14 andreas 955
bool TButton::setActive(int instance)
956
{
957
    DECL_TRACER("TButton::setActive(int instance)");
958
 
53 andreas 959
    if (mAniRunning)
960
        return true;
961
 
165 andreas 962
    if (instance < 0 || (size_t)instance >= sr.size())
14 andreas 963
    {
165 andreas 964
        MSG_ERROR("Instance " << instance << " is out of range from 0 to " << sr.size() << "!");
14 andreas 965
        return false;
966
    }
967
 
318 andreas 968
    if (instance == mActInstance && !mLastImage.empty())
14 andreas 969
        return true;
970
 
971
    mActInstance = instance;
177 andreas 972
    mChanged = true;
15 andreas 973
    makeElement(instance);
14 andreas 974
 
975
    return true;
976
}
977
 
978
bool TButton::setIcon(int id, int instance)
979
{
980
    DECL_TRACER("TButton::setIcon(int id, int instance)");
981
 
167 andreas 982
    if (instance >= 0 && (size_t)instance >= sr.size())
14 andreas 983
    {
984
        MSG_ERROR("Instance " << instance << " does not exist!");
985
        return false;
986
    }
987
 
165 andreas 988
    int inst = instance;
989
    int loop = 1;
990
 
991
    if (inst < 0)
992
    {
993
        loop = (int)sr.size();
994
        inst = 0;
995
    }
996
 
997
    for (int i = 0; i < loop; ++i)
998
    {
175 andreas 999
        if (sr[inst].ii != id)
1000
            mChanged = true;
1001
 
165 andreas 1002
        sr[inst].ii = id;
1003
        inst++;
1004
    }
1005
 
16 andreas 1006
    return makeElement(instance);
14 andreas 1007
}
1008
 
1009
bool TButton::setIcon(const string& icon, int instance)
1010
{
1011
    DECL_TRACER("TButton::setIcon(const string& icon, int instance)");
1012
 
167 andreas 1013
    if (instance >= 0 && (size_t)instance >= sr.size())
14 andreas 1014
    {
1015
        MSG_ERROR("Instance " << instance << " does not exist!");
1016
        return false;
1017
    }
1018
 
1019
    if (!gIcons)
1020
    {
1021
        gIcons = new TIcons();
1022
 
1023
        if (TError::isError())
1024
        {
1025
            MSG_ERROR("Error initializing icons!");
1026
            return false;
1027
        }
1028
    }
1029
 
1030
    int id = gIcons->getNumber(icon);
1031
 
1032
    if (id == -1)
1033
    {
1034
        MSG_WARNING("Icon " << icon << " not found!");
1035
        return false;
1036
    }
1037
 
165 andreas 1038
    int inst = instance;
1039
    int loop = 1;
1040
 
1041
    if (inst < 0)
1042
    {
1043
        loop = (int)sr.size();
1044
        inst = 0;
1045
    }
1046
 
1047
    for (int i = 0; i < loop; ++i)
1048
    {
1049
        if (sr[inst].ii == id)
1050
        {
1051
            inst++;
1052
            continue;
1053
        }
1054
 
316 andreas 1055
        if (sr[inst].ii != id)
1056
            mChanged = true;
1057
 
165 andreas 1058
        sr[inst].ii = id;
1059
        inst++;
1060
    }
1061
 
16 andreas 1062
    return makeElement(instance);
14 andreas 1063
}
1064
 
1065
bool TButton::revokeIcon(int instance)
1066
{
1067
    DECL_TRACER("TButton::revokeIcon(int instance)");
1068
 
167 andreas 1069
    if (instance >= 0 && (size_t)instance >= sr.size())
14 andreas 1070
    {
1071
        MSG_ERROR("Instance " << instance << " does not exist!");
1072
        return false;
1073
    }
1074
 
165 andreas 1075
    int inst = instance;
1076
    int loop = 1;
1077
 
1078
    if (inst < 0)
1079
    {
1080
        loop = (int)sr.size();
1081
        inst = 0;
1082
    }
1083
 
1084
    for (int i = 0; i < loop; ++i)
1085
    {
1086
        if (sr[inst].ii == 0)
1087
        {
1088
            inst++;
1089
            continue;
1090
        }
1091
 
316 andreas 1092
        if (sr[inst].ii != 0)
1093
            mChanged = true;
1094
 
165 andreas 1095
        sr[inst].ii = 0;
1096
        inst++;
1097
    }
1098
 
16 andreas 1099
    return makeElement(instance);
14 andreas 1100
}
1101
 
1102
bool TButton::setText(const string& txt, int instance)
1103
{
1104
    DECL_TRACER("TButton::setText(const string& txt, int instance)");
1105
 
167 andreas 1106
    if (instance >= 0 && (size_t)instance >= sr.size())
14 andreas 1107
    {
1108
        MSG_ERROR("Instance " << instance << " does not exist!");
334 andreas 1109
#if TESTMODE == 1
1110
        setAllDone();
1111
#endif
14 andreas 1112
        return false;
1113
    }
1114
 
165 andreas 1115
    if (!setTextOnly(txt, instance))
334 andreas 1116
    {
1117
#if TESTMODE == 1
1118
        setAllDone();
1119
#endif
165 andreas 1120
        return false;
334 andreas 1121
    }
165 andreas 1122
 
333 andreas 1123
    if (!mChanged)      // Do not try to redraw the button if nothing changed
1124
    {
1125
#if TESTMODE == 1
334 andreas 1126
        MSG_INFO("Nothing changed!");
333 andreas 1127
        __success = true;
334 andreas 1128
        setScreenDone();
333 andreas 1129
#endif
1130
        return true;
1131
    }
1132
 
16 andreas 1133
    return makeElement(instance);
14 andreas 1134
}
1135
 
51 andreas 1136
bool TButton::setTextOnly(const string& txt, int instance)
1137
{
1138
    DECL_TRACER("TButton::setTextOnly(const string& txt, int instance)");
1139
 
167 andreas 1140
    if (instance >= 0 && (size_t)instance >= sr.size())
51 andreas 1141
    {
1142
        MSG_ERROR("Instance " << instance << " does not exist!");
1143
        return false;
1144
    }
1145
 
333 andreas 1146
    if (instance < 0)
165 andreas 1147
    {
333 andreas 1148
        for (size_t i = 0; i < sr.size(); ++i)
1149
        {
1150
            if (sr[i].te != txt && (int)i == mActInstance)
1151
                mChanged = true;
165 andreas 1152
 
333 andreas 1153
            sr[i].te = txt;
1154
        }
165 andreas 1155
    }
333 andreas 1156
    else
334 andreas 1157
    {
1158
        if (sr[instance].te != txt && (int)instance == mActInstance)
1159
            mChanged = true;
1160
 
333 andreas 1161
        sr[instance].te = txt;
334 andreas 1162
    }
165 andreas 1163
 
333 andreas 1164
    if (instance <= 0 && isSystemButton())
192 andreas 1165
    {
316 andreas 1166
        bool temp = TConfig::setTemporary(true);
209 andreas 1167
        // If we've an input line or the text line of a "combobox" then we'll
1168
        // save the changed value here.
192 andreas 1169
        switch(ad)
1170
        {
209 andreas 1171
            case SYSTEM_ITEM_NETLINX_IP:        TConfig::saveController(txt); break;
1172
            case SYSTEM_ITEM_NETLINX_CHANNEL:   TConfig::saveChannel(atoi(txt.c_str())); break;
1173
            case SYSTEM_ITEM_NETLINX_PORT:      TConfig::savePort(atoi(txt.c_str())); break;
1174
            case SYSTEM_ITEM_NETLINX_PTYPE:     TConfig::savePanelType(txt); break;
192 andreas 1175
 
209 andreas 1176
            case SYSTEM_ITEM_SYSTEMSOUND:       TConfig::saveSystemSoundFile(txt); break;
1177
            case SYSTEM_ITEM_SINGLEBEEP:        TConfig::saveSingleBeepFile(txt); break;
1178
            case SYSTEM_ITEM_DOUBLEBEEP:        TConfig::saveDoubleBeepFile(txt); break;
192 andreas 1179
 
209 andreas 1180
            case SYSTEM_ITEM_SIPPROXY:          TConfig::setSIPproxy(txt); break;
1181
            case SYSTEM_ITEM_SIPPORT:           TConfig::setSIPport(atoi(txt.c_str())); break;
1182
            case SYSTEM_ITEM_SIPSTUN:           TConfig::setSIPstun(txt); break;
1183
            case SYSTEM_ITEM_SIPDOMAIN:         TConfig::setSIPdomain(txt); break;
1184
            case SYSTEM_ITEM_SIPUSER:           TConfig::setSIPuser(txt); break;
1185
            case SYSTEM_ITEM_SIPPASSWORD:       TConfig::setSIPpassword(txt); break;
195 andreas 1186
 
209 andreas 1187
            case SYSTEM_ITEM_LOGLOGFILE:        TConfig::saveLogFile(txt); break;
192 andreas 1188
 
209 andreas 1189
            case SYSTEM_ITEM_FTPUSER:           TConfig::saveFtpUser(txt); break;
1190
            case SYSTEM_ITEM_FTPPASSWORD:       TConfig::saveFtpPassword(txt); break;
1191
            case SYSTEM_ITEM_FTPSURFACE:        TConfig::saveFtpSurface(txt); break;
192 andreas 1192
        }
316 andreas 1193
 
1194
        TConfig::setTemporary(temp);
192 andreas 1195
    }
1196
 
51 andreas 1197
    return true;
1198
}
1199
 
43 andreas 1200
bool TButton::appendText(const string &txt, int instance)
1201
{
1202
    DECL_TRACER("TButton::appendText(const string &txt, int instance)");
1203
 
331 andreas 1204
    if (instance >= 0 && (size_t)instance >= sr.size())
43 andreas 1205
    {
60 andreas 1206
        MSG_ERROR("Instance " << instance << " does not exist!");
43 andreas 1207
        return false;
1208
    }
1209
 
175 andreas 1210
    if (txt.empty())
333 andreas 1211
    {
1212
#if TESTMODE == 1
1213
        __success = true;
1214
        __done = true;
1215
#endif
175 andreas 1216
        return true;
165 andreas 1217
    }
1218
 
333 andreas 1219
    if (instance < 0)
165 andreas 1220
    {
333 andreas 1221
        for (size_t i = 0; i < sr.size(); ++i)
1222
            sr[i].te.append(txt);
165 andreas 1223
    }
333 andreas 1224
    else
1225
        sr[instance].te.append(txt);
165 andreas 1226
 
333 andreas 1227
    mChanged = true;
43 andreas 1228
    return makeElement(instance);
1229
}
1230
 
309 andreas 1231
void TButton::setTextCursorPosition(int oldPos, int newPos)
1232
{
1233
    DECL_TRACER("TButton::setTextCursorPosition(int oldPos, int newPos)");
1234
 
1235
    if (type != TEXT_INPUT)
1236
        return;
1237
 
1238
    if (oldPos == newPos && newPos == mCursorPosition)
1239
        return;
1240
 
1241
    mCursorPosition = newPos;
1242
}
1243
 
1244
void TButton::setTextFocus(bool in)
1245
{
1246
    DECL_TRACER("TButton::setTextFocus(bool in)");
1247
 
1248
    if (type != TEXT_INPUT)
1249
        return;
1250
 
1251
    mHasFocus = in;
1252
 
1253
    if (mHasFocus && mActInstance != STATE_ON)
1254
        makeElement(STATE_ON);
1255
    else if (!mHasFocus && mActInstance != STATE_OFF)
1256
        makeElement(STATE_OFF);
1257
}
1258
 
43 andreas 1259
bool TButton::setBorderColor(const string &color, int instance)
1260
{
1261
    DECL_TRACER("TButton::setBorderColor(const string &color, int instance)");
1262
 
167 andreas 1263
    if (instance >= 0 && (size_t)instance >= sr.size())
43 andreas 1264
    {
60 andreas 1265
        MSG_ERROR("Instance " << instance << " does not exist!");
43 andreas 1266
        return false;
1267
    }
1268
 
165 andreas 1269
    int inst = instance;
1270
    int loop = 1;
1271
 
1272
    if (inst < 0)
1273
    {
1274
        loop = (int)sr.size();
1275
        inst = 0;
1276
    }
1277
 
1278
    for (int i = 0; i < loop; ++i)
1279
    {
1280
        if (sr[inst].cb.compare(color) == 0)
1281
        {
1282
            inst++;
1283
            continue;
1284
        }
1285
 
1286
        sr[inst].cb = color;
175 andreas 1287
        mChanged = true;
165 andreas 1288
        inst++;
1289
    }
1290
 
43 andreas 1291
    return makeElement(instance);
1292
}
1293
 
82 andreas 1294
string TButton::getBorderColor(int instance)
1295
{
1296
    DECL_TRACER("TButton::getBorderColor(int instance)");
1297
 
165 andreas 1298
    if (instance < 0 || (size_t)instance >= sr.size())
82 andreas 1299
    {
1300
        MSG_ERROR("Instance " << instance << " does not exist!");
1301
        return string();
1302
    }
1303
 
1304
    return sr[instance].cb;
1305
}
1306
 
60 andreas 1307
bool TButton::setFillColor(const string& color, int instance)
1308
{
1309
    DECL_TRACER("TButton::setFillColor(const string& color, int instance)");
1310
 
167 andreas 1311
    if (instance >= 0 && (size_t)instance >= sr.size())
60 andreas 1312
    {
1313
        MSG_ERROR("Instance " << instance << " does not exist!");
1314
        return false;
1315
    }
1316
 
165 andreas 1317
    int inst = instance;
1318
    int loop = 1;
1319
 
1320
    if (inst < 0)
1321
    {
1322
        loop = (int)sr.size();
1323
        inst = 0;
1324
    }
1325
 
1326
    for (int i = 0; i < loop; ++i)
1327
    {
1328
        if (sr[inst].cf.compare(color) == 0)
1329
        {
1330
            inst++;
1331
            continue;
1332
        }
1333
 
1334
        sr[inst].cf = color;
175 andreas 1335
        mChanged = true;
165 andreas 1336
        inst++;
1337
    }
1338
 
60 andreas 1339
    return makeElement(instance);
1340
}
1341
 
1342
bool TButton::setTextColor(const string& color, int instance)
1343
{
1344
    DECL_TRACER("TButton::setTextColor(const string& color, int instance)");
1345
 
205 andreas 1346
    if (!setTextColorOnly(color, instance))
1347
        return false;
1348
 
1349
    return makeElement(instance);
1350
}
1351
 
1352
bool TButton::setTextColorOnly(const string& color, int instance)
1353
{
1354
    DECL_TRACER("TButton::setTextColorOnly(const string& color, int instance)");
1355
 
167 andreas 1356
    if (instance >= 0 && (size_t)instance >= sr.size())
60 andreas 1357
    {
1358
        MSG_ERROR("Instance " << instance << " does not exist!");
1359
        return false;
1360
    }
1361
 
165 andreas 1362
    int inst = instance;
1363
    int loop = 1;
1364
 
1365
    if (inst < 0)
1366
    {
1367
        loop = (int)sr.size();
1368
        inst = 0;
1369
    }
1370
 
1371
    for (int i = 0; i < loop; ++i)
1372
    {
1373
        if (sr[inst].ct.compare(color) == 0)
1374
        {
1375
            inst++;
1376
            continue;
1377
        }
1378
 
1379
        sr[inst].ct = color;
1380
        inst++;
175 andreas 1381
        mChanged = true;
165 andreas 1382
    }
1383
 
205 andreas 1384
    return true;
60 andreas 1385
}
1386
 
1387
bool TButton::setDrawOrder(const string& order, int instance)
1388
{
1389
    DECL_TRACER("TButton::setDrawOrder(const string& order, int instance)");
1390
 
167 andreas 1391
    if (instance >= 0 && (size_t)instance >= sr.size())
60 andreas 1392
    {
1393
        MSG_ERROR("Instance " << instance << " does not exist!");
1394
        return false;
1395
    }
1396
 
165 andreas 1397
    int inst = instance;
1398
    int loop = 1;
1399
 
1400
    if (inst < 0)
1401
    {
1402
        loop = (int)sr.size();
1403
        inst = 0;
1404
    }
1405
 
1406
    for (int i = 0; i < loop; ++i)
1407
    {
1408
        if (sr[inst]._do.compare(order) == 0)
1409
        {
1410
            inst++;
1411
            continue;
1412
        }
1413
 
1414
        sr[inst]._do = order;
1415
        inst++;
175 andreas 1416
        mChanged = true;
165 andreas 1417
    }
1418
 
60 andreas 1419
    return makeElement(instance);
1420
}
1421
 
1422
bool TButton::setFeedback(FEEDBACK feedback)
1423
{
1424
    DECL_TRACER("TButton::setFeedback(FEEDBACK feedback)");
1425
 
152 andreas 1426
    int oldFB = fb;
60 andreas 1427
    fb = feedback;
152 andreas 1428
 
1429
    if (mEnabled && !hd)
1430
    {
1431
        if ((feedback == FB_ALWAYS_ON || feedback == FB_INV_CHANNEL) && mActInstance != 1)
1432
        {
1433
            mActInstance = 1;
175 andreas 1434
            mChanged = true;
152 andreas 1435
            makeElement(1);
1436
        }
1437
        else if (oldFB == FB_ALWAYS_ON && feedback != FB_ALWAYS_ON && feedback != FB_INV_CHANNEL && mActInstance == 1)
1438
        {
1439
            mActInstance = 0;
175 andreas 1440
            mChanged = true;
152 andreas 1441
            makeElement(0);
1442
        }
1443
    }
1444
 
60 andreas 1445
    return true;
1446
}
1447
 
1448
bool TButton::setBorderStyle(const string& style, int instance)
1449
{
1450
    DECL_TRACER("TButton::setBorderStyle(const string& style, int instance)");
1451
 
167 andreas 1452
    if (instance >= 0 && (size_t)instance >= sr.size())
60 andreas 1453
    {
1454
        MSG_ERROR("Instance " << instance << " does not exist!");
1455
        return false;
1456
    }
1457
 
175 andreas 1458
    mChanged = true;
1459
 
60 andreas 1460
    if (strCaseCompare(style, "None") == 0)     // Clear the border?
1461
    {
152 andreas 1462
        if (instance < 0)
332 andreas 1463
        {
60 andreas 1464
            bs.clear();
332 andreas 1465
 
1466
            for (size_t i = 0; i < sr.size(); ++i)
1467
                sr[i].bs.clear();
1468
        }
60 andreas 1469
        else
332 andreas 1470
        {
152 andreas 1471
            sr[instance].bs.clear();
332 andreas 1472
            bs.clear();
1473
        }
60 andreas 1474
 
152 andreas 1475
        if (mEnabled && !hd)
1476
            makeElement(instance);
1477
 
60 andreas 1478
        return true;
1479
    }
1480
 
79 andreas 1481
    // Look in the system table and try to find the border.
1482
    if (gPageManager && gPageManager->getSystemDraw())
1483
    {
1484
        if (gPageManager->getSystemDraw()->existBorder(style))
1485
        {
152 andreas 1486
            if (instance < 0)
332 andreas 1487
            {
79 andreas 1488
                bs = style;
332 andreas 1489
 
1490
                for (size_t i = 0; i < sr.size(); ++i)
1491
                    sr[i].bs = style;
1492
            }
79 andreas 1493
            else
332 andreas 1494
            {
152 andreas 1495
                sr[instance].bs = style;
79 andreas 1496
 
332 andreas 1497
                if (bs != style)
1498
                    bs.clear();
1499
            }
1500
 
152 andreas 1501
            if (mEnabled && !hd)
1502
                makeElement(instance);
1503
 
79 andreas 1504
            return true;
1505
        }
1506
    }
1507
 
60 andreas 1508
    // Check whether it is a supported style or not. If the style is not
1509
    // supported, it will be ignored.
306 andreas 1510
    string corrName = getCorrectName(style);
60 andreas 1511
 
306 andreas 1512
    if (!style.empty())
60 andreas 1513
    {
306 andreas 1514
        if (instance < 0)
332 andreas 1515
        {
306 andreas 1516
            bs = corrName;
332 andreas 1517
 
1518
            for (size_t i = 0; i < sr.size(); ++i)
1519
                sr[i].bs = corrName;
1520
        }
306 andreas 1521
        else
332 andreas 1522
        {
306 andreas 1523
            sr[instance].bs = corrName;
60 andreas 1524
 
332 andreas 1525
            if (bs != corrName)
1526
                bs.clear();
1527
        }
1528
 
306 andreas 1529
        if (mEnabled && !hd)
1530
            makeElement(instance);
152 andreas 1531
 
306 andreas 1532
        return true;
60 andreas 1533
    }
332 andreas 1534
#if TESTMODE == 1
1535
    __done = true;
1536
#endif
60 andreas 1537
    return false;
1538
}
1539
 
332 andreas 1540
bool TButton::setBorderStyle(int style, int instance)
1541
{
1542
    DECL_TRACER("TButton::setBorderStyle(int style, int instance)");
1543
 
1544
    if (instance >= 0 && (size_t)instance >= sr.size())
1545
    {
1546
        MSG_ERROR("Instance " << instance << " does not exist!");
1547
        return false;
1548
    }
1549
 
1550
    if (style == 0)     // Clear the border?
1551
    {
1552
        if (instance < 0)
1553
        {
1554
            bs.clear();
1555
 
1556
            for (size_t i = 0; i < sr.size(); ++i)
334 andreas 1557
            {
1558
                if (!sr[i].bs.empty())
1559
                    mChanged = true;
1560
 
332 andreas 1561
                sr[i].bs.clear();
334 andreas 1562
            }
1563
 
1564
            if (!bs.empty())
1565
                mChanged = true;
1566
 
1567
            bs.clear();
332 andreas 1568
        }
1569
        else
1570
        {
334 andreas 1571
            if (!sr[instance].bs.empty())
1572
                mChanged = true;
1573
 
332 andreas 1574
            sr[instance].bs.clear();
1575
            bs.clear();
1576
        }
1577
 
1578
        if (mEnabled && !hd)
1579
            makeElement(instance);
1580
 
1581
        return true;
1582
    }
1583
 
1584
    string st = getBorderName(style);
1585
 
1586
    if (st.empty())
1587
    {
1588
        MSG_WARNING("The index " << style << " is not supported!");
1589
#if TESTMODE == 1
334 andreas 1590
        setAllDone();
332 andreas 1591
#endif
1592
        return false;
1593
    }
1594
 
1595
    // Look in the system table and try to find the border.
1596
    if (gPageManager && gPageManager->getSystemDraw())
1597
    {
1598
        if (gPageManager->getSystemDraw()->existBorder(st))
1599
        {
1600
            MSG_DEBUG("Found frame " << st << " and draw it ...");
1601
 
1602
            if (instance < 0)
1603
            {
1604
                bs = st;
1605
 
1606
                for (size_t i = 0; i < sr.size(); ++i)
1607
                    sr[i].bs = st;
1608
            }
1609
            else
1610
            {
1611
                sr[instance].bs = st;
1612
 
1613
                if (bs != st)
1614
                    bs.clear();
1615
            }
1616
 
1617
            mChanged = true;
1618
 
1619
            if (mEnabled && !hd)
1620
                makeElement(instance);
1621
 
1622
            return true;
1623
        }
1624
    }
1625
 
1626
    // Check whether it is a supported style or not. If the style is not
1627
    // supported, it will be ignored.
1628
    if (instance < 0)
1629
    {
1630
        bs = st;
1631
 
1632
        for (size_t i = 0; i < sr.size(); ++i)
1633
            sr[i].bs = st;
1634
    }
1635
    else
1636
    {
1637
        sr[instance].bs = st;
1638
 
1639
        if (bs != st)
1640
            bs.clear();
1641
    }
1642
 
1643
    mChanged = true;
1644
 
1645
    if (mEnabled && !hd)
1646
        makeElement(instance);
1647
 
1648
    return true;
1649
}
1650
 
106 andreas 1651
string TButton::getBorderStyle(int instance)
1652
{
1653
    DECL_TRACER("TButton::getBorderStyle(int instance)");
1654
 
1655
    if (instance < 0 || instance >= (int)sr.size())
1656
    {
1657
        MSG_ERROR("Invalid instance " << (instance + 1) << " submitted!");
1658
        return string();
1659
    }
1660
 
332 andreas 1661
    if (sr[instance].bs.empty())
1662
        return bs;
1663
 
106 andreas 1664
    return sr[instance].bs;
1665
}
1666
 
60 andreas 1667
bool TButton::setBargraphUpperLimit(int limit)
1668
{
1669
    DECL_TRACER("TButton::setBargraphUpperLimit(int limit)");
1670
 
1671
    if (limit < 1 || limit > 65535)
1672
    {
1673
        MSG_ERROR("Invalid upper limit " << limit);
1674
        return false;
1675
    }
1676
 
1677
    rh = limit;
1678
    return true;
1679
}
1680
 
1681
bool TButton::setBargraphLowerLimit(int limit)
1682
{
1683
    DECL_TRACER("TButton::setBargraphLowerLimit(int limit)");
1684
 
1685
    if (limit < 1 || limit > 65535)
1686
    {
1687
        MSG_ERROR("Invalid lower limit " << limit);
1688
        return false;
1689
    }
1690
 
1691
    rl = limit;
1692
    return true;
1693
}
1694
 
108 andreas 1695
bool TButton::setBargraphSliderColor(const string& color)
1696
{
1697
    DECL_TRACER("TButton::setBargraphSliderColor(const string& color, int inst)");
1698
 
1699
    if (!TColor::isValidAMXcolor(color))
1700
    {
1701
        MSG_PROTOCOL("Invalid color >" << color << "< ignored!");
1702
        return false;
1703
    }
1704
 
175 andreas 1705
    if (sc != color)
1706
        mChanged = true;
1707
 
108 andreas 1708
    sc = color;
1709
 
1710
    if (visible)
1711
        refresh();
1712
 
1713
    return true;
1714
}
1715
 
167 andreas 1716
bool TButton::setFontFileName(const string& name, int /*size*/, int instance)
149 andreas 1717
{
1718
    DECL_TRACER("TButton::setFontFileName(const string& name, int size)");
1719
 
1720
    if (name.empty() || !mFonts)
334 andreas 1721
    {
1722
#if TESTMODE == 1
1723
        setScreenDone();
1724
#endif
149 andreas 1725
        return false;
334 andreas 1726
    }
149 andreas 1727
 
165 andreas 1728
    if ((size_t)instance >= sr.size())
334 andreas 1729
    {
1730
#if TESTMODE == 1
1731
        setScreenDone();
1732
#endif
149 andreas 1733
        return false;
334 andreas 1734
    }
149 andreas 1735
 
1736
    int id = mFonts->getFontIDfromFile(name);
1737
 
1738
    if (id == -1)
334 andreas 1739
    {
1740
#if TESTMODE == 1
1741
        setScreenDone();
1742
#endif
149 andreas 1743
        return false;
334 andreas 1744
    }
149 andreas 1745
 
334 andreas 1746
    if (instance < 0)
1747
    {
1748
        for (size_t i = 0; i < sr.size(); ++i)
1749
        {
1750
            if (sr[i].fi != id)
1751
                mChanged = true;
165 andreas 1752
 
334 andreas 1753
            sr[i].fi = id;
1754
        }
1755
    }
1756
    else if (sr[instance].fi != id)
149 andreas 1757
    {
334 andreas 1758
        mChanged = true;
1759
        sr[instance].fi = id;
149 andreas 1760
    }
334 andreas 1761
#if TESTMODE == 1
1762
    setScreenDone();
1763
#endif
1764
    return true;
1765
}
165 andreas 1766
 
334 andreas 1767
bool TButton::setFontName(const string &name, int instance)
1768
{
1769
    DECL_TRACER("TButton::setFontName(const string &name, int instance)");
1770
 
1771
    if (name.empty() || !mFonts)
165 andreas 1772
    {
334 andreas 1773
#if TESTMODE == 1
1774
        setScreenDone();
1775
#endif
1776
        return false;
1777
    }
175 andreas 1778
 
334 andreas 1779
    if ((size_t)instance >= sr.size())
1780
    {
1781
#if TESTMODE == 1
1782
        setScreenDone();
1783
#endif
1784
        return false;
165 andreas 1785
    }
149 andreas 1786
 
334 andreas 1787
    int id = mFonts->getFontIDfromName(name);
1788
 
1789
    if (id == -1)
1790
    {
1791
#if TESTMODE == 1
1792
        setScreenDone();
1793
#endif
1794
        return false;
1795
    }
1796
 
1797
    if (instance < 0)
1798
    {
1799
        for (size_t i = 0; i < sr.size(); ++i)
1800
        {
1801
            if (sr[i].fi != id)
1802
                mChanged = true;
1803
 
1804
            sr[i].fi = id;
1805
        }
1806
    }
1807
    else if (sr[instance].fi != id)
1808
    {
1809
        mChanged = true;
1810
        sr[instance].fi = id;
1811
    }
1812
#if TESTMODE == 1
1813
    setScreenDone();
1814
#endif
149 andreas 1815
    return true;
1816
}
1817
 
16 andreas 1818
bool TButton::setBitmap(const string& file, int instance)
1819
{
1820
    DECL_TRACER("TButton::setBitmap(const string& file, int instance)");
1821
 
165 andreas 1822
    if (instance >= (int)sr.size())
16 andreas 1823
    {
1824
        MSG_ERROR("Invalid parameters!");
1825
        return false;
1826
    }
1827
 
165 andreas 1828
    int inst = instance;
1829
    int loop = 1;
104 andreas 1830
 
165 andreas 1831
    if (inst < 0)
1832
    {
1833
        loop = (int)sr.size();
1834
        inst = 0;
1835
    }
16 andreas 1836
 
165 andreas 1837
    for (int i = 0; i < loop; ++i)
1838
    {
1839
        if (sr[inst].bm == file)
1840
        {
1841
            inst++;
1842
            continue;
1843
        }
16 andreas 1844
 
175 andreas 1845
        mChanged = true;
165 andreas 1846
        sr[inst].bm = file;
1847
 
1848
        if (!file.empty() && !TImgCache::existBitmap(file, _BMTYPE_BITMAP))
1849
        {
1850
            sk_sp<SkData> image;
1851
            SkBitmap bm;
1852
 
1853
            image = readImage(file);
1854
 
1855
            if (image)
1856
            {
1857
                DecodeDataToBitmap(image, &bm);
1858
 
1859
                if (!bm.empty())
167 andreas 1860
                {
165 andreas 1861
                    TImgCache::addImage(sr[inst].bm, bm, _BMTYPE_BITMAP);
167 andreas 1862
                    sr[inst].bm_width = bm.info().width();
1863
                    sr[inst].bm_height = bm.info().height();
1864
                }
165 andreas 1865
            }
1866
        }
1867
 
1868
        inst++;
1869
    }
1870
 
40 andreas 1871
    if (!createButtons(true))   // We're forcing the image to load
16 andreas 1872
        return false;
1873
 
1874
    return makeElement(instance);
1875
}
1876
 
104 andreas 1877
bool TButton::setCameleon(const string& file, int instance)
1878
{
1879
    DECL_TRACER("TButton::setCameleon(const string& file, int instance)");
1880
 
1881
    if (file.empty() || instance >= (int)sr.size())
1882
    {
1883
        MSG_ERROR("Invalid parameters!");
1884
        return false;
1885
    }
1886
 
165 andreas 1887
    int inst = instance;
1888
    int loop = 1;
1889
 
1890
    if (inst < 0)
1891
    {
1892
        loop = (int)sr.size();
1893
        inst = 0;
1894
    }
1895
 
1896
    for (int i = 0; i < loop; ++i)
1897
    {
1898
        if (sr[inst].mi == file)
1899
        {
1900
            inst++;
1901
            continue;
1902
        }
1903
 
175 andreas 1904
        mChanged = true;
165 andreas 1905
        sr[inst].mi = file;
167 andreas 1906
 
1907
        if (!file.empty() && !TImgCache::existBitmap(file, _BMTYPE_CHAMELEON))
1908
        {
1909
            sk_sp<SkData> image;
1910
            SkBitmap bm;
1911
 
1912
            image = readImage(file);
1913
 
1914
            if (image)
1915
            {
1916
                DecodeDataToBitmap(image, &bm);
1917
 
1918
                if (!bm.empty())
1919
                {
1920
                    TImgCache::addImage(sr[inst].mi, bm, _BMTYPE_CHAMELEON);
1921
                    sr[inst].mi_width = bm.info().width();
1922
                    sr[inst].mi_height = bm.info().height();
1923
                }
1924
            }
1925
        }
1926
 
165 andreas 1927
        inst++;
1928
    }
1929
 
104 andreas 1930
    if (!createButtons(true))   // We're forcing the image to load
1931
        return false;
1932
 
1933
    return makeElement(instance);
1934
}
1935
 
224 andreas 1936
bool TButton::setInputMask(const std::string& mask)
1937
{
1938
    DECL_TRACER("TButton::setInputMask(const std::string& mask)");
1939
 
1940
    vector<char> mTable = { '0', '9', '#', 'L', '?', 'A', 'a', '&', 'C',
1941
                            '[', ']', '|', '{', '}', '<', '>', '^' };
1942
    vector<char>::iterator iter;
1943
 
1944
    for (size_t i = 0; i < mask.length(); ++i)
1945
    {
1946
        bool found = false;
1947
 
1948
        for (iter = mTable.begin(); iter != mTable.end(); ++iter)
1949
        {
1950
            if (mask[i] == *iter)
1951
            {
1952
                found = true;
1953
                break;
1954
            }
1955
        }
1956
 
1957
        if (!found)
1958
        {
1959
            MSG_WARNING("The mask letter " << mask[i] << " is invalid!");
1960
            return false;
1961
        }
1962
    }
1963
 
1964
    im = mask;
1965
    return true;
1966
}
1967
 
51 andreas 1968
void TButton::setActiveInstance(int inst)
1969
{
1970
    DECL_TRACER("TButton::setActiveInstance()");
1971
 
1972
    if (inst < 0 || (size_t)inst >= sr.size())
1973
        return;
1974
 
175 andreas 1975
    if (mActInstance != inst)
1976
        mChanged = true;
1977
 
51 andreas 1978
    mActInstance = inst;
1979
}
1980
 
300 andreas 1981
SUBVIEW_POSITION_t TButton::getSubViewAnchor()
1982
{
1983
    DECL_TRACER("TButton::getSubViewAnchor()");
1984
 
1985
    if (we.empty())
1986
        return SVP_CENTER;
1987
    else if (strCaseCompare(we, "l/t") == 0)
1988
        return SVP_LEFT_TOP;
1989
    else if (strCaseCompare(we, "r/b") == 0)
1990
        return SVP_RIGHT_BOTTOM;
1991
 
1992
    return SVP_CENTER;
1993
}
1994
 
110 andreas 1995
bool TButton::getDynamic(int inst)
1996
{
1997
    DECL_TRACER("TButton::getDynamic(int inst)");
1998
 
1999
    if (inst < 0 || inst >= (int)sr.size())
2000
    {
2001
        MSG_ERROR("Instance " << inst << " does not exist!");
2002
        return false;
2003
    }
2004
 
2005
    return sr[inst].dynamic;
2006
}
2007
 
107 andreas 2008
void TButton::setDynamic(int d, int inst)
2009
{
2010
    DECL_TRACER("TButton::setDynamic(int d, int inst)");
2011
 
2012
    if (inst >= (int)sr.size())
2013
    {
2014
        MSG_ERROR("Instance is out of size!");
2015
        return;
2016
    }
2017
 
2018
    bool dyn = (d != 0) ? true : false;
2019
 
2020
    if (inst < 0)
2021
    {
2022
        vector<SR_T>::iterator iter;
2023
        int instance = 0;
2024
 
2025
        for (iter = sr.begin(); iter != sr.end(); ++iter)
2026
        {
2027
            bool old = iter->dynamic;
2028
            iter->dynamic = dyn;
2029
 
2030
            if (old && old != dyn && mActInstance == instance)
2031
            {
2032
                THR_REFRESH_t *thref = _findResource(mHandle, getParent(), bi);
2033
 
2034
                if (thref)
2035
                {
2036
                    TImageRefresh *mImageRefresh = thref->mImageRefresh;
2037
 
2038
                    if (mImageRefresh)
2039
                        mImageRefresh->stop();
2040
                }
2041
 
175 andreas 2042
                mChanged = true;
107 andreas 2043
                makeElement(instance);
2044
            }
2045
 
2046
            instance++;
2047
        }
2048
    }
2049
    else
2050
    {
2051
        bool old = sr[inst].dynamic;
2052
        sr[inst].dynamic = dyn;
2053
 
2054
        if (old && old != dyn && mActInstance == inst)
2055
        {
2056
            THR_REFRESH_t *thref = _findResource(mHandle, getParent(), bi);
2057
 
2058
            if (thref)
2059
            {
2060
                TImageRefresh *mImageRefresh = thref->mImageRefresh;
2061
 
2062
                if (mImageRefresh)
2063
                    mImageRefresh->stop();
2064
            }
2065
 
175 andreas 2066
            mChanged = true;
107 andreas 2067
            makeElement(inst);
2068
        }
2069
    }
2070
}
2071
 
110 andreas 2072
int TButton::getOpacity(int inst)
2073
{
2074
    DECL_TRACER("TButoon::getOpacity(int inst)");
2075
 
2076
    if (inst < 0 || inst >= (int)sr.size())
2077
    {
2078
        MSG_ERROR("Instance " << inst << " does not exist!");
2079
        return 0;
2080
    }
2081
 
2082
    return sr[inst].oo;
2083
}
2084
 
16 andreas 2085
bool TButton::setOpacity(int op, int instance)
2086
{
2087
    DECL_TRACER("TButton::setOpacity(int op, int instance)");
2088
 
167 andreas 2089
    if (instance >= 0 && (size_t)instance >= sr.size())
16 andreas 2090
    {
2091
        MSG_ERROR("Instance " << instance << " does not exist!");
2092
        return false;
2093
    }
2094
 
2095
    if (op < 0 || op < 255)
2096
    {
2097
        MSG_ERROR("Invalid opacity " << op << "!");
2098
        return false;
2099
    }
2100
 
165 andreas 2101
    int inst = instance;
2102
    int loop = 1;
2103
 
2104
    if (inst < 0)
2105
    {
2106
        loop = (int)sr.size();
2107
        inst = 0;
2108
    }
2109
 
2110
    for (int i = 0; i < loop; ++i)
2111
    {
2112
        if (sr[inst].oo == op)
2113
        {
2114
            inst++;
2115
            continue;
2116
        }
2117
 
2118
        sr[inst].oo = op;
175 andreas 2119
        mChanged = true;
165 andreas 2120
        inst++;
2121
    }
2122
 
16 andreas 2123
    return makeElement(instance);
2124
}
2125
 
2126
bool TButton::setFont(int id, int instance)
2127
{
2128
    DECL_TRACER("TButton::setFont(int id)");
2129
 
205 andreas 2130
    if (!setFontOnly(id, instance))
2131
        return false;
2132
 
2133
    return makeElement(instance);
2134
}
2135
 
2136
bool TButton::setFontOnly(int id, int instance)
2137
{
2138
    DECL_TRACER("TButton::setFontOnly(int id)");
2139
 
167 andreas 2140
    if (instance >= 0 && (size_t)instance >= sr.size())
16 andreas 2141
    {
2142
        MSG_ERROR("Instance " << instance << " does not exist!");
2143
        return false;
2144
    }
2145
 
165 andreas 2146
    int inst = instance;
2147
    int loop = 1;
2148
 
2149
    if (inst < 0)
2150
    {
2151
        loop = (int)sr.size();
2152
        inst = 0;
2153
    }
2154
 
2155
    for (int i = 0; i < loop; ++i)
2156
    {
2157
        if (sr[inst].fi == id)
2158
        {
2159
            inst++;
2160
            continue;
2161
        }
2162
 
2163
        sr[inst].fi = id;
175 andreas 2164
        mChanged = true;
165 andreas 2165
        inst++;
2166
    }
2167
 
205 andreas 2168
    return true;
16 andreas 2169
}
2170
 
2171
void TButton::setLeft(int left)
2172
{
2173
    DECL_TRACER("TButton::setLeft(int left)");
2174
 
2175
    if (left < 0)
2176
        return;
2177
 
175 andreas 2178
    if (lt != left)
2179
        mChanged = true;
2180
 
16 andreas 2181
    lt = left;
2182
    makeElement(mActInstance);
2183
}
2184
 
2185
void TButton::setTop(int top)
2186
{
2187
    DECL_TRACER("TButton::setTop(int top)");
2188
 
2189
    if (top < 0)
2190
        return;
2191
 
175 andreas 2192
    if (tp != top)
2193
        mChanged = true;
2194
 
16 andreas 2195
    tp = top;
2196
    makeElement(mActInstance);
2197
}
2198
 
2199
void TButton::setLeftTop(int left, int top)
2200
{
2201
    DECL_TRACER("TButton::setLeftTop(int left, int top)");
2202
 
2203
    if (top < 0 || left < 0)
2204
        return;
2205
 
175 andreas 2206
    if (lt != left || tp != top)
2207
        mChanged = true;
2208
 
16 andreas 2209
    lt = left;
2210
    tp = top;
2211
    makeElement(mActInstance);
2212
}
2213
 
152 andreas 2214
void TButton::setRectangle(int left, int top, int right, int bottom)
2215
{
2216
    DECL_TRACER("setRectangle(int left, int top, int right, int bottom)");
2217
 
2218
    if (!gPageManager)
2219
        return;
2220
 
217 andreas 2221
    int screenWidth = gPageManager->getSettings()->getWidth();
152 andreas 2222
    int screenHeight = gPageManager->getSettings()->getHeight();
2223
    int width = right - left;
2224
    int height = bottom - top;
2225
 
2226
    if (left >= 0 && right > left && (left + width) < screenWidth)
2227
        lt = left;
2228
 
2229
    if (top >= 0 && bottom > top && (top + height) < screenHeight)
2230
        tp = top;
2231
 
2232
    if (left >= 0 && right > left)
2233
        wt = width;
2234
 
2235
    if (top >= 0 && bottom > top)
2236
        ht = height;
2237
}
2238
 
334 andreas 2239
void TButton::getRectangle(int *left, int *top, int *height, int *width)
2240
{
2241
    DECL_TRACER("TButton::getRectangle(int *left, int *top, int *height, int *width)");
2242
 
2243
    if (left)
2244
        *left = lt;
2245
 
2246
    if (top)
2247
        *top = tp;
2248
 
2249
    if (height)
2250
        *height = ht;
2251
 
2252
    if (width)
2253
        *width = wt;
2254
 
2255
}
2256
 
21 andreas 2257
void TButton::setResourceName(const string& name, int instance)
2258
{
2259
    DECL_TRACER("TButton::setResourceName(const string& name, int instance)");
2260
 
165 andreas 2261
    if (instance >= (int)sr.size())
21 andreas 2262
    {
2263
        MSG_ERROR("Invalid instance " << instance);
2264
        return;
2265
    }
2266
 
165 andreas 2267
    int inst = instance;
2268
    int loop = 1;
2269
 
2270
    if (inst < 0)
21 andreas 2271
    {
165 andreas 2272
        loop = (int)sr.size();
2273
        inst = 0;
21 andreas 2274
    }
2275
 
165 andreas 2276
    for (int i = 0; i < loop; ++i)
2277
    {
2278
        if (!sr[inst].dynamic)
2279
        {
2280
            inst++;
2281
            continue;
2282
        }
2283
 
176 andreas 2284
        if (sr[inst].bm != name)
2285
            mChanged = true;
2286
 
165 andreas 2287
        sr[inst].bm = name;
2288
        inst++;
2289
    }
21 andreas 2290
}
2291
 
106 andreas 2292
int TButton::getBitmapJustification(int* x, int* y, int instance)
104 andreas 2293
{
106 andreas 2294
    DECL_TRACER("TButton::getBitmapJustification(int* x, int* y, int instance)");
104 andreas 2295
 
106 andreas 2296
    if (instance < 0 || instance >= (int)sr.size())
2297
    {
2298
        MSG_ERROR("Invalid instance " << (instance + 1));
2299
        return -1;
2300
    }
2301
 
2302
    if (x)
334 andreas 2303
        *x = sr[instance].jb == 0 ? sr[instance].bx : 0;
106 andreas 2304
 
2305
    if (y)
334 andreas 2306
        *y = sr[instance].jb == 0 ? sr[instance].by : 0;
106 andreas 2307
 
2308
    return sr[instance].jb;
2309
}
2310
 
2311
void TButton::setBitmapJustification(int j, int x, int y, int instance)
2312
{
2313
    DECL_TRACER("TButton::setBitmapJustification(int j, int instance)");
2314
 
165 andreas 2315
    if (j < 0 || j > 9 || instance >= (int)sr.size())
334 andreas 2316
    {
2317
#if TESTMODE == 1
2318
        setScreenDone();
2319
#endif
104 andreas 2320
        return;
334 andreas 2321
    }
104 andreas 2322
 
106 andreas 2323
    if (instance < 0)
104 andreas 2324
    {
2325
        for (size_t i = 0; i < sr.size(); i++)
2326
        {
176 andreas 2327
            if (sr[i].jb != j)
2328
                mChanged = true;
2329
 
104 andreas 2330
            sr[i].jb = j;
2331
 
2332
            if (j == 0)
2333
            {
2334
                sr[i].bx = x;
2335
                sr[i].by = y;
2336
            }
2337
        }
2338
    }
2339
    else
2340
    {
176 andreas 2341
        if (sr[instance].jb != j)
2342
            mChanged = true;
2343
 
104 andreas 2344
        sr[instance].jb = j;
2345
 
2346
        if (j == 0)
2347
        {
2348
            sr[instance].bx = x;
2349
            sr[instance].by = y;
2350
        }
2351
    }
110 andreas 2352
 
2353
    makeElement();
104 andreas 2354
}
2355
 
106 andreas 2356
int TButton::getIconJustification(int* x, int* y, int instance)
2357
{
2358
    DECL_TRACER("TButton::getIconJustification(int* x, int* y, int instance)");
2359
 
2360
    if (instance < 0 || instance >= (int)sr.size())
2361
    {
2362
        MSG_ERROR("Invalid instance " << (instance + 1));
2363
        return -1;
2364
    }
2365
 
2366
    if (x)
334 andreas 2367
        *x = sr[instance].ji == 0 ? sr[instance].ix : 0;
106 andreas 2368
 
2369
    if (y)
334 andreas 2370
        *y = sr[instance].ji == 0 ? sr[instance].iy : 0;
106 andreas 2371
 
2372
    return sr[instance].ji;
2373
}
2374
 
104 andreas 2375
void TButton::setIconJustification(int j, int x, int y, int instance)
2376
{
2377
    DECL_TRACER("TButton::setIconJustification(int j, int x, int y, int instance)");
2378
 
165 andreas 2379
    if (j < 0 || j > 9 || instance >= (int)sr.size())
334 andreas 2380
    {
2381
#if TESTMODE == 1
2382
        setScreenDone();
2383
#endif
104 andreas 2384
        return;
334 andreas 2385
    }
104 andreas 2386
 
106 andreas 2387
    if (instance < 0)
104 andreas 2388
    {
2389
        for (size_t i = 0; i < sr.size(); i++)
2390
        {
176 andreas 2391
            if (sr[i].ji != j)
2392
                mChanged = true;
2393
 
104 andreas 2394
            sr[i].ji = j;
2395
 
2396
            if (j == 0)
2397
            {
2398
                sr[i].ix = x;
2399
                sr[i].iy = y;
2400
            }
2401
        }
2402
    }
2403
    else
2404
    {
176 andreas 2405
        if (sr[instance].ji != j)
2406
            mChanged = true;
2407
 
104 andreas 2408
        sr[instance].ji = j;
2409
 
2410
        if (j == 0)
2411
        {
2412
            sr[instance].ix = x;
2413
            sr[instance].iy = y;
2414
        }
2415
    }
110 andreas 2416
 
2417
    makeElement();
104 andreas 2418
}
2419
 
106 andreas 2420
int TButton::getTextJustification(int* x, int* y, int instance)
2421
{
2422
    DECL_TRACER("TButton::getTextJustification(int* x, int* y, int instance)");
2423
 
2424
    if (instance < 0 || instance >= (int)sr.size())
2425
    {
2426
        MSG_ERROR("Invalid instance " << (instance + 1));
2427
        return -1;
2428
    }
2429
 
2430
    if (x)
334 andreas 2431
        *x = sr[instance].jt == 0 ? sr[instance].tx : 0;
106 andreas 2432
 
2433
    if (y)
334 andreas 2434
        *y = sr[instance].jt == 0 ? sr[instance].ty : 0;
106 andreas 2435
 
2436
    return sr[instance].jt;
2437
}
2438
 
104 andreas 2439
void TButton::setTextJustification(int j, int x, int y, int instance)
2440
{
2441
    DECL_TRACER("TButton::setTextJustification(int j, int x, int y, int instance)");
2442
 
205 andreas 2443
    if (!setTextJustificationOnly(j, x, y, instance))
334 andreas 2444
    {
2445
#if TESTMODE == 1
2446
        setScreenDone();
2447
#endif
104 andreas 2448
        return;
334 andreas 2449
    }
104 andreas 2450
 
205 andreas 2451
    makeElement();
2452
}
2453
 
2454
bool TButton::setTextJustificationOnly(int j, int x, int y, int instance)
2455
{
2456
    DECL_TRACER("TButton::setTextJustificationOnly(int j, int x, int y, int instance)");
2457
 
2458
    if (j < 0 || j > 9 || instance >= (int)sr.size())
2459
        return false;
2460
 
106 andreas 2461
    if (instance < 0)
104 andreas 2462
    {
2463
        for (size_t i = 0; i < sr.size(); i++)
2464
        {
176 andreas 2465
            if (sr[i].jt != j)
2466
                mChanged = true;
2467
 
104 andreas 2468
            sr[i].jt = (TEXT_ORIENTATION)j;
2469
 
2470
            if (j == 0)
2471
            {
2472
                sr[i].tx = x;
2473
                sr[i].ty = y;
2474
            }
2475
        }
2476
    }
2477
    else
2478
    {
176 andreas 2479
        if (sr[instance].jt != j)
2480
            mChanged = true;
2481
 
104 andreas 2482
        sr[instance].jt = (TEXT_ORIENTATION)j;
2483
 
2484
        if (j == 0)
2485
        {
2486
            sr[instance].tx = x;
2487
            sr[instance].ty = y;
2488
        }
2489
    }
110 andreas 2490
 
205 andreas 2491
    return true;
104 andreas 2492
}
2493
 
110 andreas 2494
string TButton::getText(int inst)
2495
{
2496
    DECL_TRACER("TButton::getText(int inst)");
2497
 
2498
    if (inst < 0 || inst >= (int)sr.size())
2499
    {
2500
        MSG_ERROR("Instance " << inst << " does not exist!");
2501
        return string();
2502
    }
2503
 
2504
    return sr[inst].te;
2505
}
2506
 
2507
string TButton::getTextColor(int inst)
2508
{
2509
    DECL_TRACER("TButton::getTextColor(int const)");
2510
 
2511
    if (inst < 0 || inst >= (int)sr.size())
2512
    {
2513
        MSG_ERROR("Instance " << inst << " does not exist!");
2514
        return string();
2515
    }
2516
 
2517
    return sr[inst].ct;
2518
}
2519
 
2520
string TButton::getTextEffectColor(int inst)
2521
{
2522
    DECL_TRACER ("TButton::getTextEffectColor(int inst)");
2523
 
2524
    if (inst < 0 || inst >= (int)sr.size())
2525
    {
2526
        MSG_ERROR("Instance " << inst << " does not exist!");
2527
        return string();
2528
    }
2529
 
2530
    return sr[inst].ec;
2531
}
2532
 
165 andreas 2533
void TButton::setTextEffectColor(const string& ec, int instance)
108 andreas 2534
{
2535
    DECL_TRACER("TButton::setTextEffectColor(const string& ec, int inst)");
2536
 
205 andreas 2537
    if (!setTextEffectColorOnly(ec, instance))
2538
        return;
2539
 
2540
    if (visible)
2541
        makeElement();
2542
}
2543
 
2544
bool TButton::setTextEffectColorOnly(const string& ec, int instance)
2545
{
2546
    DECL_TRACER("TButton::setTextEffectColorOnly(const string& ec, int inst)");
2547
 
165 andreas 2548
    if ((size_t)instance >= sr.size())
108 andreas 2549
    {
165 andreas 2550
        MSG_ERROR("Instance " << instance << " does not exist!");
205 andreas 2551
        return false;
108 andreas 2552
    }
2553
 
2554
    if (!TColor::isValidAMXcolor(ec))
2555
    {
2556
        MSG_PROTOCOL("Invalid color >" << ec << "< ignored!");
205 andreas 2557
        return false;
108 andreas 2558
    }
2559
 
165 andreas 2560
    int inst = instance;
2561
    int loop = 1;
108 andreas 2562
 
2563
    if (inst < 0)
2564
    {
165 andreas 2565
        loop = (int)sr.size();
2566
        inst = 0;
108 andreas 2567
    }
165 andreas 2568
 
2569
    for (int i = 0; i < loop; ++i)
2570
    {
2571
        if (sr[inst].ec.compare(ec) == 0)
2572
        {
2573
            inst++;
2574
            continue;
2575
        }
2576
 
108 andreas 2577
        sr[inst].ec = ec;
176 andreas 2578
        mChanged = true;
165 andreas 2579
        inst++;
2580
    }
108 andreas 2581
 
205 andreas 2582
    return true;
108 andreas 2583
}
2584
 
110 andreas 2585
int TButton::getTextEffect(int inst)
16 andreas 2586
{
110 andreas 2587
    DECL_TRACER("TButton::getTextEffect(int inst)");
2588
 
2589
    if (inst < 0 || inst >= (int)sr.size())
2590
    {
2591
        MSG_ERROR("Instance " << inst << " does not exist!");
2592
        return 0;
2593
    }
2594
 
2595
    return sr[inst].et;
2596
}
2597
 
2598
void TButton::setTextEffect(int et, int inst)
2599
{
2600
    DECL_TRACER("TButton::setTextEffect(bool et, int inst)");
2601
 
2602
    if (inst >= (int)sr.size())
2603
    {
2604
        MSG_ERROR("instance " << inst << " is out of bounds!");
2605
        return;
2606
    }
2607
 
2608
    if (inst < 0)
2609
    {
2610
        for (size_t i = 0; i < sr.size(); i++)
176 andreas 2611
        {
2612
            if (sr[i].et != et)
2613
                mChanged = true;
2614
 
110 andreas 2615
            sr[i].et = et;
176 andreas 2616
        }
110 andreas 2617
    }
2618
    else
176 andreas 2619
    {
2620
        if (sr[inst].et != et)
2621
            mChanged = true;
2622
 
110 andreas 2623
        sr[inst].et = et;
176 andreas 2624
    }
110 andreas 2625
 
2626
    makeElement();
2627
}
2628
 
2629
string TButton::getTextEffectName(int inst)
2630
{
2631
    DECL_TRACER("TButton::getTextEffectName(int inst)");
2632
 
2633
    if (inst < 0 || inst >= (int)sr.size())
2634
        return string();
2635
 
2636
    int idx = 0;
2637
 
2638
    while (sysTefs[idx].idx)
2639
    {
2640
        if (sysTefs[idx].idx == sr[inst].et)
2641
            return sysTefs[idx].name;
2642
 
2643
        idx++;
2644
    }
2645
 
2646
    return string();
2647
}
2648
 
2649
void TButton::setTextEffectName(const string& name, int inst)
2650
{
2651
    DECL_TRACER("TButton::setTextEffectName(const string& name, int inst)");
2652
 
2653
    if (inst >= (int)sr.size())
2654
        return;
2655
 
2656
    int idx = 0;
2657
 
2658
    while (sysTefs[idx].idx)
2659
    {
2660
        if (strCaseCompare(sysTefs[idx].name, name) == 0)
2661
        {
2662
            if (inst < 0)
2663
            {
2664
                for (size_t i = 0; i < sr.size(); i++)
176 andreas 2665
                {
2666
                    if (sr[i].et != sysTefs[idx].idx)
2667
                        mChanged = true;
2668
 
110 andreas 2669
                    sr[i].et = sysTefs[idx].idx;
176 andreas 2670
                }
110 andreas 2671
            }
2672
            else
176 andreas 2673
            {
2674
                if (sr[inst].et != sysTefs[idx].idx)
2675
                    mChanged = true;
2676
 
110 andreas 2677
                sr[inst].et = sysTefs[idx].idx;
176 andreas 2678
            }
110 andreas 2679
 
2680
            makeElement();
2681
            break;
2682
        }
2683
 
2684
        idx++;
2685
    }
2686
}
2687
 
2688
string TButton::getBitmapName(int inst)
2689
{
2690
    DECL_TRACER("TButton::getBitmapName(int inst)");
2691
 
2692
    if (inst < 0 || inst >= (int)sr.size())
2693
    {
2694
        MSG_ERROR("Instance " << inst << " does not exist!");
2695
        return string();
2696
    }
2697
 
2698
    return sr[inst].bm;
2699
}
2700
 
2701
string TButton::getFillColor(int inst)
2702
{
2703
    DECL_TRACER("TButton::getFillColor(int inst)");
2704
 
2705
    if (inst < 0 || inst >= (int)sr.size())
2706
    {
2707
        MSG_ERROR("Instance " << inst << " does not exist!");
2708
        return string();
2709
    }
2710
 
2711
    return sr[inst].cf;
2712
}
2713
 
2714
bool TButton::setTextWordWrap(bool state, int instance)
2715
{
16 andreas 2716
    DECL_TRACER("TButton::setWorWrap(bool state, int instance)");
2717
 
110 andreas 2718
    if (instance >= (int)sr.size())
16 andreas 2719
    {
2720
        MSG_ERROR("Invalid instance " << instance);
2721
        return false;
2722
    }
2723
 
176 andreas 2724
    int stt = state ? 1 : 0;
2725
 
110 andreas 2726
    if (instance < 0)
2727
    {
2728
        for (size_t i = 0; i < sr.size(); i++)
176 andreas 2729
        {
2730
            if (sr[i].ww != stt)
2731
                mChanged = true;
2732
 
2733
            sr[i].ww = stt;
2734
        }
110 andreas 2735
    }
2736
    else
176 andreas 2737
    {
2738
        if (sr[instance].ww != stt)
2739
            mChanged = true;
110 andreas 2740
 
176 andreas 2741
        sr[instance].ww = stt;
2742
    }
2743
 
16 andreas 2744
    return makeElement(instance);
2745
}
2746
 
110 andreas 2747
bool TButton::getTextWordWrap(int inst)
2748
{
2749
    DECL_TRACER("TButton::getTextWordWrap(int inst)");
2750
 
2751
    if (inst < 0 || inst >= (int)sr.size())
2752
    {
2753
        MSG_ERROR("Instance " << inst << " does not exist!");
2754
        return false;
2755
    }
2756
 
2757
    return (sr[inst].ww == 1);
2758
}
2759
 
2760
int TButton::getFontIndex(int inst)
2761
{
2762
    DECL_TRACER("TButton::getFontIndex(int inst)");
2763
 
2764
    if (inst < 0 || inst >= (int)sr.size())
2765
    {
2766
        MSG_ERROR("Instance " << inst << " does not exist!");
2767
        return 0;
2768
    }
2769
 
2770
    return sr[inst].fi;
2771
}
2772
 
165 andreas 2773
bool TButton::setFontIndex(int fi, int instance)
110 andreas 2774
{
2775
    DECL_TRACER("TButton::setFontIndex(int fi, int inst)");
2776
 
165 andreas 2777
    if (instance >= (int)sr.size())
110 andreas 2778
    {
165 andreas 2779
        MSG_ERROR("Invalid instance " << instance);
110 andreas 2780
        return false;
2781
    }
2782
 
165 andreas 2783
    int inst = instance;
2784
    int loop = 1;
2785
 
110 andreas 2786
    if (inst < 0)
2787
    {
165 andreas 2788
        loop = (int)sr.size();
2789
        inst = 0;
110 andreas 2790
    }
165 andreas 2791
 
2792
    for (int i = 0; i < loop; ++i)
2793
    {
176 andreas 2794
        if (sr[inst].fi != fi)
2795
            mChanged = true;
2796
 
110 andreas 2797
        sr[inst].fi = fi;
165 andreas 2798
        inst++;
2799
    }
110 andreas 2800
 
2801
    return makeElement(inst);
2802
}
2803
 
2804
int TButton::getIconIndex(int inst)
2805
{
2806
    DECL_TRACER("TButton::getIconIndex(int inst)");
2807
 
2808
    if (inst < 0 || inst >= (int)sr.size())
2809
    {
2810
        MSG_ERROR("Instance " << inst << " does not exist!");
2811
        return 0;
2812
    }
2813
 
2814
    return sr[inst].ii;
2815
}
2816
 
2817
string TButton::getSound(int inst)
2818
{
2819
    DECL_TRACER("TButton::getSound(int inst)");
2820
 
2821
    if (inst < 0 || inst >= (int)sr.size())
2822
    {
2823
        MSG_ERROR("Instance " << inst << " does not exist!");
2824
        return string();
2825
    }
2826
 
2827
    return sr[inst].sd;
2828
}
2829
 
2830
void TButton::setSound(const string& sound, int inst)
2831
{
2832
    DECL_TRACER("TButton::setSound(const string& sound, int inst)");
2833
 
2834
    if (inst >= (int)sr.size())
2835
    {
2836
        MSG_ERROR("Invalid instance " << inst);
2837
        return;
2838
    }
2839
 
2840
    if (inst < 0)
2841
    {
2842
        for (size_t i = 0; i < sr.size(); i++)
176 andreas 2843
        {
2844
            if (sr[i].sd != sound)
2845
                mChanged = true;
2846
 
110 andreas 2847
            sr[i].sd = sound;
176 andreas 2848
        }
110 andreas 2849
    }
2850
    else
176 andreas 2851
    {
2852
        if (sr[inst].sd != sound)
2853
            mChanged = true;
2854
 
110 andreas 2855
        sr[inst].sd = sound;
176 andreas 2856
    }
110 andreas 2857
}
2858
 
320 andreas 2859
bool TButton::startAnimation(int st, int end, int time)
38 andreas 2860
{
2861
    DECL_TRACER("TButton::startAnimation(int start, int end, int time)");
2862
 
320 andreas 2863
    if (st > end || st < 0 || (size_t)end > sr.size() || time < 0)
38 andreas 2864
    {
320 andreas 2865
        MSG_ERROR("Invalid parameter: start=" << st << ", end=" << end << ", time=" << time);
38 andreas 2866
        return false;
2867
    }
2868
 
320 andreas 2869
    if (time <= 1)
153 andreas 2870
    {
2871
        int inst = end - 1;
2872
 
2873
        if (inst >= 0 && (size_t)inst < sr.size())
2874
        {
2875
            if (mActInstance != inst)
2876
            {
2877
                mActInstance = inst;
320 andreas 2878
                mChanged = true;
153 andreas 2879
                drawButton(inst);
2880
            }
2881
        }
2882
 
2883
        return true;
2884
    }
2885
 
320 andreas 2886
    int start = std::max(1, st);
2887
 
38 andreas 2888
    if (mAniRunning || mThrAni.joinable())
2889
    {
99 andreas 2890
        MSG_PROTOCOL("Animation is already running!");
38 andreas 2891
        return true;
2892
    }
2893
 
2894
    int number = end - start;
2895
    ulong stepTime = ((ulong)time * 10L) / (ulong)number;
2896
    mAniRunTime = (ulong)time * 10L;
2897
 
2898
    try
2899
    {
93 andreas 2900
        mAniStop = false;
38 andreas 2901
        mThrAni = thread([=] { runAnimationRange(start, end, stepTime); });
2902
        mThrAni.detach();
2903
    }
2904
    catch (exception& e)
2905
    {
2906
        MSG_ERROR("Error starting the button animation thread: " << e.what());
2907
        return false;
2908
    }
2909
 
2910
    return true;
2911
}
2912
 
22 andreas 2913
void TButton::_TimerCallback(ulong)
15 andreas 2914
{
2915
    mLastBlink.second++;
2916
    int months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
2917
 
2918
    if ((mLastBlink.year % 4) == 0)
2919
        months[1] = 29;
2920
 
2921
    if (mLastBlink.second > 59)
2922
    {
2923
        mLastBlink.minute++;
2924
        mLastBlink.second = 0;
2925
 
2926
        if (mLastBlink.minute > 59)
2927
        {
2928
            mLastBlink.hour++;
2929
            mLastBlink.minute = 0;
2930
 
2931
            if (mLastBlink.hour >= 24)
2932
            {
2933
                mLastBlink.hour = 0;
2934
                mLastBlink.weekday++;
2935
                mLastBlink.day++;
2936
 
2937
                if (mLastBlink.weekday > 7)
2938
                    mLastBlink.weekday = 0;
2939
 
2940
                if (mLastBlink.day > months[mLastBlink.month-1])
2941
                {
2942
                    mLastBlink.day = 1;
2943
                    mLastBlink.month++;
2944
 
2945
                    if (mLastBlink.month > 12)
2946
                    {
2947
                        mLastBlink.year++;
2948
                        mLastBlink.month = 1;
2949
                    }
2950
                }
2951
            }
2952
        }
2953
    }
2954
 
2955
    funcTimer(mLastBlink);
2956
}
2957
 
21 andreas 2958
void TButton::_imageRefresh(const string& url)
2959
{
2960
    DECL_TRACER("TButton::_imageRefresh(const string& url)");
2961
 
38 andreas 2962
    if (prg_stopped || killed || !visible)
33 andreas 2963
        return;
35 andreas 2964
 
2965
    if (!gPrjResources)
2966
    {
2967
        MSG_WARNING("No resources available!");
2968
        return;
2969
    }
2970
 
21 andreas 2971
    ulong parent = mHandle & 0xffff0000;
2972
    getDrawOrder(sr[mActInstance]._do, (DRAW_ORDER *)&mDOrder);
2973
 
2974
    if (TError::isError())
2975
    {
2976
        TError::clear();
2977
        return;
2978
    }
2979
 
2980
    SkBitmap imgButton;
2981
 
254 andreas 2982
    if (!allocPixels(wt, ht, &imgButton))
2983
        return;
2984
 
21 andreas 2985
    for (int i = 0; i < ORD_ELEM_COUNT; i++)
2986
    {
2987
        if (mDOrder[i] == ORD_ELEM_FILL)
2988
        {
2989
            if (!buttonFill(&imgButton, mActInstance))
2990
                return;
2991
        }
2992
        else if (mDOrder[i] == ORD_ELEM_BITMAP)
2993
        {
2994
            RESOURCE_T resource = gPrjResources->findResource(sr[mActInstance].bm);
2995
 
2996
            if (resource.protocol.empty())
2997
            {
2998
                MSG_ERROR("Resource " << sr[mActInstance].bm << " not found!");
2999
                return;
3000
            }
3001
 
94 andreas 3002
            THTTPClient *WEBClient = nullptr;
3003
 
21 andreas 3004
            try
3005
            {
3006
                char *content = nullptr;
3007
                size_t length = 0, contentlen = 0;
3008
 
94 andreas 3009
                WEBClient = new THTTPClient;
3010
 
3011
                if (WEBClient && (content = WEBClient->tcall(&length, url, resource.user, resource.password)) == nullptr)
3012
                {
3013
                    if (WEBClient)
3014
                        delete WEBClient;
3015
 
21 andreas 3016
                    return;
94 andreas 3017
                }
21 andreas 3018
 
94 andreas 3019
                contentlen = WEBClient->getContentSize();
21 andreas 3020
 
3021
                if (content == nullptr)
3022
                {
3023
                    MSG_ERROR("Server returned no or invalid content!");
94 andreas 3024
                    delete WEBClient;
21 andreas 3025
                    return;
3026
                }
3027
 
3028
                sk_sp<SkData> data = SkData::MakeWithCopy(content, contentlen);
3029
 
3030
                if (!data)
3031
                {
3032
                    MSG_ERROR("Could not make an image!");
94 andreas 3033
                    delete WEBClient;
21 andreas 3034
                    return;
3035
                }
3036
 
3037
                SkBitmap image;
3038
 
3039
                if (!DecodeDataToBitmap(data, &image))
3040
                {
3041
                    MSG_ERROR("Error creating an image!");
94 andreas 3042
                    delete WEBClient;
21 andreas 3043
                    return;
3044
                }
3045
 
3046
                loadImage(&imgButton, image, mActInstance);
94 andreas 3047
                delete WEBClient;
21 andreas 3048
            }
3049
            catch (std::exception& e)
3050
            {
94 andreas 3051
                if (WEBClient)
3052
                    delete WEBClient;
3053
 
21 andreas 3054
                MSG_ERROR(e.what());
3055
                return;
3056
            }
93 andreas 3057
            catch(...)
3058
            {
94 andreas 3059
                if (WEBClient)
3060
                    delete WEBClient;
3061
 
93 andreas 3062
                MSG_ERROR("Unexpected exception occured. [TButton::_imageRefresh()]");
3063
                return;
3064
            }
21 andreas 3065
        }
3066
        else if (mDOrder[i] == ORD_ELEM_ICON)
3067
        {
3068
            if (!buttonIcon(&imgButton, mActInstance))
3069
                return;
3070
        }
3071
        else if (mDOrder[i] == ORD_ELEM_TEXT)
3072
        {
3073
            if (!buttonText(&imgButton, mActInstance))
3074
                return;
3075
        }
3076
        else if (mDOrder[i] == ORD_ELEM_BORDER)
3077
        {
3078
            if (!buttonBorder(&imgButton, mActInstance))
3079
                return;
3080
        }
3081
    }
3082
 
3083
    if (mGlobalOO >= 0 || sr[mActInstance].oo >= 0) // Take overall opacity into consideration
3084
    {
3085
        SkBitmap ooButton;
3086
        int w = imgButton.width();
3087
        int h = imgButton.height();
254 andreas 3088
 
3089
        if (!allocPixels(w, h, &ooButton))
3090
            return;
3091
 
21 andreas 3092
        SkCanvas canvas(ooButton);
3093
        SkIRect irect = SkIRect::MakeXYWH(0, 0, w, h);
3094
        SkRegion region;
3095
        region.setRect(irect);
3096
        SkScalar oo;
3097
 
3098
        if (mGlobalOO >= 0 && sr[mActInstance].oo >= 0)
3099
        {
3100
            oo = std::min((SkScalar)mGlobalOO, (SkScalar)sr[mActInstance].oo);
3101
            MSG_DEBUG("Set global overal opacity to " << oo);
3102
        }
3103
        else if (sr[mActInstance].oo >= 0)
3104
        {
3105
            oo = (SkScalar)sr[mActInstance].oo;
3106
            MSG_DEBUG("Set overal opacity to " << oo);
3107
        }
3108
        else
3109
        {
3110
            oo = (SkScalar)mGlobalOO;
3111
            MSG_DEBUG("Set global overal opacity to " << oo);
3112
        }
3113
 
3114
        SkScalar alpha = 1.0 / 255.0 * oo;
3115
        MSG_DEBUG("Calculated alpha value: " << alpha);
3116
        SkPaint paint;
3117
        paint.setAlphaf(alpha);
3118
        paint.setImageFilter(SkImageFilters::AlphaThreshold(region, 0.0, alpha, nullptr));
179 andreas 3119
        sk_sp<SkImage> _image = SkImage::MakeFromBitmap(imgButton);
3120
        canvas.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
21 andreas 3121
        imgButton.erase(SK_ColorTRANSPARENT, {0, 0, w, h});
3122
        imgButton = ooButton;
3123
    }
3124
 
3125
    mLastImage = imgButton;
177 andreas 3126
    mChanged = false;
21 andreas 3127
 
3128
    if (!prg_stopped && visible && _displayButton)
26 andreas 3129
    {
3130
        int rwidth = wt;
3131
        int rheight = ht;
3132
        int rleft = lt;
3133
        int rtop = tp;
43 andreas 3134
#ifdef _SCALE_SKIA_
26 andreas 3135
        if (gPageManager && gPageManager->getScaleFactor() != 1.0)
3136
        {
3137
            rwidth = (int)((double)wt * gPageManager->getScaleFactor());
3138
            rheight = (int)((double)ht * gPageManager->getScaleFactor());
3139
            rleft = (int)((double)lt * gPageManager->getScaleFactor());
3140
            rtop = (int)((double)tp * gPageManager->getScaleFactor());
3141
 
3142
            SkPaint paint;
3143
            paint.setBlendMode(SkBlendMode::kSrc);
3144
            paint.setFilterQuality(kHigh_SkFilterQuality);
28 andreas 3145
            // Calculate new dimension
26 andreas 3146
            SkImageInfo info = imgButton.info();
3147
            int width = (int)((double)info.width() * gPageManager->getScaleFactor());
3148
            int height = (int)((double)info.height() * gPageManager->getScaleFactor());
28 andreas 3149
            // Create a canvas and draw new image
3150
            sk_sp<SkImage> im = SkImage::MakeFromBitmap(imgButton);
3151
            imgButton.allocN32Pixels(width, height);
3152
            imgButton.eraseColor(SK_ColorTRANSPARENT);
254 andreas 3153
            SkCanvas can(imgButton, SkSurfaceProps());
26 andreas 3154
            SkRect rect = SkRect::MakeXYWH(0, 0, width, height);
179 andreas 3155
            can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
28 andreas 3156
            rowBytes = imgButton.info().minRowBytes();
3157
            mLastImage = imgButton;
26 andreas 3158
        }
43 andreas 3159
#endif
289 andreas 3160
        TBitmap image((unsigned char *)imgButton.getPixels(), imgButton.info().width(), imgButton.info().height());
298 andreas 3161
        _displayButton(mHandle, parent, image, rwidth, rheight, rleft, rtop, isPassThrough());
26 andreas 3162
    }
21 andreas 3163
}
3164
 
15 andreas 3165
void TButton::registerSystemButton()
3166
{
3167
    DECL_TRACER("TButton::registerSystemButton()");
3168
 
3169
    if (mSystemReg)
3170
        return;
3171
 
3172
    // If this is a special system button, register it to receive the state
206 andreas 3173
    if (ap == 0 && ad == SYSTEM_ITEM_CONNSTATE)     // Connection status?
15 andreas 3174
    {
3175
        MSG_TRACE("Try to register button " << na << " as connection status ...");
3176
 
3177
        if (gAmxNet)
3178
        {
3179
            gAmxNet->registerNetworkState(bind(&TButton::funcNetwork, this, std::placeholders::_1), mHandle);
3180
            mSystemReg = true;
3181
            MSG_TRACE("Button registered");
3182
        }
3183
        else
3184
            MSG_WARNING("Network class not initialized!");
3185
 
3186
    }
206 andreas 3187
    else if (ap == 0 && ((ad >= SYSTEM_ITEM_STANDARDTIME && ad <= SYSTEM_ITEM_TIME24) || (ad >= SYSTEM_ITEM_DATEWEEKDAY && ad <= SYSTEM_ITEM_DATEYYYYMMDD))) // time or date
15 andreas 3188
    {
3189
        MSG_TRACE("Try to register button " << na << " as time/date ...");
3190
 
3191
        if (gAmxNet)
3192
        {
3193
            gAmxNet->registerTimer(bind(&TButton::funcTimer, this, std::placeholders::_1), mHandle);
3194
            mSystemReg = true;
3195
            MSG_TRACE("Button registered");
3196
        }
3197
        else
3198
            MSG_WARNING("Network class not initialized!");
3199
 
206 andreas 3200
        if (ad >= SYSTEM_ITEM_STANDARDTIME && ad <= SYSTEM_ITEM_TIME24 && !mTimer)
15 andreas 3201
        {
3202
            mTimer = new TTimer;
3203
            mTimer->setInterval(std::chrono::milliseconds(1000));   // 1 second
3204
            mTimer->registerCallback(bind(&TButton::_TimerCallback, this, std::placeholders::_1));
3205
            mTimer->run();
3206
        }
3207
    }
206 andreas 3208
    else if (ap == 0 && (ad == SYSTEM_ITEM_BATTERYLEVEL || ad == SYSTEM_ITEM_BATTERYCHARGING))   // Battery status
23 andreas 3209
    {
38 andreas 3210
        if (gPageManager)
247 andreas 3211
        {
3212
#ifdef Q_OS_ANDROID
38 andreas 3213
            gPageManager->regCallbackBatteryState(bind(&TButton::funcBattery, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), mHandle);
247 andreas 3214
#endif
3215
#ifdef Q_OS_IOS
3216
            gPageManager->regCallbackBatteryState(bind(&TButton::funcBattery, this, std::placeholders::_1, std::placeholders::_2), mHandle);
3217
#endif
3218
        }
195 andreas 3219
 
3220
        mSystemReg = true;
23 andreas 3221
    }
206 andreas 3222
    else if (lp == 0 && lv == SYSTEM_ITEM_CONNSTRENGTH)       // Network connection strength
36 andreas 3223
    {
3224
        if (gPageManager)
3225
            gPageManager->regCallbackNetState(bind(&TButton::funcNetworkState, this, std::placeholders::_1), mHandle);
195 andreas 3226
 
3227
        mSystemReg = true;
36 andreas 3228
    }
206 andreas 3229
    else if (lp == 0 && lv == SYSTEM_ITEM_SYSVOLUME)        // System volume
192 andreas 3230
    {
3231
        mLastLevel = TConfig::getSystemVolume();
3232
        mChanged = true;
195 andreas 3233
        mSystemReg = true;
192 andreas 3234
    }
195 andreas 3235
    else if (cp == 0 && type == GENERAL && ch > 0 && isSystemCheckBox(ch))
192 andreas 3236
    {
195 andreas 3237
        int inst = getButtonInstance(0, ch);
3238
 
3239
        if (inst >= 0)
3240
        {
3241
            mActInstance = inst;
3242
            mChanged = true;
3243
            mSystemReg = true;
3244
        }
192 andreas 3245
    }
195 andreas 3246
    else if (ap == 0 && ad > 0 && isSystemTextLine(ad))
192 andreas 3247
    {
195 andreas 3248
        sr[0].te = sr[1].te = fillButtonText(ad, 0);
185 andreas 3249
        mChanged = true;
195 andreas 3250
        mSystemReg = true;
185 andreas 3251
    }
15 andreas 3252
}
3253
 
3254
void TButton::addPushFunction(string& func, string& page)
3255
{
3256
    DECL_TRACER("TButton::addPushFunction(string& func, string& page)");
3257
 
3258
    vector<string> allFunc = { "Stan", "Prev", "Show", "Hide", "Togg", "ClearG", "ClearP", "ClearA" };
3259
    vector<string>::iterator iter;
3260
 
3261
    for (iter = allFunc.begin(); iter != allFunc.end(); ++iter)
3262
    {
162 andreas 3263
        if (strCaseCompare(*iter, func) == 0)
15 andreas 3264
        {
3265
            bool found = false;
3266
            vector<PUSH_FUNC_T>::iterator iterPf;
3267
 
162 andreas 3268
            if (pushFunc.size() > 0)
15 andreas 3269
            {
162 andreas 3270
                for (iterPf = pushFunc.begin(); iterPf != pushFunc.end(); ++iterPf)
15 andreas 3271
                {
162 andreas 3272
                    if (strCaseCompare(iterPf->pfType, func) == 0)
3273
                    {
3274
                        iterPf->pfName = page;
3275
                        found = true;
3276
                        break;
3277
                    }
15 andreas 3278
                }
3279
            }
3280
 
3281
            if (!found)
3282
            {
3283
                PUSH_FUNC_T pf;
3284
                pf.pfType = func;
3285
                pf.pfName = page;
3286
                pushFunc.push_back(pf);
3287
            }
108 andreas 3288
 
3289
            break;
15 andreas 3290
        }
3291
    }
3292
}
3293
 
16 andreas 3294
void TButton::clearPushFunction(const string& action)
3295
{
3296
    DECL_TRACER("TButton::clearPushFunction(const string& action)");
3297
 
3298
    if (pushFunc.empty())
3299
        return;
3300
 
3301
    vector<PUSH_FUNC_T>::iterator iter;
3302
 
118 andreas 3303
    for (iter = pushFunc.begin(); iter != pushFunc.end(); ++iter)
16 andreas 3304
    {
162 andreas 3305
        if (strCaseCompare(iter->pfName, action) == 0)
16 andreas 3306
        {
3307
            pushFunc.erase(iter);
3308
            return;
3309
        }
3310
    }
3311
}
3312
 
8 andreas 3313
void TButton::getDrawOrder(const std::string& sdo, DRAW_ORDER *order)
4 andreas 3314
{
8 andreas 3315
    DECL_TRACER("TButton::getDrawOrder(const std::string& sdo, DRAW_ORDER *order)");
4 andreas 3316
 
8 andreas 3317
    if (!order)
3318
        return;
3319
 
3320
    if (sdo.empty() || sdo.length() != 10)
4 andreas 3321
    {
8 andreas 3322
        *order     = ORD_ELEM_FILL;
3323
        *(order+1) = ORD_ELEM_BITMAP;
3324
        *(order+2) = ORD_ELEM_ICON;
3325
        *(order+3) = ORD_ELEM_TEXT;
3326
        *(order+4) = ORD_ELEM_BORDER;
3327
        return;
3328
    }
3329
 
289 andreas 3330
    int elems = (int)(sdo.length() / 2);
8 andreas 3331
 
3332
    for (int i = 0; i < elems; i++)
3333
    {
3334
        int e = atoi(sdo.substr(i * 2, 2).c_str());
3335
 
3336
        if (e < 1 || e > 5)
3337
        {
3338
            MSG_ERROR("Invalid draw order \"" << sdo << "\"!");
3339
            TError::setError();
3340
            return;
3341
        }
3342
 
3343
        *(order+i) = (DRAW_ORDER)e;
3344
    }
3345
}
3346
 
3347
bool TButton::buttonFill(SkBitmap* bm, int instance)
3348
{
3349
    DECL_TRACER("TButton::buttonFill(SkBitmap* bm, int instance)");
3350
 
3351
    if (!bm)
3352
    {
3353
        MSG_ERROR("Invalid bitmap!");
4 andreas 3354
        return false;
3355
    }
3356
 
165 andreas 3357
    if (instance < 0 || (size_t)instance >= sr.size())
3358
    {
3359
        MSG_ERROR("Invalid instance " << instance);
3360
        return false;
3361
    }
3362
 
8 andreas 3363
    SkColor color = TColor::getSkiaColor(sr[instance].cf);
306 andreas 3364
    MSG_DEBUG("Fill color[" << instance << "]: " << sr[instance].cf << " (#" << std::setw(8) << std::setfill('0') << std::hex << color << ")" << std::dec << std::setfill(' ') << std::setw(1));
292 andreas 3365
    // We create a new bitmap and fill it with the given fill color. Then
3366
    // we put this image over the existing image "bm". In case this method is
3367
    // not the first in the draw order, it prevents the button from completely
3368
    // overwrite.
3369
    SkImageInfo info = bm->info();
3370
    SkBitmap bitmap;
3371
 
3372
    if (!allocPixels(info.width(), info.height(), &bitmap))
3373
    {
3374
        MSG_ERROR("Error allocating a bitmap with size " << info.width() << " x " << info.height() << "!");
3375
        return false;
3376
    }
3377
 
3378
    bitmap.eraseColor(color);                       // Fill the new bitmap with the fill color
3379
    SkCanvas ctx(*bm, SkSurfaceProps());            // Create a canvas
3380
    SkPaint paint;                                  // The paint "device"
3381
    paint.setBlendMode(SkBlendMode::kSrcOver);      // We're overwriting each pixel
3382
    sk_sp<SkImage> _image = SkImage::MakeFromBitmap(bitmap);    // Technically we need an image. So we convert our new bitmap into an image.
3383
    ctx.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);   // Now we put the new image over the existing one.
8 andreas 3384
    return true;
3385
}
3386
 
46 andreas 3387
bool TButton::buttonBitmap(SkBitmap* bm, int inst)
8 andreas 3388
{
3389
    DECL_TRACER("TButton::buttonBitmap(SkBitmap* bm, int instane)");
3390
 
240 andreas 3391
    if (prg_stopped || !bm)
33 andreas 3392
        return false;
35 andreas 3393
 
46 andreas 3394
    int instance = inst;
3395
 
3396
    if (inst < 0)
3397
        instance = 0;
3398
    else if ((size_t)inst >= sr.size())
289 andreas 3399
        instance = (int)(sr.size() - 1);
46 andreas 3400
 
184 andreas 3401
    /*
3402
     * Here we test if we have a cameleon image. If there is a mask (sr[].mi)
3403
     * and no frame (sr[].bs) then we have a cameleon image. A bitmap is
3404
     * optional. If there is one it will be used to draw with the mask.
3405
     * Otherwise the mask may be used as an overlay for a bitmap on another
3406
     * button below the mask.
3407
     */
29 andreas 3408
    if (!sr[instance].mi.empty() && sr[instance].bs.empty())       // Chameleon image?
4 andreas 3409
    {
184 andreas 3410
        MSG_DEBUG("Chameleon image consisting of mask " << sr[instance].mi << " and bitmap " << (sr[instance].bm.empty() ? "NONE" : sr[instance].bm) << " ...");
69 andreas 3411
 
165 andreas 3412
        SkBitmap bmMi;
3413
        SkBitmap bmBm;
3414
 
167 andreas 3415
        if (!TImgCache::getBitmap(sr[instance].mi, &bmMi, _BMTYPE_CHAMELEON, &sr[instance].mi_width, &sr[instance].mi_height))
69 andreas 3416
        {
165 andreas 3417
            sk_sp<SkData> data = readImage(sr[instance].mi);
3418
            bool loaded = false;
3419
 
3420
            if (data)
3421
            {
3422
                DecodeDataToBitmap(data, &bmMi);
3423
 
3424
                if (!bmMi.empty())
3425
                {
3426
                    TImgCache::addImage(sr[instance].mi, bmMi, _BMTYPE_CHAMELEON);
3427
                    loaded = true;
3428
                    sr[instance].mi_width = bmMi.info().width();
3429
                    sr[instance].mi_height = bmMi.info().height();
3430
                }
3431
            }
3432
 
3433
            if(!loaded)
3434
            {
3435
                MSG_ERROR("Missing image " << sr[instance].mi << "!");
3436
                TError::setError();
3437
                return false;
3438
            }
69 andreas 3439
        }
3440
 
240 andreas 3441
        MSG_DEBUG("Chameleon image size: " << bmMi.info().width() << " x " << bmMi.info().height());
165 andreas 3442
        SkBitmap imgRed(bmMi);
24 andreas 3443
        SkBitmap imgMask;
163 andreas 3444
        bool haveBothImages = true;
4 andreas 3445
 
24 andreas 3446
        if (!sr[instance].bm.empty())
163 andreas 3447
        {
167 andreas 3448
            if (!TImgCache::getBitmap(sr[instance].bm, &bmBm, _BMTYPE_BITMAP, &sr[instance].bm_width, &sr[instance].bm_height))
163 andreas 3449
            {
165 andreas 3450
                sk_sp<SkData> data = readImage(sr[instance].bm);
3451
                bool loaded = false;
3452
 
3453
                if (data)
3454
                {
3455
                    DecodeDataToBitmap(data, &bmBm);
3456
 
3457
                    if (!bmMi.empty())
3458
                    {
3459
                        TImgCache::addImage(sr[instance].bm, bmMi, _BMTYPE_BITMAP);
3460
                        loaded = true;
3461
                        sr[instance].bm_width = bmBm.info().width();
3462
                        sr[instance].bm_height = bmBm.info().height();
3463
                    }
3464
                }
3465
 
3466
                if (!loaded)
3467
                {
3468
                    MSG_ERROR("Missing image " << sr[instance].bm << "!");
3469
                    TError::setError();
3470
                    return false;
3471
                }
163 andreas 3472
            }
165 andreas 3473
 
184 andreas 3474
            if (!bmBm.empty())
240 andreas 3475
            {
3476
                if (!imgMask.installPixels(bmBm.pixmap()))
3477
                {
3478
                    MSG_ERROR("Error installing pixmap " << sr[instance].bm << " for chameleon image!");
254 andreas 3479
 
3480
                    if (!allocPixels(imgRed.info().width(), imgRed.info().height(), &imgMask))
3481
                        return false;
3482
 
240 andreas 3483
                    imgMask.eraseColor(SK_ColorTRANSPARENT);
3484
                    haveBothImages = false;
3485
                }
3486
            }
163 andreas 3487
            else
3488
            {
184 andreas 3489
                MSG_WARNING("No or invalid bitmap! Ignoring bitmap for cameleon image.");
254 andreas 3490
 
3491
                if (!allocPixels(imgRed.info().width(), imgRed.info().height(), &imgMask))
3492
                    return false;
3493
 
163 andreas 3494
                imgMask.eraseColor(SK_ColorTRANSPARENT);
3495
                haveBothImages = false;
3496
            }
3497
        }
3498
        else
3499
            haveBothImages = false;
24 andreas 3500
 
240 andreas 3501
        MSG_DEBUG("Bitmap image size: " << bmBm.info().width() << " x " << bmBm.info().height());
3502
        MSG_DEBUG("Bitmap mask size: " << imgMask.info().width() << " x " << imgMask.info().height());
167 andreas 3503
        SkBitmap img = drawImageButton(imgRed, imgMask, sr[instance].mi_width, sr[instance].mi_height, TColor::getSkiaColor(sr[instance].cf), TColor::getSkiaColor(sr[instance].cb));
20 andreas 3504
 
3505
        if (img.empty())
4 andreas 3506
        {
20 andreas 3507
            MSG_ERROR("Error creating the cameleon image \"" << sr[instance].mi << "\" / \"" << sr[instance].bm << "\"!");
3508
            TError::setError();
3509
            return false;
3510
        }
4 andreas 3511
 
240 andreas 3512
        MSG_DEBUG("Have both images: " << (haveBothImages ? "YES" : "NO"));
254 andreas 3513
        SkCanvas ctx(img, SkSurfaceProps());
20 andreas 3514
        SkImageInfo info = img.info();
3515
        SkPaint paint;
24 andreas 3516
        paint.setBlendMode(SkBlendMode::kSrcOver);
179 andreas 3517
        sk_sp<SkImage> _image = SkImage::MakeFromBitmap(imgMask);
3518
        ctx.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
4 andreas 3519
 
20 andreas 3520
        POSITION_t position = calcImagePosition(sr[instance].mi_width, sr[instance].mi_height, SC_BITMAP, instance);
7 andreas 3521
 
20 andreas 3522
        if (!position.valid)
3523
        {
3524
            MSG_ERROR("Error calculating the position of the image for button number " << bi << ": " << na);
3525
            TError::setError();
3526
            return false;
4 andreas 3527
        }
10 andreas 3528
 
254 andreas 3529
        SkCanvas can(*bm, SkSurfaceProps());
20 andreas 3530
        paint.setBlendMode(SkBlendMode::kSrc);
21 andreas 3531
 
3532
        if (sr[instance].sb == 0)
163 andreas 3533
        {
3534
            if (!haveBothImages)
3535
            {
179 andreas 3536
                sk_sp<SkImage> _image = SkImage::MakeFromBitmap(img);
3537
                can.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
163 andreas 3538
 
3539
                if (!sr[instance].bm.empty())
3540
                {
165 andreas 3541
                    imgMask.installPixels(bmBm.pixmap());
163 andreas 3542
                    paint.setBlendMode(SkBlendMode::kSrcOver);
179 andreas 3543
                    _image = SkImage::MakeFromBitmap(imgMask);
3544
                    can.drawImage(_image, position.left, position.top, SkSamplingOptions(), &paint);
163 andreas 3545
                }
3546
            }
3547
            else
179 andreas 3548
            {
3549
                sk_sp<SkImage> _image = SkImage::MakeFromBitmap(img);
3550
                can.drawImage(_image, position.left, position.top, SkSamplingOptions(), &paint);
3551
            }
163 andreas 3552
        }
21 andreas 3553
        else    // Scale to fit
3554
        {
163 andreas 3555
            if (!haveBothImages)
3556
            {
3557
                SkRect rect;
3558
                rect.setXYWH(0, 0, imgRed.info().width(), imgRed.info().height());
3559
                sk_sp<SkImage> im = SkImage::MakeFromBitmap(img);
179 andreas 3560
                can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
163 andreas 3561
 
3562
                if (!sr[instance].bm.empty())
3563
                {
165 andreas 3564
                    imgMask.installPixels(bmBm.pixmap());
163 andreas 3565
                    rect.setXYWH(position.left, position.top, position.width, position.height);
3566
                    im = SkImage::MakeFromBitmap(imgMask);
3567
                    paint.setBlendMode(SkBlendMode::kSrcOver);
179 andreas 3568
                    can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
163 andreas 3569
                }
3570
            }
3571
            else
3572
            {
3573
                SkRect rect = SkRect::MakeXYWH(position.left, position.top, position.width, position.height);
3574
                sk_sp<SkImage> im = SkImage::MakeFromBitmap(img);
179 andreas 3575
                can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
163 andreas 3576
            }
21 andreas 3577
        }
4 andreas 3578
    }
3579
    else if (!sr[instance].bm.empty())
3580
    {
69 andreas 3581
        MSG_TRACE("Drawing normal image " << sr[instance].bm << " ...");
3582
 
165 andreas 3583
        SkBitmap image;
3584
 
167 andreas 3585
        if (!TImgCache::getBitmap(sr[instance].bm, &image, _BMTYPE_BITMAP, &sr[instance].bm_width, &sr[instance].bm_height))
69 andreas 3586
        {
165 andreas 3587
            sk_sp<SkData> data = readImage(sr[instance].bm);
3588
            bool loaded = false;
3589
 
3590
            if (data)
3591
            {
3592
                DecodeDataToBitmap(data, &image);
3593
 
3594
                if (!image.empty())
3595
                {
3596
                    TImgCache::addImage(sr[instance].mi, image, _BMTYPE_BITMAP);
3597
                    loaded = true;
3598
                    sr[instance].bm_width = image.info().width();
3599
                    sr[instance].bm_height = image.info().height();
3600
                }
3601
            }
3602
 
3603
            if (!loaded)
3604
            {
3605
                MSG_ERROR("Missing image " << sr[instance].bm << "!");
3606
                return true;        // We want the button even without an image
3607
            }
69 andreas 3608
        }
3609
 
6 andreas 3610
        if (image.empty())
4 andreas 3611
        {
3612
            MSG_ERROR("Error creating the image \"" << sr[instance].bm << "\"!");
3613
            TError::setError();
3614
            return false;
3615
        }
3616
 
99 andreas 3617
        IMAGE_SIZE_t isize = calcImageSize(image.info().width(), image.info().height(), instance, true);
3618
        POSITION_t position = calcImagePosition((sr[instance].sb ? isize.width : image.info().width()), (sr[instance].sb ? isize.height : image.info().height()), SC_BITMAP, instance);
4 andreas 3619
 
3620
        if (!position.valid)
3621
        {
3622
            MSG_ERROR("Error calculating the position of the image for button number " << bi);
3623
            TError::setError();
3624
            return false;
3625
        }
3626
 
10 andreas 3627
        MSG_DEBUG("Putting bitmap on top of image ...");
3628
        SkPaint paint;
69 andreas 3629
        paint.setBlendMode(SkBlendMode::kSrcOver);
254 andreas 3630
        SkCanvas can(*bm, SkSurfaceProps());
21 andreas 3631
 
69 andreas 3632
        if (sr[instance].sb == 0)   // Scale bitmap?
3633
        {                           // No, keep size
46 andreas 3634
            if ((sr[instance].jb == 0 && sr[instance].bx >= 0 && sr[instance].by >= 0) || sr[instance].jb != 0)  // Draw the full image
179 andreas 3635
            {
3636
                sk_sp<SkImage> _image = SkImage::MakeFromBitmap(image);
3637
                can.drawImage(_image, position.left, position.top, SkSamplingOptions(), &paint);
3638
            }
49 andreas 3639
            else    // We need only a subset of the image
46 andreas 3640
            {
3641
                MSG_DEBUG("Create a subset of an image ...");
3642
 
3643
                // Create a new Info to have the size of the subset.
3644
                SkImageInfo info = SkImageInfo::Make(position.width, position.height, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
3645
                size_t byteSize = info.computeMinByteSize();
3646
 
3647
                if (byteSize == 0)
3648
                {
3649
                    MSG_ERROR("Unable to calculate size of image!");
3650
                    TError::setError();
3651
                    return false;
3652
                }
3653
 
3654
                MSG_DEBUG("Rectangle of part: x: " << position.left << ", y: " << position.top << ", w: " << position.width << ", h: " << position.height);
3655
                SkBitmap part;      // Bitmap receiving the wanted part from the whole image
3656
                SkIRect irect = SkIRect::MakeXYWH(position.left, position.top, position.width, position.height);
3657
                image.extractSubset(&part, irect);  // Extract the part of the image containg the pixels we want
179 andreas 3658
                sk_sp<SkImage> _image = SkImage::MakeFromBitmap(part);
3659
                can.drawImage(_image, 0, 0, SkSamplingOptions(), &paint); // Draw the image
46 andreas 3660
            }
3661
        }
21 andreas 3662
        else    // Scale to fit
3663
        {
99 andreas 3664
            SkRect rect = SkRect::MakeXYWH(position.left, position.top, isize.width, isize.height);
21 andreas 3665
            sk_sp<SkImage> im = SkImage::MakeFromBitmap(image);
179 andreas 3666
            can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
21 andreas 3667
        }
6 andreas 3668
    }
8 andreas 3669
    else
6 andreas 3670
    {
8 andreas 3671
        MSG_DEBUG("No bitmap defined.");
3672
    }
4 andreas 3673
 
8 andreas 3674
    return true;
3675
}
4 andreas 3676
 
97 andreas 3677
bool TButton::buttonDynamic(SkBitmap* bm, int instance, bool show, bool *state)
21 andreas 3678
{
97 andreas 3679
    DECL_TRACER("TButton::buttonDynamic(SkBitmap* bm, int instance, bool show, bool *state)");
21 andreas 3680
 
33 andreas 3681
    if (prg_stopped)
3682
        return false;
35 andreas 3683
 
21 andreas 3684
    if (!gPrjResources)
3685
    {
3686
        MSG_ERROR("Internal error: Global resource class not initialized!");
3687
        return false;
3688
    }
3689
 
165 andreas 3690
    if (instance < 0 || (size_t)instance >= sr.size())
3691
    {
3692
        MSG_ERROR("Invalid instance " << instance);
3693
        return false;
3694
    }
3695
 
21 andreas 3696
    if (!sr[instance].dynamic)
3697
    {
3698
        MSG_WARNING("Button " << bi << ": \"" << na << "\" is not for remote image!");
3699
        return false;
3700
    }
3701
 
98 andreas 3702
    if (!visible)
99 andreas 3703
    {
271 andreas 3704
        MSG_DEBUG("Dynamic button " << handleToString(mHandle) << " is invisible. Will not draw it.");
98 andreas 3705
        return true;
99 andreas 3706
    }
98 andreas 3707
 
271 andreas 3708
    MSG_DEBUG("Dynamic button " << handleToString(mHandle) << " will be drawn ...");
97 andreas 3709
    size_t idx = 0;
21 andreas 3710
 
97 andreas 3711
    if ((idx = gPrjResources->getResourceIndex("image")) == TPrjResources::npos)
3712
    {
3713
        MSG_ERROR("There exists no image resource!");
3714
        return false;
3715
    }
3716
 
289 andreas 3717
    RESOURCE_T resource = gPrjResources->findResource((int)idx, sr[instance].bm);
97 andreas 3718
 
21 andreas 3719
    if (resource.protocol.empty())
3720
    {
100 andreas 3721
        MSG_WARNING("Resource " << sr[instance].bm << " not found!");
3722
        return true;
21 andreas 3723
    }
3724
 
3725
    string path = resource.path;
3726
 
3727
    if (!resource.file.empty())
3728
        path += "/" + resource.file;
3729
 
94 andreas 3730
    string url = THTTPClient::makeURLs(toLower(resource.protocol), resource.host, 0, path);
21 andreas 3731
 
97 andreas 3732
    if (url.empty())
3733
    {
100 andreas 3734
        MSG_DEBUG("No URL, no bitmap!");
97 andreas 3735
        return true;    // We have no image but the button still exists
3736
    }
3737
 
3738
    SkBitmap image;
3739
 
165 andreas 3740
    if (TImgCache::getBitmap(url, &image, _BMTYPE_URL))
97 andreas 3741
    {
100 andreas 3742
        MSG_DEBUG("Found image \"" << url << "\" in the cache. Will reuse it.");
99 andreas 3743
        IMAGE_SIZE_t isize = calcImageSize(image.info().width(), image.info().height(), instance, true);
3744
        POSITION_t position = calcImagePosition((sr[instance].sb ? isize.width : image.info().width()), (sr[instance].sb ? isize.height : image.info().height()), SC_BITMAP, instance);
97 andreas 3745
 
3746
        if (!position.valid)
3747
        {
3748
            MSG_ERROR("Error calculating the position of the image for button number " << bi);
3749
            TError::setError();
3750
            return false;
3751
        }
3752
 
3753
        SkPaint paint;
3754
        paint.setBlendMode(SkBlendMode::kSrcOver);
254 andreas 3755
        SkCanvas can(*bm, SkSurfaceProps());
97 andreas 3756
 
3757
        if (sr[instance].sb == 0)   // Scale bitmap?
3758
        {                           // No, keep size
3759
            if ((sr[instance].jb == 0 && sr[instance].bx >= 0 && sr[instance].by >= 0) || sr[instance].jb != 0)  // Draw the full image
179 andreas 3760
            {
3761
                sk_sp<SkImage> _image = SkImage::MakeFromBitmap(image);
3762
                can.drawImage(_image, position.left, position.top, SkSamplingOptions(), &paint);
3763
            }
97 andreas 3764
            else    // We need only a subset of the image
3765
            {
3766
                MSG_DEBUG("Create a subset of an image ...");
3767
 
3768
                // Create a new Info to have the size of the subset.
3769
                SkImageInfo info = SkImageInfo::Make(position.width, position.height, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
3770
                size_t byteSize = info.computeMinByteSize();
3771
 
3772
                if (byteSize == 0)
3773
                {
3774
                    MSG_ERROR("Unable to calculate size of image!");
3775
                    TError::setError();
3776
                    return false;
3777
                }
3778
 
3779
                MSG_DEBUG("Rectangle of part: x: " << position.left << ", y: " << position.top << ", w: " << position.width << ", h: " << position.height);
3780
                SkBitmap part;      // Bitmap receiving the wanted part from the whole image
3781
                SkIRect irect = SkIRect::MakeXYWH(position.left, position.top, position.width, position.height);
3782
                image.extractSubset(&part, irect);  // Extract the part of the image containg the pixels we want
179 andreas 3783
                sk_sp<SkImage> _image = SkImage::MakeFromBitmap(part);
3784
                can.drawImage(_image, 0, 0, SkSamplingOptions(), &paint); // Draw the image
97 andreas 3785
            }
3786
        }
3787
        else    // Scale to fit
3788
        {
99 andreas 3789
            SkRect rect = SkRect::MakeXYWH(position.left, position.top, isize.width, isize.height);
97 andreas 3790
            sk_sp<SkImage> im = SkImage::MakeFromBitmap(image);
179 andreas 3791
            can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
97 andreas 3792
        }
3793
 
3794
        return true;
3795
    }
3796
 
21 andreas 3797
    try
3798
    {
94 andreas 3799
        // First me must add the credential for the image into a bitmap cache element
3800
        BITMAP_CACHE bc;
3801
        bc.top = tp;
3802
        bc.left = lt;
3803
        bc.width = wt;
3804
        bc.height = ht;
3805
        bc.bi = bi;
97 andreas 3806
        bc.show = show;
94 andreas 3807
        bc.handle = getHandle();
3808
        bc.parent = getParent();
3809
        bc.bitmap = *bm;
3810
        addToBitmapCache(bc);
97 andreas 3811
 
3812
        if (state)
3813
            *state = true;  // Prevent the calling method from displaying the button
3814
 
21 andreas 3815
        MSG_TRACE("Starting thread for loading a dynamic image ...");
94 andreas 3816
        mThrRes = std::thread([=] { this->funcResource(&resource, url, bc, instance); });
21 andreas 3817
        MSG_TRACE("Thread started. Detaching ...");
3818
        mThrRes.detach();
3819
        MSG_TRACE("Thread is running and detached.");
3820
    }
3821
    catch (std::exception& e)
3822
    {
28 andreas 3823
        MSG_ERROR("Error starting the resource thread: " << e.what());
21 andreas 3824
    }
3825
 
3826
    return true;
3827
}
3828
 
99 andreas 3829
/*
3830
 * Draws the elements of a button starting at the point where the bitmap was
3831
 * already drawed. Everything coming afterwards acording to the draw order
3832
 * is drawed in the desired order.
3833
 * This method is called out of a thread to draw a button with an external
3834
 * image coming from a WEB server.
3835
 */
3836
bool TButton::drawAlongOrder(SkBitmap *imgButton, int instance)
3837
{
3838
    DECL_TRACER("TButton::drawAlongOrder(SkBitmap *imgButton, int instance)");
3839
 
165 andreas 3840
    if (instance < 0 || (size_t)instance >= sr.size())
3841
    {
3842
        MSG_ERROR("Invalid instance " << instance);
3843
        return false;
3844
    }
3845
 
99 andreas 3846
    bool cont = false;
3847
 
3848
    for (int i = 0; i < ORD_ELEM_COUNT; i++)
3849
    {
3850
        if (!cont && mDOrder[i] == ORD_ELEM_BITMAP)
3851
        {
3852
            cont = true;
3853
            continue;
3854
        }
100 andreas 3855
        else if (!cont)
3856
            continue;
99 andreas 3857
 
3858
        if (mDOrder[i] == ORD_ELEM_FILL)
3859
        {
3860
            if (!buttonFill(imgButton, instance))
3861
            {
3862
                mutex_button.unlock();
3863
                return false;
3864
            }
3865
        }
3866
        else if (mDOrder[i] == ORD_ELEM_ICON)
3867
        {
3868
            if (!buttonIcon(imgButton, instance))
3869
            {
3870
                mutex_button.unlock();
3871
                return false;
3872
            }
3873
        }
3874
        else if (mDOrder[i] == ORD_ELEM_TEXT)
3875
        {
3876
            if (!buttonText(imgButton, instance))
3877
            {
3878
                mutex_button.unlock();
3879
                return false;
3880
            }
3881
        }
3882
        else if (mDOrder[i] == ORD_ELEM_BORDER)
3883
        {
3884
            if (!buttonBorder(imgButton, instance))
3885
            {
3886
                mutex_button.unlock();
3887
                return false;
3888
            }
3889
        }
3890
    }
3891
 
3892
    return true;
3893
}
3894
 
94 andreas 3895
void TButton::funcResource(const RESOURCE_T* resource, const std::string& url, BITMAP_CACHE bc, int instance)
21 andreas 3896
{
3897
    DECL_TRACER("TButton::funcResource(RESOURCE_T* resource, std::string& url, SkBitmap* bm, int instance)");
3898
 
97 andreas 3899
    if (prg_stopped || killed || _restart_ || !resource)
35 andreas 3900
        return;
3901
 
21 andreas 3902
    if (resource->refresh > 0 && !resource->dynamo)      // Periodically refreshing image?
3903
    {
3904
        MSG_DEBUG("Retrieving periodicaly refreshed image");
3905
 
97 andreas 3906
        if (!bc.handle || !bc.parent || bc.bi <= 1)
21 andreas 3907
        {
3908
            MSG_ERROR("Invalid button. Can't make a dynamo image!");
3909
            return;
3910
        }
3911
 
97 andreas 3912
        THR_REFRESH_t *thref = _findResource(bc.handle, bc.parent, bc.bi);
21 andreas 3913
        TImageRefresh *mImageRefresh = nullptr;
3914
 
3915
        if (!thref)
3916
        {
3917
            MSG_DEBUG("Creating a new refresh thread");
3918
            mImageRefresh = new TImageRefresh();
3919
            mImageRefresh->registerCallback(bind(&TButton::_imageRefresh, this, std::placeholders::_1));
3920
            mImageRefresh->setInterval(std::chrono::seconds(resource->refresh));
3921
            mImageRefresh->setUsername(resource->user);
3922
            mImageRefresh->setPassword(resource->password);
3923
 
3924
            if (resource->preserve)
3925
                mImageRefresh->setRunOnce();
3926
 
97 andreas 3927
            _addResource(mImageRefresh, bc.handle, bc.parent, bc.bi);
21 andreas 3928
        }
3929
        else
3930
        {
3931
            mImageRefresh = thref->mImageRefresh;
3932
 
3933
            if (!mImageRefresh)
3934
            {
3935
                MSG_ERROR("Error creating a new refresh class!");
3936
                return;
3937
            }
3938
 
3939
            mImageRefresh->setInterval(std::chrono::seconds(resource->refresh));
3940
            mImageRefresh->setUsername(resource->user);
3941
            mImageRefresh->setPassword(resource->password);
3942
 
3943
            if (resource->preserve)
3944
                mImageRefresh->setRunOnce();
3945
        }
3946
 
97 andreas 3947
        if (mImageRefresh->isRunning())
3948
            mImageRefresh->stopWait();
3949
 
3950
        if (!mImageRefresh->isRunning() && !_restart_)
21 andreas 3951
        {
3952
            MSG_DEBUG("Starting a refresh thread.");
3953
            mImageRefresh->run(url);
3954
        }
3955
    }
3956
    else if (resource->refresh == 0 && !resource->dynamo)
3957
    {
3958
        MSG_DEBUG("Retrieving single image");
3959
 
94 andreas 3960
        if (bc.handle == 0)
3961
        {
3962
            MSG_ERROR("Invalid bitmap cache!");
3963
            return;
3964
        }
3965
 
165 andreas 3966
        if (instance < 0 || (size_t)instance >= sr.size())
3967
        {
3968
            MSG_ERROR("Invalid instance " << instance);
3969
            return;
3970
        }
3971
 
97 andreas 3972
        // Check whether we have this image already
3973
        SkBitmap bitm;
3974
        bool cached = false;
3975
 
165 andreas 3976
        cached = TImgCache::getBitmap(url, &bitm, _BMTYPE_URL);
94 andreas 3977
        BITMAP_CACHE bmCache = getBCentryByHandle(bc.handle, bc.parent);
3978
 
97 andreas 3979
        if (!cached)    // If the bitmap was not in cache we must load it
94 andreas 3980
        {
97 andreas 3981
            MSG_DEBUG("Image not in cache. Downloading it ...");
3982
            THTTPClient *WEBClient = nullptr;
94 andreas 3983
 
97 andreas 3984
            if (bmCache.handle == 0)
3985
            {
271 andreas 3986
                MSG_ERROR("Couldn't find the handle " << handleToString(bc.handle) << " in bitmap cache!");
97 andreas 3987
                return;
3988
            }
3989
 
21 andreas 3990
            char *content = nullptr;
3991
            size_t length = 0, contentlen = 0;
94 andreas 3992
            WEBClient = new THTTPClient;
21 andreas 3993
 
94 andreas 3994
            if (!WEBClient || (content = WEBClient->tcall(&length, url, resource->user, resource->password)) == nullptr)
97 andreas 3995
            {
3996
                if (WEBClient)
3997
                    delete WEBClient;
3998
 
3999
                if (bc.show)
4000
                {
4001
                    setReady(bmCache.handle);
4002
                    showBitmapCache();
4003
                }
4004
                else
4005
                    setInvalid(bc.handle);
4006
 
21 andreas 4007
                return;
97 andreas 4008
            }
21 andreas 4009
 
94 andreas 4010
            contentlen = WEBClient->getContentSize();
21 andreas 4011
            MSG_DEBUG("Loaded " << contentlen << " bytes:");
4012
            sk_sp<SkData> data = SkData::MakeWithCopy(content, contentlen);
4013
 
97 andreas 4014
            if (!data || _restart_)
21 andreas 4015
            {
94 andreas 4016
                delete WEBClient;
21 andreas 4017
                MSG_ERROR("Error making image data!");
97 andreas 4018
 
4019
                if (bc.show)
4020
                {
4021
                    setReady(bmCache.handle);
4022
                    showBitmapCache();
4023
                }
4024
                else
4025
                    setInvalid(bc.handle);
4026
 
21 andreas 4027
                return;
4028
            }
4029
 
4030
            SkBitmap image;
4031
 
4032
            if (!DecodeDataToBitmap(data, &image))
4033
            {
97 andreas 4034
                delete WEBClient;
21 andreas 4035
                MSG_ERROR("Error creating an image!");
97 andreas 4036
 
4037
                if (bc.show)
4038
                {
4039
                    setReady(bmCache.handle);
4040
                    showBitmapCache();
4041
                }
4042
                else
4043
                    setInvalid(bc.handle);
4044
 
21 andreas 4045
                return;
4046
            }
4047
 
97 andreas 4048
            // Put this image into the static image cache
165 andreas 4049
            TImgCache::addImage(url, image, _BMTYPE_URL);
97 andreas 4050
            // Make the button complete
94 andreas 4051
            loadImage(&bmCache.bitmap, image, instance);
99 andreas 4052
            drawAlongOrder(&bmCache.bitmap, instance);
94 andreas 4053
            setBCBitmap(bmCache.handle, bmCache.bitmap);
4054
            setReady(bmCache.handle);
4055
            delete WEBClient;
97 andreas 4056
            // Display the image
94 andreas 4057
            showBitmapCache();
21 andreas 4058
            return;
4059
        }
97 andreas 4060
        else
21 andreas 4061
        {
97 andreas 4062
            MSG_DEBUG("Found image in cache. Using it ...");
165 andreas 4063
 
4064
            if (instance < 0 || (size_t)instance >= sr.size())
4065
            {
4066
                MSG_ERROR("Invalid instance " << instance);
4067
                return;
4068
            }
4069
 
97 andreas 4070
            loadImage(&bmCache.bitmap, bitm, instance);
4071
            setInvalid(bc.handle);
94 andreas 4072
 
97 andreas 4073
            if (bc.show && _displayButton)
176 andreas 4074
            {
289 andreas 4075
                TBitmap image((unsigned char *)bmCache.bitmap.getPixels(), bmCache.bitmap.info().width(), bmCache.bitmap.info().height());
298 andreas 4076
                _displayButton(bc.handle, bc.parent, image, bc.width, bc.height, bc.left, bc.top, isPassThrough());
176 andreas 4077
                mChanged = false;
4078
            }
21 andreas 4079
        }
4080
    }
97 andreas 4081
    else if (!_restart_)
21 andreas 4082
    {
4083
        MSG_DEBUG("Retrieving a video");
4084
 
4085
        if (_playVideo && !prg_stopped)
4086
        {
4087
            ulong parent = (mHandle >> 16) & 0x0000ffff;
4088
            _playVideo(mHandle, parent, lt, tp, wt, ht, url, resource->user, resource->password);
4089
        }
4090
    }
4091
}
247 andreas 4092
#ifdef Q_OS_ANDROID
38 andreas 4093
void TButton::funcBattery(int level, bool charging, int /* chargeType */)
23 andreas 4094
{
38 andreas 4095
    DECL_TRACER("TButton::funcBattery(int level, bool charging, int chargeType)");
59 andreas 4096
 
23 andreas 4097
    // Battery level is always a bargraph
249 andreas 4098
    if (ap == 0 && ad == SYSTEM_ITEM_BATTERYLEVEL)       // Not charging
23 andreas 4099
    {
38 andreas 4100
        mEnabled = !charging;
177 andreas 4101
        mChanged = true;
23 andreas 4102
 
4103
        if (!mEnabled && visible)
4104
            hide(true);
4105
        else if (mEnabled)
4106
        {
4107
            visible = true;
38 andreas 4108
            drawBargraph(mActInstance, level, visible);
23 andreas 4109
        }
4110
    }
249 andreas 4111
    else if (ap == 0 && ad == SYSTEM_ITEM_BATTERYCHARGING)  // Charging
23 andreas 4112
    {
38 andreas 4113
        mEnabled = charging;
177 andreas 4114
        mChanged = true;
23 andreas 4115
 
4116
        if (!mEnabled && visible)
4117
            hide(true);
4118
        else if (mEnabled)
4119
        {
4120
            visible = true;
38 andreas 4121
            drawBargraph(mActInstance, level, visible);
23 andreas 4122
        }
4123
    }
4124
}
247 andreas 4125
#endif
4126
#ifdef Q_OS_IOS
4127
void TButton::funcBattery(int level, int state)
4128
{
4129
    DECL_TRACER("TButton::funcBattery(int level, bool charging, int chargeType)");
23 andreas 4130
 
247 andreas 4131
    // Battery level is always a bargraph
249 andreas 4132
    if (ap == 0 && ad == SYSTEM_ITEM_BATTERYLEVEL)       // Not charging
247 andreas 4133
    {
249 andreas 4134
        mEnabled = (state == 1 || state == 3);
247 andreas 4135
        mChanged = true;
4136
 
4137
        if (!mEnabled && visible)
4138
            hide(true);
4139
        else if (mEnabled)
4140
        {
4141
            visible = true;
4142
            drawBargraph(mActInstance, level, visible);
4143
        }
4144
    }
249 andreas 4145
    else if (ap == 0 && ad == SYSTEM_ITEM_BATTERYCHARGING)  // Charging
247 andreas 4146
    {
4147
        mEnabled = (state == 2);
4148
        mChanged = true;
4149
 
4150
        if (!mEnabled && visible)
4151
            hide(true);
4152
        else if (mEnabled)
4153
        {
4154
            visible = true;
4155
            drawBargraph(mActInstance, level, visible);
4156
        }
4157
    }
4158
}
4159
#endif
36 andreas 4160
void TButton::funcNetworkState(int level)
4161
{
4162
    DECL_TRACER("TButton::funcNetworkState(int level)");
4163
 
38 andreas 4164
    if (level >= rl && level <= rh)
4165
    {
4166
        mLastLevel = level;
177 andreas 4167
        mChanged = true;
38 andreas 4168
        drawMultistateBargraph(mLastLevel);
4169
    }
36 andreas 4170
}
4171
 
21 andreas 4172
bool TButton::loadImage(SkBitmap* bm, SkBitmap& image, int instance)
4173
{
4174
    DECL_TRACER("TButton::loadImage(SkBitmap* bm, SkBitmap& image, int instance)");
4175
 
94 andreas 4176
    if (!bm)
4177
    {
4178
        MSG_WARNING("Got no image to load!");
4179
        return false;
4180
    }
4181
 
165 andreas 4182
    if (instance < 0 || (size_t)instance >= sr.size())
4183
    {
4184
        MSG_ERROR("Invalid instance " << instance);
4185
        return false;
4186
    }
4187
 
21 andreas 4188
    SkImageInfo info = image.info();
99 andreas 4189
    IMAGE_SIZE_t isize = calcImageSize(image.info().width(), image.info().height(), instance, true);
4190
    POSITION_t position = calcImagePosition((sr[instance].sb ? isize.width : info.width()), (sr[instance].sb ? isize.height : info.height()), SC_BITMAP, instance);
4191
//    POSITION_t position = calcImagePosition(info.width(), info.height(), SC_BITMAP, instance);
21 andreas 4192
 
4193
    if (!position.valid)
4194
    {
4195
        MSG_ERROR("Error calculating the position of the image for button number " << bi);
4196
        return false;
4197
    }
4198
 
94 andreas 4199
    MSG_DEBUG("New image position: left=" << position.left << ", top=" << position.top << ", width=" << position.width << ", height=" << position.height);
4200
    MSG_DEBUG("Image size : width=" << info.width() << ", height=" << info.height());
4201
    MSG_DEBUG("Bitmap size: width=" << bm->info().width() << ", height=" << bm->info().height());
21 andreas 4202
    MSG_DEBUG("Putting bitmap on top of image ...");
4203
    SkPaint paint;
4204
    paint.setBlendMode(SkBlendMode::kSrc);
4205
 
254 andreas 4206
    SkCanvas can(*bm, SkSurfaceProps());
21 andreas 4207
 
4208
    if (sr[instance].sb == 0)
179 andreas 4209
    {
4210
        sk_sp<SkImage> _image = SkImage::MakeFromBitmap(image);
4211
        can.drawImage(_image, position.left, position.top, SkSamplingOptions(), &paint);
4212
    }
21 andreas 4213
    else    // Scale to fit
4214
    {
179 andreas 4215
//        paint.setFilterQuality(kHigh_SkFilterQuality);
99 andreas 4216
        SkRect rect = SkRect::MakeXYWH(position.left, position.top, isize.width, isize.height);
21 andreas 4217
        sk_sp<SkImage> im = SkImage::MakeFromBitmap(image);
179 andreas 4218
        can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
21 andreas 4219
    }
4220
 
4221
    return true;
4222
}
4223
 
111 andreas 4224
bool TButton::barLevel(SkBitmap* bm, int, int level)
15 andreas 4225
{
100 andreas 4226
    DECL_TRACER("TButton::barLevel(SkBitmap* bm, int inst, int level)");
15 andreas 4227
 
30 andreas 4228
    if (!sr[0].mi.empty()  && sr[0].bs.empty() && !sr[1].bm.empty())       // Chameleon image?
15 andreas 4229
    {
38 andreas 4230
        MSG_TRACE("Chameleon image ...");
165 andreas 4231
        SkBitmap bmMi, bmBm;
15 andreas 4232
 
167 andreas 4233
        TImgCache::getBitmap(sr[0].mi, &bmMi, _BMTYPE_CHAMELEON, &sr[0].mi_width, &sr[0].mi_height);
4234
        TImgCache::getBitmap(sr[1].bm, &bmBm, _BMTYPE_BITMAP, &sr[1].bm_width, &sr[1].bm_height);
165 andreas 4235
        SkBitmap imgRed(bmMi);
4236
        SkBitmap imgMask(bmBm);
4237
 
20 andreas 4238
        SkBitmap img;
4239
        SkPixmap pixmapRed = imgRed.pixmap();
4240
        SkPixmap pixmapMask;
15 andreas 4241
 
20 andreas 4242
        if (!imgMask.empty())
4243
            pixmapMask = imgMask.pixmap();
15 andreas 4244
 
20 andreas 4245
        int width = sr[0].mi_width;
4246
        int height = sr[0].mi_height;
4247
        int startX = 0;
4248
        int startY = 0;
100 andreas 4249
        // Calculation: width / <effective pixels> * level
4250
        // Calculation: height / <effective pixels> * level
20 andreas 4251
        if (dr.compare("horizontal") == 0)
4252
            width = (int)((double)width / ((double)rh - (double)rl) * (double)level);
4253
        else
4254
            height = (int)((double)height / ((double)rh - (double)rl) * (double)level);
4255
 
59 andreas 4256
        if (ri && dr.compare("horizontal") == 0)
20 andreas 4257
        {
59 andreas 4258
            startX = sr[0].mi_width - width;
20 andreas 4259
            width = sr[0].mi_width;
59 andreas 4260
        }
4261
        else if (dr.compare("horizontal") != 0)
4262
        {
4263
            startY = sr[0].mi_height - height;
20 andreas 4264
            height = sr[0].mi_height;
4265
        }
15 andreas 4266
 
254 andreas 4267
        if (!allocPixels(sr[0].mi_width, sr[0].mi_height, &img))
4268
            return false;
4269
 
20 andreas 4270
        SkCanvas canvas(img);
4271
        SkColor col1 = TColor::getSkiaColor(sr[1].cf);
4272
        SkColor col2 = TColor::getSkiaColor(sr[1].cb);
15 andreas 4273
 
20 andreas 4274
        for (int ix = 0; ix < sr[0].mi_width; ix++)
4275
        {
4276
            for (int iy = 0; iy < sr[0].mi_height; iy++)
4277
            {
4278
                SkPaint paint;
4279
                SkColor pixel;
15 andreas 4280
 
20 andreas 4281
                if (ix >= startX && ix < width && iy >= startY && iy < height)
15 andreas 4282
                {
20 andreas 4283
                    SkColor pixelRed = pixmapRed.getColor(ix, iy);
4284
                    SkColor pixelMask;
15 andreas 4285
 
20 andreas 4286
                    if (!imgMask.empty())
4287
                        pixelMask = pixmapMask.getColor(ix, iy);
15 andreas 4288
                    else
20 andreas 4289
                        pixelMask = SK_ColorWHITE;
15 andreas 4290
 
20 andreas 4291
                    pixel = baseColor(pixelRed, pixelMask, col1, col2);
15 andreas 4292
                }
20 andreas 4293
                else
4294
                    pixel = SK_ColorTRANSPARENT;
15 andreas 4295
 
20 andreas 4296
                paint.setColor(pixel);
4297
                canvas.drawPoint(ix, iy, paint);
15 andreas 4298
            }
20 andreas 4299
        }
15 andreas 4300
 
20 andreas 4301
        if (img.empty())
4302
        {
4303
            MSG_ERROR("Error creating the cameleon image \"" << sr[0].mi << "\" / \"" << sr[0].bm << "\"!");
4304
            TError::setError();
4305
            return false;
4306
        }
15 andreas 4307
 
254 andreas 4308
        SkCanvas ctx(img, SkSurfaceProps());
20 andreas 4309
        SkPaint paint;
4310
        paint.setBlendMode(SkBlendMode::kSrcATop);
179 andreas 4311
        sk_sp<SkImage> _image = SkImage::MakeFromBitmap(imgMask);
4312
        ctx.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
15 andreas 4313
 
20 andreas 4314
        POSITION_t position = calcImagePosition(sr[0].mi_width, sr[0].mi_height, SC_BITMAP, 0);
15 andreas 4315
 
20 andreas 4316
        if (!position.valid)
4317
        {
4318
            MSG_ERROR("Error calculating the position of the image for button number " << bi << ": " << na);
4319
            TError::setError();
4320
            return false;
15 andreas 4321
        }
4322
 
254 andreas 4323
        SkCanvas can(*bm, SkSurfaceProps());
20 andreas 4324
        paint.setBlendMode(SkBlendMode::kSrc);
179 andreas 4325
        _image = SkImage::MakeFromBitmap(img);
4326
        can.drawImage(_image, position.left, position.top, SkSamplingOptions(), &paint);
15 andreas 4327
    }
59 andreas 4328
    else if (!sr[0].bm.empty() && !sr[1].bm.empty())
15 andreas 4329
    {
23 andreas 4330
        MSG_TRACE("Drawing normal image ...");
165 andreas 4331
        SkBitmap image1, image2;
4332
 
167 andreas 4333
        TImgCache::getBitmap(sr[0].bm, &image1, _BMTYPE_BITMAP, &sr[0].bm_width, &sr[0].bm_height);   // State when level = 0%
4334
        TImgCache::getBitmap(sr[1].bm, &image2, _BMTYPE_BITMAP, &sr[1].bm_width, &sr[1].bm_height);   // State when level = 100%
254 andreas 4335
        SkCanvas can_bm(*bm, SkSurfaceProps());
15 andreas 4336
 
59 andreas 4337
 
23 andreas 4338
        if (image1.empty())
15 andreas 4339
        {
23 andreas 4340
            MSG_ERROR("Error creating the image \"" << sr[0].bm << "\"!");
15 andreas 4341
            TError::setError();
4342
            return false;
4343
        }
4344
 
23 andreas 4345
        if (image2.empty())
4346
        {
4347
            MSG_ERROR("Error creating the image \"" << sr[1].bm << "\"!");
4348
            TError::setError();
4349
            return false;
4350
        }
4351
 
4352
        int width = sr[1].bm_width;
4353
        int height = sr[1].bm_height;
15 andreas 4354
        int startX = 0;
4355
        int startY = 0;
4356
 
100 andreas 4357
        // Calculation: width / <effective pixels> * level
4358
        // Calculation: height / <effective pixels> * level
15 andreas 4359
        if (dr.compare("horizontal") == 0)
4360
            width = (int)((double)width / ((double)rh - (double)rl) * (double)level);
4361
        else
4362
            height = (int)((double)height / ((double)rh - (double)rl) * (double)level);
4363
 
59 andreas 4364
        if (ri && dr.compare("horizontal") == 0)     // range inverted?
15 andreas 4365
        {
59 andreas 4366
            startX = sr[0].mi_width - width;
15 andreas 4367
            width = sr[0].mi_width;
59 andreas 4368
        }
4369
        else if (dr.compare("horizontal") != 0)
4370
        {
4371
            startY = sr[0].mi_height - height;
15 andreas 4372
            height = sr[0].mi_height;
4373
        }
4374
 
28 andreas 4375
        MSG_DEBUG("dr=" << dr << ", startX=" << startX << ", startY=" << startY << ", width=" << width << ", height=" << height << ", level=" << level);
23 andreas 4376
        MSG_TRACE("Creating bargraph ...");
59 andreas 4377
        SkBitmap img_bar;
254 andreas 4378
 
4379
        if (!allocPixels(sr[1].bm_width, sr[1].bm_height, &img_bar))
4380
            return false;
4381
 
59 andreas 4382
        img_bar.eraseColor(SK_ColorTRANSPARENT);
254 andreas 4383
        SkCanvas bar(img_bar, SkSurfaceProps());
23 andreas 4384
 
4385
        for (int ix = 0; ix < sr[1].bm_width; ix++)
4386
        {
4387
            for (int iy = 0; iy < sr[1].bm_height; iy++)
4388
            {
4389
                SkPaint paint;
4390
                SkColor pixel;
4391
 
4392
                if (ix >= startX && ix < width && iy >= startY && iy < height)
4393
                    pixel = image2.getColor(ix, iy);
4394
                else
4395
                    pixel = SK_ColorTRANSPARENT;
4396
 
4397
                paint.setColor(pixel);
59 andreas 4398
                bar.drawPoint(ix, iy, paint);
23 andreas 4399
            }
4400
        }
4401
 
15 andreas 4402
        SkPaint paint;
59 andreas 4403
        paint.setBlendMode(SkBlendMode::kSrc);
179 andreas 4404
        sk_sp<SkImage> _image = SkImage::MakeFromBitmap(image1);
4405
        can_bm.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
23 andreas 4406
        paint.setBlendMode(SkBlendMode::kSrcATop);
179 andreas 4407
        _image = SkImage::MakeFromBitmap(img_bar);
4408
        can_bm.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);       // Draw the above created image over the 0% image
142 andreas 4409
    }
4410
    else if (sr[0].bm.empty() && !sr[1].bm.empty())     // Only one bitmap in the second instance
4411
    {
4412
        MSG_TRACE("Drawing second image " << sr[1].bm << " ...");
165 andreas 4413
        SkBitmap image;
167 andreas 4414
        TImgCache::getBitmap(sr[1].bm, &image, _BMTYPE_BITMAP, &sr[1].bm_width, &sr[1].bm_height);   // State when level = 100%
254 andreas 4415
        SkCanvas can_bm(*bm, SkSurfaceProps());
142 andreas 4416
 
4417
        if (image.empty())
4418
        {
4419
            MSG_ERROR("Error creating the image \"" << sr[1].bm << "\"!");
4420
            TError::setError();
4421
            return false;
4422
        }
4423
 
4424
        int width = sr[1].bm_width;
4425
        int height = sr[1].bm_height;
4426
        int startX = 0;
4427
        int startY = 0;
4428
 
4429
        // Calculation: width / <effective pixels> * level
4430
        // Calculation: height / <effective pixels> * level
4431
        if (dr.compare("horizontal") == 0)
4432
            width = (int)((double)width / ((double)rh - (double)rl) * (double)level);
4433
        else
4434
            height = (int)((double)height / ((double)rh - (double)rl) * (double)level);
4435
 
4436
        if (ri && dr.compare("horizontal") == 0)     // range inverted?
4437
        {
4438
            startX = sr[1].mi_width - width;
4439
            width = sr[1].mi_width;
4440
        }
4441
        else if (dr.compare("horizontal") != 0)
4442
        {
4443
            startY = sr[1].mi_height - height;
4444
            height = sr[1].mi_height;
4445
        }
4446
 
4447
        MSG_DEBUG("dr=" << dr << ", startX=" << startX << ", startY=" << startY << ", width=" << width << ", height=" << height << ", level=" << level);
4448
        MSG_TRACE("Creating bargraph ...");
4449
        SkBitmap img_bar;
254 andreas 4450
 
4451
        if (!allocPixels(sr[1].bm_width, sr[1].bm_height, &img_bar))
4452
            return false;
4453
 
142 andreas 4454
        img_bar.eraseColor(SK_ColorTRANSPARENT);
254 andreas 4455
        SkCanvas bar(img_bar, SkSurfaceProps());
142 andreas 4456
        SkPaint pt;
4457
 
4458
        for (int ix = 0; ix < sr[1].bm_width; ix++)
4459
        {
4460
            for (int iy = 0; iy < sr[1].bm_height; iy++)
4461
            {
4462
                SkColor pixel;
4463
 
4464
                if (ix >= startX && ix < width && iy >= startY && iy < height)
4465
                    pixel = image.getColor(ix, iy);
4466
                else
4467
                    pixel = SK_ColorTRANSPARENT;
4468
 
4469
                pt.setColor(pixel);
4470
                bar.drawPoint(ix, iy, pt);
4471
            }
4472
        }
4473
 
4474
        SkPaint paint;
4475
        paint.setBlendMode(SkBlendMode::kSrcOver);
179 andreas 4476
        sk_sp<SkImage> _image = SkImage::MakeFromBitmap(img_bar);
4477
        can_bm.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);      // Draw the above created image over the 0% image
15 andreas 4478
    }
4479
    else
4480
    {
38 andreas 4481
        MSG_TRACE("No bitmap defined.");
4482
        int width = wt;
4483
        int height = ht;
15 andreas 4484
        int startX = 0;
4485
        int startY = 0;
4486
 
100 andreas 4487
        // Calculation: width / <effective pixels> * level = <level position>
4488
        // Calculation: height / <effective pixels> * level = <level position>
15 andreas 4489
        if (dr.compare("horizontal") == 0)
4490
            width = (int)((double)width / ((double)rh - (double)rl) * (double)level);
4491
        else
4492
            height = (int)((double)height / ((double)rh - (double)rl) * (double)level);
4493
 
59 andreas 4494
        if (ri && dr.compare("horizontal") == 0)
15 andreas 4495
        {
59 andreas 4496
            startX = wt - width;
38 andreas 4497
            width = wt;
59 andreas 4498
        }
4499
        else if (dr.compare("horizontal") != 0)
4500
        {
4501
            startY = ht - height;
38 andreas 4502
            height = ht;
15 andreas 4503
        }
4504
 
4505
        SkPaint paint;
4506
        paint.setBlendMode(SkBlendMode::kSrc);
254 andreas 4507
        SkCanvas can(*bm, SkSurfaceProps());
20 andreas 4508
        paint.setStyle(SkPaint::kFill_Style);
4509
        paint.setAntiAlias(true);
4510
        paint.setStrokeWidth(4);
38 andreas 4511
        paint.setColor(TColor::getSkiaColor(sr[1].cf));
4512
        MSG_DEBUG("Drawing rectangle: X=" << startX << ", Y=" << startY << ", W=" << width << ", H=" << height << ", level=" << level);
15 andreas 4513
        SkRect dst;
4514
        dst.setXYWH(startX, startY, width, height);
20 andreas 4515
        can.drawRect(dst, paint);
99 andreas 4516
        // If we have a slider button defined, we must draw it. To do it, we
4517
        // must look into the system resources to find the credentials to draw
4518
        // the button.
4519
        if (!sd.empty())
4520
        {
4521
            MSG_DEBUG("Attempt to draw the slider button \"" << sd << "\".");
100 andreas 4522
            int innerW = 0;
4523
            int innerH = 0;
4524
 
99 andreas 4525
            SkBitmap slButton = drawSliderButton(sd, TColor::getSkiaColor(sc));
4526
 
4527
            if (slButton.empty())
4528
            {
4529
                MSG_ERROR("Error drawing the slicer button " << sd);
4530
                return true;
4531
            }
4532
 
4533
            double scaleW, scaleH;
100 andreas 4534
            int border_size = getBorderSize(sr[0].bs);
99 andreas 4535
 
4536
            if (dr.compare("horizontal") != 0)
4537
            {
4538
                double scale;
100 andreas 4539
                innerH = (int)((double)(height - border_size * 2 - slButton.info().height() / 2) / ((double)rh - (double)rl) * (double)level) + border_size + slButton.info().height() / 2;
4540
                innerW = width;
4541
                scale = (double)(wt - border_size * 2) / (double)slButton.info().width();
99 andreas 4542
                scaleW = scale;
100 andreas 4543
                scaleH = 1.0;
4544
 
4545
                if (!ri)
4546
                    innerH = height - innerH;
99 andreas 4547
            }
4548
            else
4549
            {
4550
                double scale;
100 andreas 4551
                scale = (double)(ht - border_size * 2) / (double)slButton.info().height();
4552
                scaleW = 1.0;
99 andreas 4553
                scaleH = scale;
100 andreas 4554
                innerW = (int)((double)(width - border_size * 2 - slButton.info().width() / 2) / ((double)rh - (double)rl) * (double)level) + border_size + slButton.info().width() / 2;
4555
                innerH = height;
4556
 
4557
                if (!ri)
4558
                    innerW = width - innerW;
99 andreas 4559
            }
100 andreas 4560
 
99 andreas 4561
            if (scaleImage(&slButton, scaleW, scaleH))
4562
            {
4563
                int w = slButton.info().width();
4564
                int h = slButton.info().height();
4565
 
4566
                if (dr.compare("horizontal") == 0)
4567
                {
100 andreas 4568
                    int pos = innerW;
4569
                    dst.setXYWH(pos - w / 2, border_size, w, h);
99 andreas 4570
                }
4571
                else
4572
                {
100 andreas 4573
                    int pos = innerH;
4574
                    dst.setXYWH(border_size, pos - h / 2, w, h);
99 andreas 4575
                }
4576
 
4577
                SkPaint pnt;
100 andreas 4578
                pnt.setBlendMode(SkBlendMode::kSrcOver);
179 andreas 4579
                sk_sp<SkImage> _image = SkImage::MakeFromBitmap(slButton);
4580
                can.drawImageRect(_image, dst, SkSamplingOptions(), &pnt);
99 andreas 4581
            }
4582
        }
15 andreas 4583
    }
4584
 
4585
    return true;
4586
}
4587
 
99 andreas 4588
SkBitmap TButton::drawSliderButton(const string& slider, SkColor col)
4589
{
4590
    DECL_TRACER("TButton::drawSliderButton(const string& slider)");
4591
 
4592
    SkBitmap slButton;
4593
    // First we look for the slider button.
4594
    if (!gPageManager || !gPageManager->getSystemDraw()->existSlider(slider))
4595
        return slButton;
4596
 
4597
    // There exists one with the wanted name. We grab it and create
4598
    // the images from the files.
4599
    SLIDER_STYLE_t sst;
4600
 
4601
    if (!gPageManager->getSystemDraw()->getSlider(slider, &sst))    // should never be true!
4602
    {
4603
        MSG_ERROR("No slider entry found!");
4604
        return slButton;
4605
    }
4606
 
4607
    int width, height;
4608
 
4609
    if (dr.compare("horizontal") != 0)
4610
    {
100 andreas 4611
        width = (sst.fixedSize / 2) * 2 + sst.fixedSize;
99 andreas 4612
        height = sst.fixedSize;
4613
    }
4614
    else
4615
    {
4616
        width = sst.fixedSize;
100 andreas 4617
        height = (sst.fixedSize / 2) * 2 + sst.fixedSize;
99 andreas 4618
    }
4619
 
4620
    // Retrieve all available slider graphics files from the system
4621
    vector<SLIDER_t> sltList = gPageManager->getSystemDraw()->getSliderFiles(slider);
4622
 
4623
    if (sltList.empty())
4624
    {
4625
        MSG_ERROR("No system slider graphics found!");
4626
        return SkBitmap();
4627
    }
4628
 
4629
    SkPaint paint;
4630
    paint.setBlendMode(SkBlendMode::kSrc);
254 andreas 4631
 
4632
    if (!allocPixels(width, height, &slButton))
4633
        return slButton;
4634
 
99 andreas 4635
    slButton.eraseColor(SK_ColorTRANSPARENT);
254 andreas 4636
    SkCanvas slCan(slButton, SkSurfaceProps());
99 andreas 4637
    vector<SLIDER_t>::iterator sltIter;
4638
    // Loop through list of slider graphic files
4639
    for (sltIter = sltList.begin(); sltIter != sltList.end(); ++sltIter)
4640
    {
4641
        SkBitmap slPart;
4642
        SkBitmap slPartAlpha;
4643
        SkRect dst;
4644
 
4645
        if (dr.compare("horizontal") != 0 && (sltIter->type == SGR_LEFT || sltIter->type == SGR_RIGHT || sltIter->type == SGR_VERTICAL))    // vertical slider
4646
        {
4647
            if (!retrieveImage(sltIter->path, &slPart))     // Get the mask
4648
            {
4649
                MSG_ERROR("Missing slider button mask image " << sltIter->path);
4650
                return SkBitmap();
4651
            }
4652
 
4653
            if (!retrieveImage(sltIter->pathAlpha, &slPartAlpha))   // Get the alpha mask
4654
            {
4655
                MSG_ERROR("Missing slider button alpha image " << sltIter->pathAlpha);
4656
                return SkBitmap();
4657
            }
4658
 
4659
            SkBitmap sl = combineImages(slPart, slPartAlpha, col);
4660
 
4661
            if (sl.empty())
4662
                return sl;
4663
 
4664
            switch (sltIter->type)
4665
            {
4666
                case SGR_LEFT:      dst.setXYWH(0, 0, sl.info().width(), sl.info().height()); break;
4667
 
4668
                case SGR_VERTICAL:
100 andreas 4669
                    stretchImageWidth(&sl, sst.fixedSize);
99 andreas 4670
                    dst.setXYWH(sst.fixedSize / 2, 0, sl.info().width(), sl.info().height());
4671
                break;
4672
 
100 andreas 4673
                case SGR_RIGHT:     dst.setXYWH((sst.fixedSize / 2) + sst.fixedSize, 0, sl.info().width(), sl.info().height()); break;
99 andreas 4674
 
4675
                default:
4676
                    MSG_WARNING("Invalid type " << sltIter->type << " found!");
4677
            }
4678
 
179 andreas 4679
            sk_sp<SkImage> _image = SkImage::MakeFromBitmap(sl);
4680
            slCan.drawImageRect(_image, dst, SkSamplingOptions(), &paint);
99 andreas 4681
        }
4682
        else if (dr.compare("horizontal") == 0 && (sltIter->type == SGR_TOP || sltIter->type == SGR_BOTTOM || sltIter->type == SGR_HORIZONTAL)) // horizontal slider
4683
        {
4684
            if (!retrieveImage(sltIter->path, &slPart))
4685
            {
4686
                MSG_ERROR("Missing slider button image " << sltIter->path);
4687
                return SkBitmap();
4688
            }
4689
 
4690
            if (!retrieveImage(sltIter->pathAlpha, &slPartAlpha))
4691
            {
4692
                MSG_ERROR("Missing slider button image " << sltIter->pathAlpha);
4693
                return SkBitmap();
4694
            }
4695
 
4696
            SkBitmap sl = combineImages(slPart, slPartAlpha, col);
4697
 
4698
            if (sl.empty())
4699
                return sl;
4700
 
4701
            switch (sltIter->type)
4702
            {
4703
                case SGR_TOP:       dst.setXYWH(0, 0, sl.info().width(), sl.info().height()); break;
4704
 
4705
                case SGR_HORIZONTAL:
100 andreas 4706
                    stretchImageHeight(&sl, sst.fixedSize);
99 andreas 4707
                    dst.setXYWH(0, sst.fixedSize / 2, sl.info().width(), sl.info().height());
4708
                break;
4709
 
100 andreas 4710
                case SGR_BOTTOM:    dst.setXYWH(0, (sst.fixedSize / 2) + sst.fixedSize, sl.info().width(), sl.info().height()); break;
99 andreas 4711
 
4712
                default:
4713
                    MSG_WARNING("Invalid type " << sltIter->type << " found!");
4714
            }
4715
 
179 andreas 4716
            sk_sp<SkImage> _image = SkImage::MakeFromBitmap(sl);
4717
            slCan.drawImageRect(_image, dst, SkSamplingOptions(), &paint);
99 andreas 4718
        }
4719
    }
4720
 
4721
    return slButton;
4722
}
4723
 
8 andreas 4724
bool TButton::buttonIcon(SkBitmap* bm, int instance)
4725
{
4726
    DECL_TRACER("TButton::buttonIcon(SkBitmap* bm, int instance)");
4727
 
165 andreas 4728
    if (instance < 0 || (size_t)instance >= sr.size())
4729
    {
4730
        MSG_ERROR("Invalid instance " << instance);
4731
        return false;
4732
    }
4733
 
8 andreas 4734
    if (sr[instance].ii <= 0)
4735
    {
4736
        MSG_TRACE("No icon defined!");
4737
        return true;
7 andreas 4738
    }
4739
 
8 andreas 4740
    MSG_DEBUG("Drawing an icon ...");
4741
 
4742
    if (!gIcons)
4743
    {
192 andreas 4744
        MSG_WARNING("No icons were defined!");
4745
        return true;
4746
    }
8 andreas 4747
 
192 andreas 4748
    string file = gIcons->getFile(sr[instance].ii);
4749
 
4750
    if (file.empty())
4751
    {
4752
        MSG_WARNING("The icon " << sr[instance].ii << " was not found in table!");
4753
        return true;
8 andreas 4754
    }
4755
 
4756
    MSG_DEBUG("Loading icon file " << file);
4757
    sk_sp<SkData> image;
4758
    SkBitmap icon;
4759
 
4760
    if (!(image = readImage(file)))
192 andreas 4761
        return true;
8 andreas 4762
 
4763
    DecodeDataToBitmap(image, &icon);
4764
 
4765
    if (icon.empty())
4766
    {
4767
        MSG_WARNING("Could not create an icon for element " << sr[instance].ii << " on button " << bi << " (" << na << ")");
192 andreas 4768
        return true;
8 andreas 4769
    }
4770
 
4771
    SkImageInfo info = icon.info();
4772
    POSITION_t position = calcImagePosition(icon.width(), icon.height(), SC_ICON, instance);
4773
 
4774
    if (!position.valid)
4775
    {
4776
        MSG_ERROR("Error calculating the position of the image for button number " << bi);
4777
        TError::setError();
4778
        return false;
4779
    }
4780
 
10 andreas 4781
    MSG_DEBUG("Putting Icon on top of bitmap ...");
4782
    SkPaint paint;
4783
    paint.setBlendMode(SkBlendMode::kSrcOver);
254 andreas 4784
    SkCanvas can(*bm, SkSurfaceProps());
8 andreas 4785
 
17 andreas 4786
    if (position.overflow)
4787
    {
179 andreas 4788
        SkRect irect;
17 andreas 4789
        SkRect bdst;
4790
        SkBitmap dst;
4791
        int left = (position.left >= 0) ? 0 : position.left * -1;
4792
        int top = (position.top >= 0) ? 0 : position.top * -1;
4793
        int width = std::min(wt, info.width());
4794
        int height = std::min(ht, info.height());
4795
        irect.setXYWH(left, top, width, height);
4796
        bm->getBounds(&bdst);
179 andreas 4797
        sk_sp<SkImage> _image = SkImage::MakeFromBitmap(icon);
4798
        can.drawImageRect(_image, irect, bdst, SkSamplingOptions(), &paint, SkCanvas::kStrict_SrcRectConstraint);
17 andreas 4799
    }
4800
    else
179 andreas 4801
    {
4802
        sk_sp<SkImage> _image = SkImage::MakeFromBitmap(icon);
4803
        can.drawImage(_image, position.left, position.top, SkSamplingOptions(), &paint);
4804
    }
17 andreas 4805
 
8 andreas 4806
    return true;
4807
}
4808
 
38 andreas 4809
bool TButton::buttonText(SkBitmap* bm, int inst)
8 andreas 4810
{
38 andreas 4811
    DECL_TRACER("TButton::buttonText(SkBitmap* bm, int inst)");
8 andreas 4812
 
38 andreas 4813
    int instance = inst;
4814
 
4815
    if ((size_t)instance >= sr.size())
289 andreas 4816
        instance = (int)(sr.size() - 1);
38 andreas 4817
    else if (instance < 0)
4818
        instance = 0;
4819
 
289 andreas 4820
    if (sr[instance].te.empty())            // Is there a text?
4821
    {                                       // No, then return
67 andreas 4822
        MSG_DEBUG("Empty text string.");
4823
        return true;
4824
    }
4825
 
289 andreas 4826
    if (!mFonts)                            // Do we have any fonts?
4827
    {                                       // No, warn and return
4828
        MSG_WARNING("No fonts available to write a text!");
4829
        return true;
4830
    }
4831
 
67 andreas 4832
    MSG_DEBUG("Searching for font number " << sr[instance].fi << " with text " << sr[instance].te);
4833
    FONT_T font = mFonts->getFont(sr[instance].fi);
4834
 
161 andreas 4835
    if (font.file.empty())
7 andreas 4836
    {
161 andreas 4837
        MSG_WARNING("No font file name found for font " << sr[instance].fi);
4838
        return true;
4839
    }
7 andreas 4840
 
161 andreas 4841
    sk_sp<SkTypeface> typeFace = mFonts->getTypeFace(sr[instance].fi);
254 andreas 4842
    SkCanvas canvas(*bm);
161 andreas 4843
 
4844
    if (!typeFace)
4845
    {
164 andreas 4846
        MSG_WARNING("Error creating type face " << font.fullName);
161 andreas 4847
    }
4848
 
4849
    SkScalar fontSizePt = ((SkScalar)font.size * 1.322);
164 andreas 4850
    SkFont skFont;
4851
 
4852
    if (typeFace && typeFace->countTables() > 0)
4853
        skFont.setTypeface(typeFace);
4854
 
4855
    skFont.setSize(fontSizePt);
161 andreas 4856
    skFont.setEdging(SkFont::Edging::kAntiAlias);
4857
    MSG_DEBUG("Wanted font size: " << font.size << ", this is " << fontSizePt << " pt");
4858
 
4859
    SkPaint paint;
4860
    paint.setAntiAlias(true);
4861
    paint.setColor(TColor::getSkiaColor(sr[instance].ct));
4862
    paint.setStyle(SkPaint::kFill_Style);
4863
 
4864
    SkFontMetrics metrics;
4865
    skFont.getMetrics(&metrics);
4866
    int lines = numberLines(sr[instance].te);
164 andreas 4867
//    MSG_DEBUG("fAvgCharWidth: " << metrics.fAvgCharWidth);
4868
//    MSG_DEBUG("fCapHeight:    " << metrics.fCapHeight);
4869
//    MSG_DEBUG("fAscent:       " << metrics.fAscent);
4870
//    MSG_DEBUG("fDescent:      " << metrics.fDescent);
4871
//    MSG_DEBUG("fLeading:      " << metrics.fLeading);
4872
//    MSG_DEBUG("fXHeight:      " << metrics.fXHeight);
161 andreas 4873
 
4874
    MSG_DEBUG("Found " << lines << " lines.");
4875
 
4876
    if (lines > 1 || sr[instance].ww)
4877
    {
4878
        vector<string> textLines;
4879
 
4880
        if (!sr[instance].ww)
4881
            textLines = splitLine(sr[instance].te);
4882
        else
6 andreas 4883
        {
161 andreas 4884
            textLines = splitLine(sr[instance].te, wt, ht, skFont, paint);
289 andreas 4885
            lines = (int)textLines.size();
67 andreas 4886
        }
7 andreas 4887
 
161 andreas 4888
        MSG_DEBUG("Calculated number of lines: " << lines);
4889
        int lineHeight = (metrics.fAscent * -1) + metrics.fDescent;
4890
        int totalHeight = lineHeight * lines;
19 andreas 4891
 
161 andreas 4892
        if (totalHeight > ht)
4893
        {
4894
            lines = ht / lineHeight;
4895
            totalHeight = lineHeight * lines;
4896
        }
8 andreas 4897
 
161 andreas 4898
        MSG_DEBUG("Line height: " << lineHeight << ", total height: " << totalHeight);
4899
        vector<string>::iterator iter;
4900
        int line = 0;
4901
        int maxWidth = 0;
69 andreas 4902
 
161 andreas 4903
        if (textLines.size() > 0)
67 andreas 4904
        {
161 andreas 4905
            // Calculate the maximum width
4906
            for (iter = textLines.begin(); iter != textLines.end(); ++iter)
4907
            {
4908
                SkRect rect;
4909
                skFont.measureText(iter->c_str(), iter->length(), SkTextEncoding::kUTF8, &rect, &paint);
67 andreas 4910
 
161 andreas 4911
                if (rect.width() > maxWidth)
4912
                    maxWidth = rect.width();
67 andreas 4913
            }
8 andreas 4914
 
161 andreas 4915
            POSITION_t pos = calcImagePosition(maxWidth, totalHeight, SC_TEXT, instance);
8 andreas 4916
 
161 andreas 4917
            if (!pos.valid)
67 andreas 4918
            {
161 andreas 4919
                MSG_ERROR("Error calculating the text position!");
4920
                TError::setError();
4921
                return false;
67 andreas 4922
            }
40 andreas 4923
 
161 andreas 4924
            SkScalar lnHt = metrics.fAscent * -1;
96 andreas 4925
 
161 andreas 4926
            for (iter = textLines.begin(); iter != textLines.end(); ++iter)
69 andreas 4927
            {
161 andreas 4928
                sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromString(iter->c_str(), skFont);
4929
                MSG_DEBUG("Trying to print line: " << *iter);
4930
                // We want to take care about the horizontal position.
4931
                SkRect rect;
4932
                skFont.measureText(iter->c_str(), iter->length(), SkTextEncoding::kUTF8, &rect, &paint);
4933
                SkScalar horizontal = 0.0;
4934
 
4935
                switch(sr[instance].jt)
96 andreas 4936
                {
161 andreas 4937
                    case ORI_BOTTOM_MIDDLE:
4938
                    case ORI_CENTER_MIDDLE:
4939
                    case ORI_TOP_MIDDLE:
4940
                        horizontal = (wt - rect.width()) / 2.0f;
4941
                    break;
40 andreas 4942
 
161 andreas 4943
                    case ORI_BOTTOM_RIGHT:
4944
                    case ORI_CENTER_RIGHT:
4945
                    case ORI_TOP_RIGHT:
4946
                        horizontal = wt - rect.width();
4947
                    break;
69 andreas 4948
 
161 andreas 4949
                    default:
4950
                        horizontal = pos.left;
96 andreas 4951
                }
40 andreas 4952
 
161 andreas 4953
                SkScalar startX = horizontal;
4954
                SkScalar startY = (SkScalar)pos.top + (SkScalar)lineHeight * (SkScalar)line;
4955
                MSG_DEBUG("x=" << startX << ", y=" << startY);
4956
                bool tEffect = false;
4957
                // Text effects
4958
                if (sr[instance].et > 0)
4959
                    tEffect = textEffect(&canvas, blob, startX, startY + lnHt, instance);
67 andreas 4960
 
161 andreas 4961
                if (!tEffect)
4962
                    canvas.drawTextBlob(blob.get(), startX, startY + lnHt, paint);
69 andreas 4963
 
161 andreas 4964
                line++;
69 andreas 4965
 
161 andreas 4966
                if (line > lines)
4967
                    break;
67 andreas 4968
            }
4969
        }
161 andreas 4970
    }
4971
    else    // single line
4972
    {
4973
        string text = sr[instance].te;
4974
        sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromString(text.data(), skFont);
4975
        SkRect rect;
4976
        skFont.measureText(text.data(), text.size(), SkTextEncoding::kUTF8, &rect, &paint);
164 andreas 4977
        MSG_DEBUG("Calculated Skia rectangle of font: width=" << rect.width() << ", height=" << rect.height());
4978
        POSITION_t position;
66 andreas 4979
 
164 andreas 4980
        if (metrics.fCapHeight >= 1.0)
4981
            position = calcImagePosition(rect.width(), metrics.fCapHeight, SC_TEXT, instance);
4982
        else
4983
            position = calcImagePosition(rect.width(), rect.height(), SC_TEXT, instance);
4984
 
161 andreas 4985
        if (!position.valid)
4986
        {
4987
            MSG_ERROR("Error calculating the text position!");
4988
            TError::setError();
4989
            return false;
4990
        }
66 andreas 4991
 
161 andreas 4992
        MSG_DEBUG("Printing line " << text);
4993
        SkScalar startX = (SkScalar)position.left;
164 andreas 4994
        SkScalar startY = (SkScalar)position.top;
10 andreas 4995
 
164 andreas 4996
        if (metrics.fCapHeight >= 1.0)
4997
            startY += metrics.fCapHeight;   // This is the offset of the line
4998
        else
4999
            startY += rect.height();        // This is the offset of the line
5000
 
161 andreas 5001
        FONT_TYPE sym = TFont::isSymbol(typeFace);
5002
        bool tEffect = false;
5003
        // Text effects
5004
        if (sr[instance].et > 0)
164 andreas 5005
            tEffect = textEffect(&canvas, blob, startX, startY, instance);
67 andreas 5006
 
161 andreas 5007
        if (!tEffect && utf8Strlen(text) > 1)
164 andreas 5008
            canvas.drawTextBlob(blob.get(), startX, startY, paint);
161 andreas 5009
        else
5010
        {
5011
            int count = 0;
5012
            uint16_t *glyphs = nullptr;
5013
 
5014
            if (sym == FT_SYM_MS)
8 andreas 5015
            {
161 andreas 5016
                MSG_DEBUG("Microsoft proprietary symbol font detected.");
5017
                uint16_t *uni;
5018
                size_t num = TFont::utf8ToUtf16(text, &uni, true);
5019
                MSG_DEBUG("Got " << num << " unichars, first unichar: " << std::hex << std::setw(4) << std::setfill('0') << *uni << std::dec);
7 andreas 5020
 
161 andreas 5021
                if (num > 0)
8 andreas 5022
                {
161 andreas 5023
                    glyphs = new uint16_t[num];
5024
                    size_t glyphSize = sizeof(uint16_t) * num;
289 andreas 5025
                    count = skFont.textToGlyphs(uni, num, SkTextEncoding::kUTF16, glyphs, (int)glyphSize);
8 andreas 5026
 
161 andreas 5027
                    if (count <= 0)
67 andreas 5028
                    {
161 andreas 5029
                        delete[] glyphs;
5030
                        glyphs = TFont::textToGlyphs(text, typeFace, &num);
289 andreas 5031
                        count = (int)num;
67 andreas 5032
                    }
5033
                }
5034
                else
5035
                {
161 andreas 5036
                    canvas.drawTextBlob(blob.get(), startX, startY, paint);
5037
                    return true;
67 andreas 5038
                }
5039
 
161 andreas 5040
                if (uni)
5041
                    delete[] uni;
5042
            }
5043
            else if (tEffect)
5044
                return true;
5045
            else
5046
            {
5047
                glyphs = new uint16_t[text.size()];
5048
                size_t glyphSize = sizeof(uint16_t) * text.size();
289 andreas 5049
                count = skFont.textToGlyphs(text.data(), text.size(), SkTextEncoding::kUTF8, glyphs, (int)glyphSize);
161 andreas 5050
            }
156 andreas 5051
 
331 andreas 5052
            if (glyphs && count > 0)
161 andreas 5053
            {
5054
                MSG_DEBUG("1st glyph: 0x" << std::hex << std::setw(8) << std::setfill('0') << *glyphs << ", # glyphs: " << std::dec << count);
164 andreas 5055
                canvas.drawSimpleText(glyphs, sizeof(uint16_t) * count, SkTextEncoding::kGlyphID, startX, startY, skFont, paint);
8 andreas 5056
            }
161 andreas 5057
            else    // Try to print something
5058
            {
5059
                MSG_WARNING("Got no glyphs! Try to print: " << text);
331 andreas 5060
                canvas.drawString(text.data(), startX, startY, skFont, paint);
161 andreas 5061
            }
5062
 
331 andreas 5063
            if (glyphs)
5064
                delete[] glyphs;
8 andreas 5065
        }
5066
    }
5067
 
5068
    return true;
5069
}
5070
 
69 andreas 5071
int TButton::calcLineHeight(const string& text, SkFont& font)
40 andreas 5072
{
69 andreas 5073
    DECL_TRACER("TButton::calcLineHeight(const string& text, SkFont& font)");
40 andreas 5074
 
69 andreas 5075
    size_t pos = text.find("\n");       // Search for a line break.
5076
    string lText = text;
5077
 
5078
    if (pos != string::npos)            // Do we have found a line break?
5079
        lText = text.substr(0, pos - 1);// Yes, take only the text up to 1 before the line break (only 1 line).
5080
 
5081
    sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromString(lText.c_str(), font);
40 andreas 5082
    SkRect rect = blob.get()->bounds();
5083
    return rect.height();
5084
}
5085
 
66 andreas 5086
bool TButton::textEffect(SkCanvas *canvas, sk_sp<SkTextBlob>& blob, SkScalar startX, SkScalar startY, int instance)
5087
{
5088
    DECL_TRACER("TButton::textEffect(SkBitmap *bm, int instance)");
5089
 
5090
    if (!canvas)
5091
        return false;
5092
 
165 andreas 5093
    if (instance < 0 || (size_t)instance >= sr.size())
5094
    {
5095
        MSG_ERROR("Invalid instance " << instance);
5096
        return false;
5097
    }
5098
 
66 andreas 5099
    // Drop Shadow
5100
    if (sr[instance].et >= 9 && sr[instance].et <= 32)
5101
    {
5102
        SkScalar gap = 0.0;
5103
        SkScalar sigma = 0.0;
5104
        SkScalar xDrop = 0.0;
5105
        SkScalar yDrop = 0.0;
5106
        uint8_t blurAlpha = 255;
5107
        SkPaint paint;
5108
        paint.setAntiAlias(true);
5109
        paint.setColor(TColor::getSkiaColor(sr[instance].ct));
5110
 
5111
        // Soft drop shadow
5112
        if (sr[instance].et >= 9 && sr[instance].et <= 16)
5113
        {
5114
            gap = (SkScalar)sr[instance].et - 8.0f;
5115
            sigma = 3.0f;
5116
            blurAlpha = 127;
5117
        }
5118
        else if (sr[instance].et >= 17 && sr[instance].et <= 24) // Medium drop shadow
5119
        {
5120
            gap = (SkScalar)sr[instance].et - 16.0f;
5121
            sigma = 2.0f;
5122
            blurAlpha = 159;
5123
        }
5124
        else    // Hard drop shadow
5125
        {
5126
            gap = (SkScalar)sr[instance].et - 24.0f;
5127
            sigma = 1.1f;
5128
            blurAlpha = 207;
5129
        }
5130
 
5131
        xDrop = gap;
5132
        yDrop = gap;
5133
        SkPaint blur(paint);
5134
        blur.setAlpha(blurAlpha);
5135
        blur.setColor(TColor::getSkiaColor(sr[instance].ec));
5136
        blur.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, sigma, 0));
5137
        canvas->drawTextBlob(blob.get(), startX + xDrop, startY + yDrop, blur);
5138
        canvas->drawTextBlob(blob.get(), startX, startY, paint);
5139
        return true;
5140
    }
161 andreas 5141
    else if (sr[instance].et >= 5 && sr[instance].et <= 8)  // Glow
5142
    {
5143
        SkScalar sigma = 0.0;
66 andreas 5144
 
161 andreas 5145
        switch(sr[instance].et)
5146
        {
5147
            case 5: sigma = 2.0; break;     // Glow-S
5148
            case 6: sigma = 4.0; break;     // Glow-M
5149
            case 7: sigma = 6.0; break;     // Glow-L
5150
            case 8: sigma = 8.0; break;     // Glow-X
5151
        }
5152
 
5153
        SkPaint paint, blur;
5154
        paint.setAntiAlias(true);
5155
        paint.setColor(TColor::getSkiaColor(sr[instance].ct));
5156
        blur.setColor(TColor::getSkiaColor(sr[instance].ec));
5157
        blur.setStyle(SkPaint::kStroke_Style);
5158
        blur.setStrokeWidth(sigma / 1.5);
5159
        blur.setMaskFilter(SkMaskFilter::MakeBlur(kOuter_SkBlurStyle, sigma));
5160
        canvas->drawTextBlob(blob.get(), startX, startY, paint);
5161
        canvas->drawTextBlob(blob.get(), startX, startY, blur);
5162
        return true;
5163
    }
5164
    else if (sr[instance].et >= 1 && sr[instance].et <= 4)  // Outline
5165
    {
5166
        SkScalar sigma = 0.0;
5167
 
5168
        switch(sr[instance].et)
5169
        {
5170
            case 1: sigma = 1.0; break;     // Outline-S
5171
            case 2: sigma = 2.0; break;     // Outline-M
5172
            case 3: sigma = 4.0; break;     // Outline-L
5173
            case 4: sigma = 6.0; break;     // Outline-X
5174
        }
5175
 
5176
        SkPaint paint, outline;
5177
        paint.setAntiAlias(true);
5178
        paint.setColor(TColor::getSkiaColor(sr[instance].ct));
5179
        outline.setAntiAlias(true);
5180
        outline.setColor(TColor::getSkiaColor(sr[instance].ec));
5181
        outline.setStyle(SkPaint::kStroke_Style);
5182
        outline.setStrokeWidth(sigma);
5183
        canvas->drawTextBlob(blob.get(), startX, startY, outline);
5184
        canvas->drawTextBlob(blob.get(), startX, startY, paint);
5185
        return true;
5186
    }
5187
 
66 andreas 5188
    return false;
5189
}
5190
 
317 andreas 5191
/**
5192
 * @brief TButton::buttonBorder - draw a border, if any.
5193
 * This method draws a border if there is one defined in \b sr[].bs. If there
5194
 * is also a global border defined in \b bs then this border is limiting the
5195
 * valid borders to it. The method does not check this, because it is subject
5196
 * to TPDesign.
5197
 *
5198
 * @param bm        Bitmap to draw the border on.
5199
 * @param inst      The instance where the border definitition should be taken from
5200
 *
5201
 * @return TRUE on success, otherwise FALSE.
5202
 */
159 andreas 5203
bool TButton::buttonBorder(SkBitmap* bm, int inst)
8 andreas 5204
{
5205
    DECL_TRACER("TButton::buttonBorder(SkBitmap* bm, int instance)");
5206
 
159 andreas 5207
    int instance = inst;
5208
 
5209
    if (instance < 0)
5210
        instance = 0;
5211
    else if ((size_t)instance > sr.size())
5212
        instance = (int)sr.size() - 1;
5213
 
317 andreas 5214
    if (sr[instance].bs.empty())
8 andreas 5215
    {
5216
        MSG_DEBUG("No border defined.");
5217
        return true;
5218
    }
5219
 
317 andreas 5220
    string bname = sr[instance].bs;
79 andreas 5221
    // Try to find the border in the system table
317 andreas 5222
    if (drawBorder(bm, bname, wt, ht, sr[instance].cb))
307 andreas 5223
        return true;
5224
 
5225
    // The border was not found or defined to be not drawn. Therefor we look
5226
    // into the system directory (__system/graphics/borders). If the wanted
5227
    // border exists there, we're drawing it.
160 andreas 5228
    BORDER_t bd, bda;
307 andreas 5229
    int numBorders = 0;
5230
    bool extBorder = false;
81 andreas 5231
 
307 andreas 5232
    string borderName1 = (bs.empty() ? sr[instance].bs : bs);
5233
    string borderName2 = (!bs.empty() && !sr[instance].bs.empty() ? sr[instance].bs : bs);
5234
 
317 andreas 5235
//    if (bs.empty())
5236
//    {
5237
        if (gPageManager->getSystemDraw()->getBorder(bname, TSystemDraw::LT_OFF, &bd))
307 andreas 5238
            numBorders++;
169 andreas 5239
 
317 andreas 5240
        if (gPageManager->getSystemDraw()->getBorder(bname, TSystemDraw::LT_ON, &bda))
307 andreas 5241
            numBorders++;
79 andreas 5242
 
307 andreas 5243
        if (numBorders == 2)
5244
            extBorder = true;
317 andreas 5245
//    }
5246
//    else
5247
//    {
5248
//        if (gPageManager->getSystemDraw()->getBorder(bs, (instance == 0 ? TSystemDraw::LT_OFF : TSystemDraw::LT_ON), &bd, bname))
5249
//        {
5250
//            numBorders++;
5251
//            extBorder = true;
5252
//        }
5253
//    }
79 andreas 5254
 
307 andreas 5255
    if (extBorder)
5256
    {
5257
        MSG_DEBUG("System border \"" << borderName1 << "\" and \"" << borderName2 << "\" found.");
5258
        SkColor color = TColor::getSkiaColor(sr[instance].cb);      // border color
5259
        SkColor bgColor = TColor::getSkiaColor(sr[instance].cf);    // fill color
5260
        MSG_DEBUG("Button color: #" << std::setw(6) << std::setfill('0') << std::hex << color);
5261
        // Load images
5262
        SkBitmap imgB, imgBR, imgR, imgTR, imgT, imgTL, imgL, imgBL;
169 andreas 5263
 
307 andreas 5264
        imgB = retrieveBorderImage(bd.b, bda.b, color, bgColor);
169 andreas 5265
 
307 andreas 5266
        if (imgB.empty())
5267
            return false;
79 andreas 5268
 
307 andreas 5269
        MSG_DEBUG("Got images " << bd.b << " and " << bda.b << " with size " << imgB.info().width() << " x " << imgB.info().height());
5270
        imgBR = retrieveBorderImage(bd.br, bda.br, color, bgColor);
79 andreas 5271
 
307 andreas 5272
        if (imgBR.empty())
5273
            return false;
160 andreas 5274
 
307 andreas 5275
        MSG_DEBUG("Got images " << bd.br << " and " << bda.br << " with size " << imgBR.info().width() << " x " << imgBR.info().height());
5276
        imgR = retrieveBorderImage(bd.r, bda.r, color, bgColor);
160 andreas 5277
 
307 andreas 5278
        if (imgR.empty())
5279
            return false;
79 andreas 5280
 
307 andreas 5281
        MSG_DEBUG("Got images " << bd.r << " and " << bda.r << " with size " << imgR.info().width() << " x " << imgR.info().height());
5282
        imgTR = retrieveBorderImage(bd.tr, bda.tr, color, bgColor);
79 andreas 5283
 
307 andreas 5284
        if (imgTR.empty())
5285
            return false;
79 andreas 5286
 
307 andreas 5287
        MSG_DEBUG("Got images " << bd.tr << " and " << bda.tr << " with size " << imgTR.info().width() << " x " << imgTR.info().height());
5288
        imgT = retrieveBorderImage(bd.t, bda.t, color, bgColor);
79 andreas 5289
 
307 andreas 5290
        if (imgT.empty())
5291
            return false;
79 andreas 5292
 
307 andreas 5293
        MSG_DEBUG("Got images " << bd.t << " and " << bda.t << " with size " << imgT.info().width() << " x " << imgT.info().height());
5294
        imgTL = retrieveBorderImage(bd.tl, bda.tl, color, bgColor);
79 andreas 5295
 
307 andreas 5296
        if (imgTL.empty())
5297
            return false;
79 andreas 5298
 
307 andreas 5299
        MSG_DEBUG("Got images " << bd.tl << " and " << bda.tl << " with size " << imgTL.info().width() << " x " << imgTL.info().height());
5300
        imgL = retrieveBorderImage(bd.l, bda.l, color, bgColor);
79 andreas 5301
 
307 andreas 5302
        if (imgL.empty())
5303
            return false;
79 andreas 5304
 
307 andreas 5305
        mBorderWidth = imgL.info().width();
5306
        MSG_DEBUG("Got images " << bd.l << " and " << bda.l << " with size " << imgL.info().width() << " x " << imgL.info().height());
5307
        imgBL = retrieveBorderImage(bd.bl, bda.bl, color, bgColor);
79 andreas 5308
 
307 andreas 5309
        if (imgBL.empty())
5310
            return false;
79 andreas 5311
 
307 andreas 5312
        MSG_DEBUG("Got images " << bd.bl << " and " << bda.bl << " with size " << imgBL.info().width() << " x " << imgBL.info().height());
5313
        MSG_DEBUG("Button image size: " << (imgTL.info().width() + imgT.info().width() + imgTR.info().width()) << " x " << (imgTL.info().height() + imgL.info().height() + imgBL.info().height()));
5314
        MSG_DEBUG("Total size: " << wt << " x " << ht);
5315
        stretchImageWidth(&imgB, wt - imgBL.info().width() - imgBR.info().width());
5316
        stretchImageWidth(&imgT, wt - imgTL.info().width() - imgTR.info().width());
5317
        stretchImageHeight(&imgL, ht - imgTL.info().height() - imgBL.info().height());
5318
        stretchImageHeight(&imgR, ht - imgTR.info().height() - imgBR.info().height());
5319
        MSG_DEBUG("Stretched button image size: " << (imgTL.info().width() + imgT.info().width() + imgTR.info().width()) << " x " << (imgTL.info().height() + imgL.info().height() + imgBL.info().height()));
5320
        // Draw the frame
5321
        SkBitmap frame;
5322
        allocPixels(bm->info().width(), bm->info().height(), &frame);
5323
        frame.eraseColor(SK_ColorTRANSPARENT);
5324
//        SkCanvas target(*bm, SkSurfaceProps());
5325
        SkCanvas canvas(frame, SkSurfaceProps());
5326
        SkPaint paint;
79 andreas 5327
 
307 andreas 5328
        paint.setBlendMode(SkBlendMode::kSrcOver);
5329
        sk_sp<SkImage> _image = SkImage::MakeFromBitmap(imgB);
5330
        canvas.drawImage(_image, imgBL.info().width(), ht - imgB.info().height(), SkSamplingOptions(), &paint);
5331
        _image = SkImage::MakeFromBitmap(imgBR);
5332
        canvas.drawImage(_image, wt - imgBR.info().width(), ht - imgBR.info().height(), SkSamplingOptions(), &paint);
5333
        _image = SkImage::MakeFromBitmap(imgR);
5334
        canvas.drawImage(_image, wt - imgR.info().width(), imgTR.info().height(), SkSamplingOptions(), &paint);
5335
        _image = SkImage::MakeFromBitmap(imgTR);
5336
        canvas.drawImage(_image, wt - imgTR.info().width(), 0, SkSamplingOptions(), &paint);
5337
        _image = SkImage::MakeFromBitmap(imgT);
5338
        canvas.drawImage(_image, imgTL.info().width(), 0, SkSamplingOptions(), &paint);
5339
        _image = SkImage::MakeFromBitmap(imgTL);
5340
        canvas.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
5341
        _image = SkImage::MakeFromBitmap(imgL);
5342
        canvas.drawImage(_image, 0, imgTL.info().height(), SkSamplingOptions(), &paint);
5343
        _image = SkImage::MakeFromBitmap(imgBL);
5344
        canvas.drawImage(_image, 0, ht - imgBL.info().height(), SkSamplingOptions(), &paint);
79 andreas 5345
 
307 andreas 5346
        erasePart(bm, frame, Border::ERASE_OUTSIDE);
5347
//        _image = SkImage::MakeFromBitmap(frame);
5348
//        target.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
79 andreas 5349
    }
307 andreas 5350
    else    // We try to draw a frame by forcing it to draw even the not to draw marked frames.
317 andreas 5351
        drawBorder(bm, bname, wt, ht, sr[instance].cb, true);
79 andreas 5352
 
3 andreas 5353
    return true;
5354
}
5355
 
8 andreas 5356
int TButton::numberLines(const string& str)
5357
{
5358
    DECL_TRACER("TButton::numberLines(const string& str)");
5359
 
5360
    int lines = 1;
5361
 
96 andreas 5362
    if (str.empty())
8 andreas 5363
    {
96 andreas 5364
        MSG_DEBUG("Found an empty string.");
5365
        return lines;
5366
    }
5367
 
5368
    string::const_iterator iter;
5369
 
118 andreas 5370
    for (iter = str.begin(); iter != str.end(); ++iter)
96 andreas 5371
    {
5372
        if (*iter == '\n')
8 andreas 5373
            lines++;
5374
    }
5375
 
5376
    return lines;
5377
}
5378
 
5379
SkRect TButton::calcRect(int width, int height, int pen)
5380
{
5381
    DECL_TRACER("TButton::calcRect(int width, int height, int pen)");
5382
    SkRect rect;
5383
 
5384
    SkScalar left = (SkScalar)pen / 2.0;
5385
    SkScalar top = (SkScalar)pen / 2.0;
101 andreas 5386
    SkScalar w = (SkScalar)width - (SkScalar)pen;
5387
    SkScalar h = (SkScalar)height - (SkScalar)pen;
8 andreas 5388
    rect.setXYWH(left, top, w, h);
5389
    return rect;
5390
}
5391
 
15 andreas 5392
void TButton::runAnimation()
8 andreas 5393
{
15 andreas 5394
    DECL_TRACER("TButton::runAnimation()");
8 andreas 5395
 
43 andreas 5396
    if (mAniRunning)
5397
        return;
5398
 
15 andreas 5399
    mAniRunning = true;
5400
    int instance = 0;
5401
    int max = (int)sr.size();
38 andreas 5402
    ulong tm = nu * ru + nd * rd;
15 andreas 5403
 
93 andreas 5404
    while (mAniRunning && !mAniStop && !prg_stopped)
15 andreas 5405
    {
38 andreas 5406
        mActInstance = instance;
176 andreas 5407
        mChanged = true;
38 andreas 5408
 
101 andreas 5409
        if (visible && !drawButton(instance))
15 andreas 5410
            break;
5411
 
5412
        instance++;
5413
 
5414
        if (instance >= max)
5415
            instance = 0;
5416
 
5417
        std::this_thread::sleep_for(std::chrono::milliseconds(tm));
5418
    }
5419
 
5420
    mAniRunning = false;
5421
}
5422
 
38 andreas 5423
void TButton::runAnimationRange(int start, int end, ulong step)
5424
{
5425
    DECL_TRACER("TButton::runAnimationRange(int start, int end, ulong step)");
5426
 
93 andreas 5427
    if (mAniRunning)
5428
        return;
5429
 
38 andreas 5430
    mAniRunning = true;
320 andreas 5431
    int instance = start - 1;
38 andreas 5432
    int max = std::min(end, (int)sr.size());
5433
    std::chrono::steady_clock::time_point startt = std::chrono::steady_clock::now();
5434
 
93 andreas 5435
    while (mAniRunning && !mAniStop && !prg_stopped)
38 andreas 5436
    {
5437
        mActInstance = instance;
177 andreas 5438
        mChanged = true;
101 andreas 5439
 
5440
        if (visible)
5441
            drawButton(instance);   // We ignore the state and try to draw the next instance
5442
 
38 andreas 5443
        instance++;
5444
 
5445
        if (instance >= max)
320 andreas 5446
            instance = start - 1;
38 andreas 5447
 
5448
        std::this_thread::sleep_for(std::chrono::milliseconds(step));
5449
 
5450
        if (mAniRunTime > 0)
5451
        {
5452
            std::chrono::steady_clock::time_point current = std::chrono::steady_clock::now();
5453
            std::chrono::nanoseconds difftime = current - startt;
5454
            ulong duration = std::chrono::duration_cast<std::chrono::milliseconds>(difftime).count();
5455
 
5456
            if (duration >= mAniRunTime)
5457
                break;
5458
        }
5459
    }
5460
 
5461
    mAniRunTime = 0;
5462
    mAniRunning = false;
5463
}
5464
 
15 andreas 5465
bool TButton::drawButtonMultistateAni()
5466
{
101 andreas 5467
    DECL_TRACER("TButton::drawButtonMultistateAni()");
15 andreas 5468
 
33 andreas 5469
    if (prg_stopped)
5470
        return true;
35 andreas 5471
 
100 andreas 5472
    if (!visible || hd)    // Do nothing if this button is invisible
5473
        return true;
5474
 
15 andreas 5475
    if (mAniRunning || mThrAni.joinable())
5476
    {
23 andreas 5477
        MSG_TRACE("Animation is already running!");
15 andreas 5478
        return true;
5479
    }
5480
 
5481
    try
5482
    {
93 andreas 5483
        mAniStop = false;
15 andreas 5484
        mThrAni = thread([=] { runAnimation(); });
5485
        mThrAni.detach();
5486
    }
5487
    catch (exception& e)
5488
    {
5489
        MSG_ERROR("Error starting the button animation thread: " << e.what());
5490
        return false;
5491
    }
5492
 
5493
    return true;
5494
}
5495
 
300 andreas 5496
bool TButton::drawButton(int instance, bool show, bool subview)
15 andreas 5497
{
300 andreas 5498
    DECL_TRACER("TButton::drawButton(int instance, bool show, bool subview)");
15 andreas 5499
 
33 andreas 5500
    if (prg_stopped)
5501
        return false;
35 andreas 5502
 
300 andreas 5503
    if (subview)
5504
        mSubViewPart = subview;
5505
 
8 andreas 5506
    if ((size_t)instance >= sr.size() || instance < 0)
5507
    {
5508
        MSG_ERROR("Instance " << instance << " is out of bounds!");
5509
        TError::setError();
334 andreas 5510
#if TESTMODE == 1
5511
        setScreenDone();
5512
#endif
8 andreas 5513
        return false;
5514
    }
5515
 
26 andreas 5516
    if (!_displayButton && gPageManager)
5517
        _displayButton = gPageManager->getCallbackDB();
5518
 
100 andreas 5519
    if (!visible || hd || instance != mActInstance || !_displayButton)
14 andreas 5520
    {
15 andreas 5521
        bool db = (_displayButton != nullptr);
23 andreas 5522
        MSG_DEBUG("Button " << bi << ", \"" << na << "\" at instance " << instance << " is not to draw!");
150 andreas 5523
        MSG_DEBUG("Visible: " << (visible ? "YES" : "NO") << ", Hidden: " << (hd ? "YES" : "NO") << ", Instance/actual instance: " << instance << "/" << mActInstance << ", callback: " << (db ? "PRESENT" : "N/A"));
334 andreas 5524
#if TESTMODE == 1
5525
        setScreenDone();
5526
#endif
14 andreas 5527
        return true;
5528
    }
5529
 
137 andreas 5530
    MSG_DEBUG("Drawing button " << bi << ", \"" << na << "\" at instance " << instance);
176 andreas 5531
 
5532
    if (!mChanged && !mLastImage.empty())
5533
    {
289 andreas 5534
        if (show)
291 andreas 5535
        {
289 andreas 5536
            showLastButton();
5537
 
291 andreas 5538
            if (type == SUBPAGE_VIEW)
5539
            {
5540
                if (gPageManager)
5541
                    gPageManager->showSubViewList(st, this);
5542
            }
5543
        }
5544
 
176 andreas 5545
        return true;
5546
    }
5547
 
8 andreas 5548
    ulong parent = mHandle & 0xffff0000;
5549
    getDrawOrder(sr[instance]._do, (DRAW_ORDER *)&mDOrder);
5550
 
5551
    if (TError::isError())
334 andreas 5552
    {
5553
#if TESTMODE == 1
5554
        setScreenDone();
5555
#endif
8 andreas 5556
        return false;
334 andreas 5557
    }
8 andreas 5558
 
5559
    SkBitmap imgButton;
254 andreas 5560
 
5561
    if (!allocPixels(wt, ht, &imgButton))
334 andreas 5562
    {
5563
#if TESTMODE == 1
5564
        setScreenDone();
5565
#endif
254 andreas 5566
        return false;
334 andreas 5567
    }
254 andreas 5568
 
292 andreas 5569
    // We create an empty (transparent) image here. Later it depends on the
5570
    // draw order of the elements. If, for example, the back ground fill is
5571
    // not the first thing, we must be sure to not destroy already drawn
5572
    // elemts of the button.
5573
    imgButton.eraseColor(SkColors::kTransparent);
97 andreas 5574
    bool dynState = false;
8 andreas 5575
 
5576
    for (int i = 0; i < ORD_ELEM_COUNT; i++)
5577
    {
5578
        if (mDOrder[i] == ORD_ELEM_FILL)
5579
        {
5580
            if (!buttonFill(&imgButton, instance))
334 andreas 5581
            {
5582
#if TESTMODE == 1
5583
                setScreenDone();
5584
#endif
8 andreas 5585
                return false;
334 andreas 5586
            }
8 andreas 5587
        }
5588
        else if (mDOrder[i] == ORD_ELEM_BITMAP)
5589
        {
21 andreas 5590
            if (!sr[instance].dynamic && !buttonBitmap(&imgButton, instance))
334 andreas 5591
            {
5592
#if TESTMODE == 1
5593
                setScreenDone();
5594
#endif
8 andreas 5595
                return false;
334 andreas 5596
            }
97 andreas 5597
            else if (sr[instance].dynamic && !buttonDynamic(&imgButton, instance, show, &dynState))
334 andreas 5598
            {
5599
#if TESTMODE == 1
5600
                setScreenDone();
5601
#endif
21 andreas 5602
                return false;
334 andreas 5603
            }
8 andreas 5604
        }
5605
        else if (mDOrder[i] == ORD_ELEM_ICON)
5606
        {
5607
            if (!buttonIcon(&imgButton, instance))
334 andreas 5608
            {
5609
#if TESTMODE == 1
5610
                setScreenDone();
5611
#endif
8 andreas 5612
                return false;
334 andreas 5613
            }
8 andreas 5614
        }
5615
        else if (mDOrder[i] == ORD_ELEM_TEXT)
5616
        {
5617
            if (!buttonText(&imgButton, instance))
334 andreas 5618
            {
5619
#if TESTMODE == 1
5620
                setScreenDone();
5621
#endif
8 andreas 5622
                return false;
334 andreas 5623
            }
8 andreas 5624
        }
5625
        else if (mDOrder[i] == ORD_ELEM_BORDER)
5626
        {
5627
            if (!buttonBorder(&imgButton, instance))
334 andreas 5628
            {
5629
#if TESTMODE == 1
5630
                setScreenDone();
5631
#endif
8 andreas 5632
                return false;
334 andreas 5633
            }
8 andreas 5634
        }
5635
    }
5636
 
10 andreas 5637
    if (mGlobalOO >= 0 || sr[instance].oo >= 0) // Take overall opacity into consideration
5638
    {
5639
        SkBitmap ooButton;
5640
        int w = imgButton.width();
5641
        int h = imgButton.height();
254 andreas 5642
 
5643
        if (!allocPixels(w, h, &ooButton))
334 andreas 5644
        {
5645
#if TESTMODE == 1
5646
            setScreenDone();
5647
#endif
254 andreas 5648
            return false;
334 andreas 5649
        }
254 andreas 5650
 
10 andreas 5651
        SkCanvas canvas(ooButton);
5652
        SkIRect irect = SkIRect::MakeXYWH(0, 0, w, h);
5653
        SkRegion region;
5654
        region.setRect(irect);
5655
        SkScalar oo;
5656
 
5657
        if (mGlobalOO >= 0 && sr[instance].oo >= 0)
5658
        {
5659
            oo = std::min((SkScalar)mGlobalOO, (SkScalar)sr[instance].oo);
5660
            MSG_DEBUG("Set global overal opacity to " << oo);
5661
        }
5662
        else if (sr[instance].oo >= 0)
5663
        {
5664
            oo = (SkScalar)sr[instance].oo;
5665
            MSG_DEBUG("Set overal opacity to " << oo);
5666
        }
5667
        else
5668
        {
5669
            oo = (SkScalar)mGlobalOO;
5670
            MSG_DEBUG("Set global overal opacity to " << oo);
5671
        }
5672
 
5673
        SkScalar alpha = 1.0 / 255.0 * oo;
5674
        MSG_DEBUG("Calculated alpha value: " << alpha);
5675
        SkPaint paint;
5676
        paint.setAlphaf(alpha);
5677
        paint.setImageFilter(SkImageFilters::AlphaThreshold(region, 0.0, alpha, nullptr));
179 andreas 5678
        sk_sp<SkImage> _image = SkImage::MakeFromBitmap(imgButton);
5679
        canvas.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
10 andreas 5680
        imgButton.erase(SK_ColorTRANSPARENT, {0, 0, w, h});
5681
        imgButton = ooButton;
5682
    }
5683
 
15 andreas 5684
    mLastImage = imgButton;
177 andreas 5685
    mChanged = false;
8 andreas 5686
 
97 andreas 5687
    if (!prg_stopped && !dynState)
26 andreas 5688
    {
5689
        int rwidth = wt;
5690
        int rheight = ht;
5691
        int rleft = lt;
5692
        int rtop = tp;
43 andreas 5693
#ifdef _SCALE_SKIA_
26 andreas 5694
        if (gPageManager && gPageManager->getScaleFactor() != 1.0)
5695
        {
5696
            rwidth = (int)((double)wt * gPageManager->getScaleFactor());
5697
            rheight = (int)((double)ht * gPageManager->getScaleFactor());
5698
            rleft = (int)((double)lt * gPageManager->getScaleFactor());
5699
            rtop = (int)((double)tp * gPageManager->getScaleFactor());
5700
 
5701
            SkPaint paint;
5702
            paint.setBlendMode(SkBlendMode::kSrc);
5703
            paint.setFilterQuality(kHigh_SkFilterQuality);
28 andreas 5704
            // Calculate new dimension
26 andreas 5705
            SkImageInfo info = imgButton.info();
5706
            int width = (int)((double)info.width() * gPageManager->getScaleFactor());
5707
            int height = (int)((double)info.height() * gPageManager->getScaleFactor());
28 andreas 5708
            // Create a canvas and draw new image
5709
            sk_sp<SkImage> im = SkImage::MakeFromBitmap(imgButton);
5710
            imgButton.allocN32Pixels(width, height);
5711
            imgButton.eraseColor(SK_ColorTRANSPARENT);
254 andreas 5712
            SkCanvas can(imgButton, SkSurfaceProps());
26 andreas 5713
            SkRect rect = SkRect::MakeXYWH(0, 0, width, height);
179 andreas 5714
            can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
28 andreas 5715
            rowBytes = imgButton.info().minRowBytes();
5716
            mLastImage = imgButton;
26 andreas 5717
        }
43 andreas 5718
#endif
31 andreas 5719
        if (show)
176 andreas 5720
        {
283 andreas 5721
            MSG_DEBUG("Button type: " << buttonTypeToString());
5722
 
300 andreas 5723
            if (type != SUBPAGE_VIEW && !mSubViewPart)
293 andreas 5724
            {
5725
                TBitmap image((unsigned char *)imgButton.getPixels(), imgButton.info().width(), imgButton.info().height());
298 andreas 5726
                _displayButton(mHandle, parent, image, rwidth, rheight, rleft, rtop, isPassThrough());
293 andreas 5727
            }
300 andreas 5728
            else if (type != SUBPAGE_VIEW && mSubViewPart)
5729
            {
5730
                if (gPageManager)
5731
                    gPageManager->updateSubViewItem(this);
5732
            }
176 andreas 5733
        }
26 andreas 5734
    }
5735
 
293 andreas 5736
    if (!prg_stopped && type == SUBPAGE_VIEW && show)
279 andreas 5737
    {
5738
        if (gPageManager)
280 andreas 5739
            gPageManager->showSubViewList(st, this);
279 andreas 5740
    }
5741
 
8 andreas 5742
    return true;
5743
}
5744
 
50 andreas 5745
bool TButton::drawTextArea(int instance)
5746
{
192 andreas 5747
    DECL_TRACER("TButton::drawTextArea(int instance)");
50 andreas 5748
 
5749
    if (prg_stopped)
334 andreas 5750
    {
5751
#if TESTMODE == 1
5752
        setScreenDone();
5753
#endif
50 andreas 5754
        return false;
334 andreas 5755
    }
50 andreas 5756
 
100 andreas 5757
    if (!visible || hd)
334 andreas 5758
    {
5759
#if TESTMODE == 1
5760
        setScreenDone();
5761
#endif
100 andreas 5762
        return true;
334 andreas 5763
    }
100 andreas 5764
 
50 andreas 5765
    if ((size_t)instance >= sr.size() || instance < 0)
5766
    {
5767
        MSG_ERROR("Instance " << instance << " is out of bounds!");
5768
        TError::setError();
334 andreas 5769
#if TESTMODE == 1
5770
        setScreenDone();
5771
#endif
50 andreas 5772
        return false;
5773
    }
5774
 
176 andreas 5775
    if (!mChanged)
5776
    {
5777
        showLastButton();
5778
        return true;
5779
    }
5780
 
50 andreas 5781
    getDrawOrder(sr[instance]._do, (DRAW_ORDER *)&mDOrder);
5782
 
5783
    if (TError::isError())
334 andreas 5784
    {
5785
#if TESTMODE == 1
5786
        setScreenDone();
5787
#endif
50 andreas 5788
        return false;
334 andreas 5789
    }
50 andreas 5790
 
5791
    SkBitmap imgButton;
5792
 
254 andreas 5793
    if (!allocPixels(wt, ht, &imgButton))
334 andreas 5794
    {
5795
#if TESTMODE == 1
5796
        setScreenDone();
5797
#endif
254 andreas 5798
        return false;
334 andreas 5799
    }
254 andreas 5800
 
50 andreas 5801
    for (int i = 0; i < ORD_ELEM_COUNT; i++)
5802
    {
5803
        if (mDOrder[i] == ORD_ELEM_FILL)
5804
        {
5805
            if (!buttonFill(&imgButton, instance))
334 andreas 5806
            {
5807
#if TESTMODE == 1
5808
                setScreenDone();
5809
#endif
50 andreas 5810
                return false;
334 andreas 5811
            }
50 andreas 5812
        }
5813
        else if (mDOrder[i] == ORD_ELEM_BITMAP)
5814
        {
5815
            if (!sr[instance].dynamic && !buttonBitmap(&imgButton, instance))
334 andreas 5816
            {
5817
#if TESTMODE == 1
5818
                setScreenDone();
5819
#endif
50 andreas 5820
                return false;
334 andreas 5821
            }
97 andreas 5822
            else if (sr[instance].dynamic && !buttonDynamic(&imgButton, instance, false))
334 andreas 5823
            {
5824
#if TESTMODE == 1
5825
                setScreenDone();
5826
#endif
50 andreas 5827
                return false;
334 andreas 5828
            }
50 andreas 5829
        }
5830
        else if (mDOrder[i] == ORD_ELEM_ICON)
5831
        {
5832
            if (!buttonIcon(&imgButton, instance))
334 andreas 5833
            {
5834
#if TESTMODE == 1
5835
                setScreenDone();
5836
#endif
50 andreas 5837
                return false;
334 andreas 5838
            }
50 andreas 5839
        }
5840
        else if (mDOrder[i] == ORD_ELEM_BORDER)
5841
        {
5842
            if (!buttonBorder(&imgButton, instance))
334 andreas 5843
            {
5844
#if TESTMODE == 1
5845
                setScreenDone();
5846
#endif
50 andreas 5847
                return false;
334 andreas 5848
            }
50 andreas 5849
        }
5850
    }
5851
 
5852
    if (mGlobalOO >= 0 || sr[instance].oo >= 0) // Take overall opacity into consideration
5853
    {
5854
        SkBitmap ooButton;
5855
        int w = imgButton.width();
5856
        int h = imgButton.height();
254 andreas 5857
 
5858
        if (!allocPixels(w, h, &ooButton))
334 andreas 5859
        {
5860
#if TESTMODE == 1
5861
            setScreenDone();
5862
#endif
254 andreas 5863
            return false;
334 andreas 5864
        }
254 andreas 5865
 
50 andreas 5866
        SkCanvas canvas(ooButton);
5867
        SkIRect irect = SkIRect::MakeXYWH(0, 0, w, h);
5868
        SkRegion region;
5869
        region.setRect(irect);
5870
        SkScalar oo;
5871
 
5872
        if (mGlobalOO >= 0 && sr[instance].oo >= 0)
5873
        {
5874
            oo = std::min((SkScalar)mGlobalOO, (SkScalar)sr[instance].oo);
5875
            MSG_DEBUG("Set global overal opacity to " << oo);
5876
        }
5877
        else if (sr[instance].oo >= 0)
5878
        {
5879
            oo = (SkScalar)sr[instance].oo;
5880
            MSG_DEBUG("Set overal opacity to " << oo);
5881
        }
5882
        else
5883
        {
5884
            oo = (SkScalar)mGlobalOO;
5885
            MSG_DEBUG("Set global overal opacity to " << oo);
5886
        }
5887
 
5888
        SkScalar alpha = 1.0 / 255.0 * oo;
5889
        MSG_DEBUG("Calculated alpha value: " << alpha);
5890
        SkPaint paint;
5891
        paint.setAlphaf(alpha);
5892
        paint.setImageFilter(SkImageFilters::AlphaThreshold(region, 0.0, alpha, nullptr));
179 andreas 5893
        sk_sp<SkImage> _image = SkImage::MakeFromBitmap(imgButton);
5894
        canvas.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
50 andreas 5895
        imgButton.erase(SK_ColorTRANSPARENT, {0, 0, w, h});
5896
        imgButton = ooButton;
5897
    }
5898
 
5899
    mLastImage = imgButton;
177 andreas 5900
    mChanged = false;
50 andreas 5901
 
52 andreas 5902
    if (!prg_stopped)
50 andreas 5903
    {
5904
        int rwidth = wt;
5905
        int rheight = ht;
5906
        int rleft = lt;
5907
        int rtop = tp;
5908
        size_t rowBytes = imgButton.info().minRowBytes();
52 andreas 5909
#ifdef _SCALE_SKIA_
5910
        if (gPageManager && gPageManager->getScaleFactor() != 1.0)
5911
        {
5912
            size_t rowBytes = imgButton.info().minRowBytes();
5913
            rwidth = (int)((double)wt * gPageManager->getScaleFactor());
5914
            rheight = (int)((double)ht * gPageManager->getScaleFactor());
5915
            rleft = (int)((double)lt * gPageManager->getScaleFactor());
5916
            rtop = (int)((double)tp * gPageManager->getScaleFactor());
50 andreas 5917
 
52 andreas 5918
            SkPaint paint;
5919
            paint.setBlendMode(SkBlendMode::kSrc);
5920
            paint.setFilterQuality(kHigh_SkFilterQuality);
5921
            // Calculate new dimension
5922
            SkImageInfo info = imgButton.info();
5923
            int width = (int)((double)info.width() * gPageManager->getScaleFactor());
5924
            int height = (int)((double)info.height() * gPageManager->getScaleFactor());
5925
            // Create a canvas and draw new image
5926
            sk_sp<SkImage> im = SkImage::MakeFromBitmap(imgButton);
5927
            imgButton.allocN32Pixels(width, height);
5928
            imgButton.eraseColor(SK_ColorTRANSPARENT);
254 andreas 5929
            SkCanvas can(imgButton, SkSurfaceProps());
52 andreas 5930
            SkRect rect = SkRect::MakeXYWH(0, 0, width, height);
179 andreas 5931
            can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
52 andreas 5932
            rowBytes = imgButton.info().minRowBytes();
5933
            mLastImage = imgButton;
5934
        }
5935
#endif
5936
        if (gPageManager && gPageManager->getCallbackInputText())
5937
        {
5938
            BITMAP_t bm;
5939
            bm.buffer = (unsigned char *)imgButton.getPixels();
5940
            bm.rowBytes = rowBytes;
5941
            bm.left = rleft;
5942
            bm.top = rtop;
5943
            bm.width = rwidth;
5944
            bm.height = rheight;
291 andreas 5945
            gPageManager->getCallbackInputText()(this, bm, mBorderWidth);
52 andreas 5946
        }
50 andreas 5947
    }
5948
 
5949
    return true;
5950
}
5951
 
38 andreas 5952
bool TButton::drawMultistateBargraph(int level, bool show)
5953
{
5954
    mutex_button.lock();
5955
    DECL_TRACER("TButton::drawMultistateBargraph(int level, bool show)");
5956
 
5957
    if (prg_stopped)
5958
    {
334 andreas 5959
#if TESTMODE == 1
5960
        setScreenDone();
5961
#endif
38 andreas 5962
        mutex_button.unlock();
5963
        return false;
5964
    }
5965
 
5966
    if (!_displayButton && gPageManager)
5967
        _displayButton = gPageManager->getCallbackDB();
5968
 
100 andreas 5969
    if (!visible || hd || !_displayButton)
38 andreas 5970
    {
5971
        bool db = (_displayButton != nullptr);
5972
        MSG_DEBUG("Multistate bargraph " << bi << ", \"" << na << " is not to draw!");
5973
        MSG_DEBUG("Visible: " << (visible ? "YES" : "NO") << ", callback: " << (db ? "PRESENT" : "N/A"));
334 andreas 5974
#if TESTMODE == 1
5975
        setScreenDone();
5976
#endif
38 andreas 5977
        mutex_button.unlock();
5978
        return true;
5979
    }
5980
 
5981
    int maxLevel = level;
5982
 
268 andreas 5983
    if (maxLevel > rh)
5984
        maxLevel = rh;
5985
    else if (maxLevel < rl)
5986
        maxLevel = rl;
45 andreas 5987
    else if (maxLevel < 0)
268 andreas 5988
        maxLevel = rl;
38 andreas 5989
 
46 andreas 5990
    MSG_DEBUG("Display instance " << maxLevel);
38 andreas 5991
    ulong parent = mHandle & 0xffff0000;
5992
    getDrawOrder(sr[maxLevel]._do, (DRAW_ORDER *)&mDOrder);
5993
 
5994
    if (TError::isError())
5995
    {
334 andreas 5996
#if TESTMODE == 1
5997
        setScreenDone();
5998
#endif
38 andreas 5999
        mutex_button.unlock();
6000
        return false;
6001
    }
6002
 
6003
    SkBitmap imgButton;
6004
 
254 andreas 6005
    if (!allocPixels(wt, ht, &imgButton))
334 andreas 6006
    {
6007
#if TESTMODE == 1
6008
        setScreenDone();
6009
#endif
254 andreas 6010
        return false;
334 andreas 6011
    }
254 andreas 6012
 
38 andreas 6013
    for (int i = 0; i < ORD_ELEM_COUNT; i++)
6014
    {
6015
        if (mDOrder[i] == ORD_ELEM_FILL)
6016
        {
6017
            if (!buttonFill(&imgButton, maxLevel))
6018
            {
334 andreas 6019
#if TESTMODE == 1
6020
                setScreenDone();
6021
#endif
38 andreas 6022
                mutex_button.unlock();
6023
                return false;
6024
            }
6025
        }
6026
        else if (mDOrder[i] == ORD_ELEM_BITMAP)
6027
        {
6028
            if (!buttonBitmap(&imgButton, maxLevel))
6029
            {
334 andreas 6030
#if TESTMODE == 1
6031
                setScreenDone();
6032
#endif
38 andreas 6033
                mutex_button.unlock();
6034
                return false;
6035
            }
6036
        }
6037
        else if (mDOrder[i] == ORD_ELEM_ICON)
6038
        {
6039
            if (!buttonIcon(&imgButton, maxLevel))
6040
            {
334 andreas 6041
#if TESTMODE == 1
6042
                setScreenDone();
6043
#endif
38 andreas 6044
                mutex_button.unlock();
6045
                return false;
6046
            }
6047
        }
6048
        else if (mDOrder[i] == ORD_ELEM_TEXT)
6049
        {
6050
            if (!buttonText(&imgButton, maxLevel))
6051
            {
334 andreas 6052
#if TESTMODE == 1
6053
                setScreenDone();
6054
#endif
38 andreas 6055
                mutex_button.unlock();
6056
                return false;
6057
            }
6058
        }
6059
        else if (mDOrder[i] == ORD_ELEM_BORDER)
6060
        {
6061
            if (!buttonBorder(&imgButton, maxLevel))
6062
            {
334 andreas 6063
#if TESTMODE == 1
6064
                setScreenDone();
6065
#endif
38 andreas 6066
                mutex_button.unlock();
6067
                return false;
6068
            }
6069
        }
6070
    }
6071
 
6072
    if (mGlobalOO >= 0 || sr[maxLevel].oo >= 0) // Take overall opacity into consideration
6073
    {
6074
        SkBitmap ooButton;
6075
        int w = imgButton.width();
6076
        int h = imgButton.height();
254 andreas 6077
 
6078
        if (!allocPixels(w, h, &ooButton))
334 andreas 6079
        {
6080
#if TESTMODE == 1
6081
            setScreenDone();
6082
#endif
254 andreas 6083
            return false;
334 andreas 6084
        }
254 andreas 6085
 
38 andreas 6086
        SkCanvas canvas(ooButton);
6087
        SkIRect irect = SkIRect::MakeXYWH(0, 0, w, h);
6088
        SkRegion region;
6089
        region.setRect(irect);
6090
        SkScalar oo;
6091
 
6092
        if (mGlobalOO >= 0 && sr[maxLevel].oo >= 0)
6093
        {
6094
            oo = std::min((SkScalar)mGlobalOO, (SkScalar)sr[maxLevel].oo);
6095
            MSG_DEBUG("Set global overal opacity to " << oo);
6096
        }
6097
        else if (sr[maxLevel].oo >= 0)
6098
        {
6099
            oo = (SkScalar)sr[maxLevel].oo;
6100
            MSG_DEBUG("Set overal opacity to " << oo);
6101
        }
6102
        else
6103
        {
6104
            oo = (SkScalar)mGlobalOO;
6105
            MSG_DEBUG("Set global overal opacity to " << oo);
6106
        }
6107
 
6108
        SkScalar alpha = 1.0 / 255.0 * oo;
6109
        MSG_DEBUG("Calculated alpha value: " << alpha);
6110
        SkPaint paint;
6111
        paint.setAlphaf(alpha);
6112
        paint.setImageFilter(SkImageFilters::AlphaThreshold(region, 0.0, alpha, nullptr));
179 andreas 6113
        sk_sp<SkImage> _image = SkImage::MakeFromBitmap(imgButton);
6114
        canvas.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
38 andreas 6115
        imgButton.erase(SK_ColorTRANSPARENT, {0, 0, w, h});
6116
        imgButton = ooButton;
6117
    }
6118
 
6119
    mLastImage = imgButton;
177 andreas 6120
    mChanged = false;
38 andreas 6121
 
6122
    if (!prg_stopped)
6123
    {
6124
        int rwidth = wt;
6125
        int rheight = ht;
6126
        int rleft = lt;
6127
        int rtop = tp;
43 andreas 6128
#ifdef _SCALE_SKIA_
38 andreas 6129
        if (gPageManager && gPageManager->getScaleFactor() != 1.0)
6130
        {
6131
            rwidth = (int)((double)wt * gPageManager->getScaleFactor());
6132
            rheight = (int)((double)ht * gPageManager->getScaleFactor());
6133
            rleft = (int)((double)lt * gPageManager->getScaleFactor());
6134
            rtop = (int)((double)tp * gPageManager->getScaleFactor());
6135
 
6136
            SkPaint paint;
6137
            paint.setBlendMode(SkBlendMode::kSrc);
6138
            paint.setFilterQuality(kHigh_SkFilterQuality);
6139
            // Calculate new dimension
6140
            SkImageInfo info = imgButton.info();
6141
            int width = (int)((double)info.width() * gPageManager->getScaleFactor());
6142
            int height = (int)((double)info.height() * gPageManager->getScaleFactor());
6143
            MSG_DEBUG("Button dimension: " << width << " x " << height);
6144
            // Create a canvas and draw new image
6145
            sk_sp<SkImage> im = SkImage::MakeFromBitmap(imgButton);
6146
            imgButton.allocN32Pixels(width, height);
6147
            imgButton.eraseColor(SK_ColorTRANSPARENT);
254 andreas 6148
            SkCanvas can(imgButton, SkSurfaceProps());
38 andreas 6149
            SkRect rect = SkRect::MakeXYWH(0, 0, width, height);
179 andreas 6150
            can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
38 andreas 6151
            MSG_DEBUG("Old rowBytes: " << rowBytes);
6152
            rowBytes = imgButton.info().minRowBytes();
6153
            MSG_DEBUG("New rowBytes: " << rowBytes);
6154
            mLastImage = imgButton;
6155
        }
43 andreas 6156
#endif
38 andreas 6157
        if (show)
289 andreas 6158
        {
6159
            TBitmap image((unsigned char *)imgButton.getPixels(), imgButton.info().width(), imgButton.info().height());
298 andreas 6160
            _displayButton(mHandle, parent, image, rwidth, rheight, rleft, rtop, isPassThrough());
289 andreas 6161
        }
334 andreas 6162
#if TESTMODE == 1
6163
        else
6164
            setScreenDone();
6165
#endif
38 andreas 6166
    }
6167
 
6168
    mutex_button.unlock();
6169
    return true;
6170
}
6171
 
200 andreas 6172
bool TButton::drawList(bool show)
6173
{
6174
    DECL_TRACER("TButton::drawList(bool show)");
6175
 
6176
    if (!mChanged)
6177
    {
6178
        showLastButton();
6179
        return true;
6180
    }
6181
 
6182
    getDrawOrder(sr[0]._do, (DRAW_ORDER *)&mDOrder);
6183
 
6184
    if (TError::isError())
6185
        return false;
6186
 
6187
    SkBitmap imgButton;
6188
 
254 andreas 6189
    if (!allocPixels(wt, ht, &imgButton))
6190
        return false;
6191
 
200 andreas 6192
    for (int i = 0; i < ORD_ELEM_COUNT; i++)
6193
    {
6194
        if (mDOrder[i] == ORD_ELEM_FILL)
6195
        {
6196
            if (!buttonFill(&imgButton, 0))
6197
                return false;
6198
        }
6199
        else if (mDOrder[i] == ORD_ELEM_BITMAP)
6200
        {
6201
            if (!sr[0].dynamic && !buttonBitmap(&imgButton, 0))
6202
                return false;
6203
            else if (sr[0].dynamic && !buttonDynamic(&imgButton, 0, false))
6204
                return false;
6205
        }
6206
        else if (mDOrder[i] == ORD_ELEM_ICON)
6207
        {
6208
            if (!buttonIcon(&imgButton, 0))
6209
                return false;
6210
        }
6211
        else if (mDOrder[i] == ORD_ELEM_BORDER)
6212
        {
6213
            if (!buttonBorder(&imgButton, 0))
6214
                return false;
6215
        }
6216
    }
6217
 
6218
    if (mGlobalOO >= 0 || sr[0].oo >= 0) // Take overall opacity into consideration
6219
    {
6220
        SkBitmap ooButton;
6221
        int w = imgButton.width();
6222
        int h = imgButton.height();
254 andreas 6223
 
6224
        if (!allocPixels(w, h, &ooButton))
6225
            return false;
6226
 
200 andreas 6227
        SkCanvas canvas(ooButton);
6228
        SkIRect irect = SkIRect::MakeXYWH(0, 0, w, h);
6229
        SkRegion region;
6230
        region.setRect(irect);
6231
        SkScalar oo;
6232
 
6233
        if (mGlobalOO >= 0 && sr[0].oo >= 0)
6234
        {
6235
            oo = std::min((SkScalar)mGlobalOO, (SkScalar)sr[0].oo);
6236
            MSG_DEBUG("Set global overal opacity to " << oo);
6237
        }
6238
        else if (sr[0].oo >= 0)
6239
        {
6240
            oo = (SkScalar)sr[0].oo;
6241
            MSG_DEBUG("Set overal opacity to " << oo);
6242
        }
6243
        else
6244
        {
6245
            oo = (SkScalar)mGlobalOO;
6246
            MSG_DEBUG("Set global overal opacity to " << oo);
6247
        }
6248
 
6249
        SkScalar alpha = 1.0 / 255.0 * oo;
6250
        MSG_DEBUG("Calculated alpha value: " << alpha);
6251
        SkPaint paint;
6252
        paint.setAlphaf(alpha);
6253
        paint.setImageFilter(SkImageFilters::AlphaThreshold(region, 0.0, alpha, nullptr));
6254
        sk_sp<SkImage> _image = SkImage::MakeFromBitmap(imgButton);
6255
        canvas.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
6256
        imgButton.erase(SK_ColorTRANSPARENT, {0, 0, w, h});
6257
        imgButton = ooButton;
6258
    }
6259
 
6260
    mLastImage = imgButton;
6261
    mChanged = false;
6262
 
6263
    if (!prg_stopped)
6264
    {
6265
        int rwidth = wt;
6266
        int rheight = ht;
6267
        int rleft = lt;
6268
        int rtop = tp;
6269
        size_t rowBytes = imgButton.info().minRowBytes();
6270
#ifdef _SCALE_SKIA_
6271
        if (gPageManager && gPageManager->getScaleFactor() != 1.0)
6272
        {
6273
            size_t rowBytes = imgButton.info().minRowBytes();
6274
            rwidth = (int)((double)wt * gPageManager->getScaleFactor());
6275
            rheight = (int)((double)ht * gPageManager->getScaleFactor());
6276
            rleft = (int)((double)lt * gPageManager->getScaleFactor());
6277
            rtop = (int)((double)tp * gPageManager->getScaleFactor());
6278
 
6279
            SkPaint paint;
6280
            paint.setBlendMode(SkBlendMode::kSrc);
6281
            paint.setFilterQuality(kHigh_SkFilterQuality);
6282
            // Calculate new dimension
6283
            SkImageInfo info = imgButton.info();
6284
            int width = (int)((double)info.width() * gPageManager->getScaleFactor());
6285
            int height = (int)((double)info.height() * gPageManager->getScaleFactor());
6286
            // Create a canvas and draw new image
6287
            sk_sp<SkImage> im = SkImage::MakeFromBitmap(imgButton);
6288
            imgButton.allocN32Pixels(width, height);
6289
            imgButton.eraseColor(SK_ColorTRANSPARENT);
254 andreas 6290
            SkCanvas can(imgButton, SkSurfaceProps());
200 andreas 6291
            SkRect rect = SkRect::MakeXYWH(0, 0, width, height);
6292
            can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
6293
            rowBytes = imgButton.info().minRowBytes();
6294
            mLastImage = imgButton;
6295
        }
6296
#endif
6297
        if (show && gPageManager && gPageManager->getCallbackListBox())
6298
        {
6299
            BITMAP_t bm;
6300
            bm.buffer = (unsigned char *)imgButton.getPixels();
6301
            bm.rowBytes = rowBytes;
6302
            bm.left = rleft;
6303
            bm.top = rtop;
6304
            bm.width = rwidth;
6305
            bm.height = rheight;
291 andreas 6306
            gPageManager->getCallbackListBox()(this, bm, mBorderWidth);
200 andreas 6307
        }
6308
    }
6309
 
6310
    return true;
6311
}
6312
 
15 andreas 6313
bool TButton::drawBargraph(int instance, int level, bool show)
6314
{
177 andreas 6315
    DECL_TRACER("TButton::drawBargraph(int instance, int level, bool show)");
15 andreas 6316
 
6317
    if ((size_t)instance >= sr.size() || instance < 0)
6318
    {
6319
        MSG_ERROR("Instance " << instance << " is out of bounds!");
6320
        TError::setError();
6321
        return false;
6322
    }
6323
 
38 andreas 6324
    if (!_displayButton && gPageManager)
6325
        _displayButton = gPageManager->getCallbackDB();
6326
 
176 andreas 6327
    if (!mChanged && mLastLevel == level)
6328
    {
6329
        showLastButton();
6330
        return true;
6331
    }
6332
 
318 andreas 6333
    TTRYLOCK(mutex_bargraph);
6334
 
15 andreas 6335
    if (level < rl)
6336
        mLastLevel = rl;
6337
    else if (level > rh)
6338
        mLastLevel = rh;
6339
    else
6340
        mLastLevel = level;
6341
 
38 andreas 6342
    int inst = instance;
6343
 
100 andreas 6344
    if (!visible || hd || instance != mActInstance || !_displayButton)
15 andreas 6345
    {
6346
        bool db = (_displayButton != nullptr);
23 andreas 6347
        MSG_DEBUG("Bargraph " << bi << ", \"" << na << "\" at instance " << instance << " with level " << mLastLevel << " is not to draw!");
15 andreas 6348
        MSG_DEBUG("Visible: " << (visible ? "YES" : "NO") << ", Instance/actual instance: " << instance << "/" << mActInstance << ", callback: " << (db ? "PRESENT" : "N/A"));
6349
        return true;
6350
    }
6351
 
6352
    ulong parent = mHandle & 0xffff0000;
35 andreas 6353
 
20 andreas 6354
    if (type == BARGRAPH)
38 andreas 6355
    {
20 andreas 6356
        getDrawOrder(sr[1]._do, (DRAW_ORDER *)&mDOrder);
38 andreas 6357
        inst = 1;
6358
    }
20 andreas 6359
    else
6360
        getDrawOrder(sr[instance]._do, (DRAW_ORDER *)&mDOrder);
35 andreas 6361
 
15 andreas 6362
    if (TError::isError())
6363
        return false;
6364
 
6365
    SkBitmap imgButton;
254 andreas 6366
 
6367
    if (!allocPixels(wt, ht, &imgButton))
6368
        return false;
6369
 
38 andreas 6370
    imgButton.eraseColor(TColor::getSkiaColor(sr[0].cf));
6371
    bool haveFrame = false;
15 andreas 6372
 
6373
    for (int i = 0; i < ORD_ELEM_COUNT; i++)
6374
    {
38 andreas 6375
        if (mDOrder[i] == ORD_ELEM_FILL && !haveFrame)
15 andreas 6376
        {
38 andreas 6377
            if (!buttonFill(&imgButton, (type == BARGRAPH ? 0 : inst)))
15 andreas 6378
                return false;
6379
        }
6380
        else if (mDOrder[i] == ORD_ELEM_BITMAP)
6381
        {
38 andreas 6382
            if (!barLevel(&imgButton, inst, mLastLevel))
15 andreas 6383
                return false;
6384
        }
6385
        else if (mDOrder[i] == ORD_ELEM_ICON)
6386
        {
38 andreas 6387
            if (!buttonIcon(&imgButton, inst))
15 andreas 6388
                return false;
6389
        }
6390
        else if (mDOrder[i] == ORD_ELEM_TEXT)
6391
        {
38 andreas 6392
            if (!buttonText(&imgButton, inst))
15 andreas 6393
                return false;
6394
        }
6395
        else if (mDOrder[i] == ORD_ELEM_BORDER)
6396
        {
38 andreas 6397
            if (!buttonBorder(&imgButton, (type == BARGRAPH ? 0 : inst)))
15 andreas 6398
                return false;
38 andreas 6399
 
6400
            haveFrame = true;
15 andreas 6401
        }
6402
    }
6403
 
38 andreas 6404
    if (mGlobalOO >= 0 || sr[inst].oo >= 0) // Take overall opacity into consideration
15 andreas 6405
    {
6406
        SkBitmap ooButton;
6407
        int w = imgButton.width();
6408
        int h = imgButton.height();
254 andreas 6409
 
6410
        if (!allocPixels(w, h, &ooButton))
6411
            return false;
6412
 
15 andreas 6413
        SkCanvas canvas(ooButton);
6414
        SkIRect irect = SkIRect::MakeXYWH(0, 0, w, h);
6415
        SkRegion region;
6416
        region.setRect(irect);
6417
        SkScalar oo;
6418
 
38 andreas 6419
        if (mGlobalOO >= 0 && sr[inst].oo >= 0)
15 andreas 6420
        {
38 andreas 6421
            oo = std::min((SkScalar)mGlobalOO, (SkScalar)sr[inst].oo);
15 andreas 6422
            MSG_DEBUG("Set global overal opacity to " << oo);
6423
        }
38 andreas 6424
        else if (sr[inst].oo >= 0)
15 andreas 6425
        {
38 andreas 6426
            oo = (SkScalar)sr[inst].oo;
15 andreas 6427
            MSG_DEBUG("Set overal opacity to " << oo);
6428
        }
6429
        else
6430
        {
6431
            oo = (SkScalar)mGlobalOO;
6432
            MSG_DEBUG("Set global overal opacity to " << oo);
6433
        }
6434
 
6435
        SkScalar alpha = 1.0 / 255.0 * oo;
6436
        MSG_DEBUG("Calculated alpha value: " << alpha);
6437
        SkPaint paint;
6438
        paint.setAlphaf(alpha);
6439
        paint.setImageFilter(SkImageFilters::AlphaThreshold(region, 0.0, alpha, nullptr));
179 andreas 6440
        sk_sp<SkImage> _image = SkImage::MakeFromBitmap(imgButton);
6441
        canvas.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
15 andreas 6442
        imgButton.erase(SK_ColorTRANSPARENT, {0, 0, w, h});
6443
        imgButton = ooButton;
6444
    }
6445
 
6446
    mLastImage = imgButton;
177 andreas 6447
    mChanged = false;
15 andreas 6448
 
21 andreas 6449
    if (!prg_stopped && show && visible && instance == mActInstance && _displayButton)
26 andreas 6450
    {
6451
        int rwidth = wt;
6452
        int rheight = ht;
6453
        int rleft = lt;
6454
        int rtop = tp;
43 andreas 6455
#ifdef _SCALE_SKIA_
26 andreas 6456
        if (gPageManager && gPageManager->getScaleFactor() != 1.0)
6457
        {
6458
            rwidth = (int)((double)wt * gPageManager->getScaleFactor());
6459
            rheight = (int)((double)ht * gPageManager->getScaleFactor());
6460
            rleft = (int)((double)lt * gPageManager->getScaleFactor());
6461
            rtop = (int)((double)tp * gPageManager->getScaleFactor());
6462
 
6463
            SkPaint paint;
6464
            paint.setBlendMode(SkBlendMode::kSrc);
6465
            paint.setFilterQuality(kHigh_SkFilterQuality);
28 andreas 6466
            // Calculate new dimension
26 andreas 6467
            SkImageInfo info = imgButton.info();
6468
            int width = (int)((double)info.width() * gPageManager->getScaleFactor());
6469
            int height = (int)((double)info.height() * gPageManager->getScaleFactor());
28 andreas 6470
            // Create a canvas and draw new image
6471
            sk_sp<SkImage> im = SkImage::MakeFromBitmap(imgButton);
6472
            imgButton.allocN32Pixels(width, height);
6473
            imgButton.eraseColor(SK_ColorTRANSPARENT);
254 andreas 6474
            SkCanvas can(imgButton, SkSurfaceProps());
26 andreas 6475
            SkRect rect = SkRect::MakeXYWH(0, 0, width, height);
179 andreas 6476
            can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
28 andreas 6477
            mLastImage = imgButton;
26 andreas 6478
        }
43 andreas 6479
#endif
289 andreas 6480
        TBitmap image((unsigned char *)imgButton.getPixels(), imgButton.info().width(), imgButton.info().height());
298 andreas 6481
        _displayButton(mHandle, parent, image, rwidth, rheight, rleft, rtop, isPassThrough());
26 andreas 6482
    }
6483
 
15 andreas 6484
    return true;
6485
}
6486
 
40 andreas 6487
POSITION_t TButton::calcImagePosition(int width, int height, CENTER_CODE cc, int number, int line)
4 andreas 6488
{
6489
    DECL_TRACER("TButton::calcImagePosition(int with, int height, CENTER_CODE code, int number)");
6490
 
6491
    SR_T act_sr;
6492
    POSITION_t position;
69 andreas 6493
    int ix, iy, ln;
4 andreas 6494
 
6495
    if (sr.size() == 0)
6496
        return position;
6497
 
6498
    if (number <= 0)
6499
        act_sr = sr.at(0);
6500
    else if ((size_t)number < sr.size())
6501
        act_sr = sr.at(number);
46 andreas 6502
    else if ((size_t)number >= sr.size())
6503
        act_sr = sr.at(sr.size() - 1);
4 andreas 6504
    else
6505
        return position;
6506
 
69 andreas 6507
    if (line <= 0)
6508
        ln = 1;
6509
    else
6510
        ln = line;
6511
 
4 andreas 6512
    int border_size = getBorderSize(act_sr.bs);
8 andreas 6513
    int code, border = border_size;
10 andreas 6514
    string dbgCC;
17 andreas 6515
    int rwt = 0, rht = 0;
4 andreas 6516
 
6517
    switch (cc)
3 andreas 6518
    {
8 andreas 6519
        case SC_ICON:
6520
            code = act_sr.ji;
6521
            ix = act_sr.ix;
6522
            iy = act_sr.iy;
6523
            border = border_size = 0;
10 andreas 6524
            dbgCC = "ICON";
17 andreas 6525
            rwt = width;
6526
            rht = height;
8 andreas 6527
        break;
6528
 
6529
        case SC_BITMAP:
6530
            code = act_sr.jb;
10 andreas 6531
            ix = act_sr.bx;
6532
            iy = act_sr.by;
6533
            dbgCC = "BITMAP";
17 andreas 6534
            rwt = std::min(wt - border * 2, width);
6535
            rht = std::min(ht - border_size * 2, height);
8 andreas 6536
        break;
6537
 
6538
        case SC_TEXT:
6539
            code = act_sr.jt;
6540
            ix = act_sr.tx;
6541
            iy = act_sr.ty;
10 andreas 6542
            dbgCC = "TEXT";
164 andreas 6543
 
6544
            if (border < 4)
6545
                border = 4;
6546
//            border += 4;
69 andreas 6547
            rwt = std::min(wt - border * 2, width);         // We've always a minimum (invisible) border of 4 pixels.
6548
            rht = std::min(ht - border_size * 2, height);   // The height is calculated from a defined border, if any.
8 andreas 6549
        break;
3 andreas 6550
    }
4 andreas 6551
 
17 andreas 6552
    if (width > rwt || height > rht)
6553
        position.overflow = true;
46 andreas 6554
 
4 andreas 6555
    switch (code)
6556
    {
6557
        case 0: // absolute position
8 andreas 6558
            position.left = ix;
69 andreas 6559
            position.top = iy;
40 andreas 6560
 
46 andreas 6561
            if (cc == SC_BITMAP && ix < 0 && rwt < width)
6562
                position.left *= -1;
6563
 
6564
            if (cc == SC_BITMAP && iy < 0 && rht < height)
6565
                position.top += -1;
6566
 
10 andreas 6567
            position.width = rwt;
6568
            position.height = rht;
4 andreas 6569
        break;
6570
 
6571
        case 1: // top, left
10 andreas 6572
            if (cc == SC_TEXT)
40 andreas 6573
            {
10 andreas 6574
                position.left = border;
96 andreas 6575
                position.top = ht - ((ht - rht) / 2) - height * ln;
40 andreas 6576
            }
10 andreas 6577
 
6578
            position.width = rwt;
6579
            position.height = rht;
4 andreas 6580
        break;
6581
 
6582
        case 2: // center, top
40 andreas 6583
            if (cc == SC_TEXT)
96 andreas 6584
                position.top = ht - ((ht - rht) / 2) - height * ln;
40 andreas 6585
 
10 andreas 6586
            position.left = (wt - rwt) / 2;
6587
            position.height = rht;
6588
            position.width = rwt;
4 andreas 6589
        break;
6590
 
6591
        case 3: // right, top
10 andreas 6592
            position.left = wt - rwt;
19 andreas 6593
 
6594
            if (cc == SC_TEXT)
40 andreas 6595
            {
19 andreas 6596
                position.left = (((position.left - border) < 0) ? 0 : position.left - border);
96 andreas 6597
                position.top = ht - (ht - rht) - height * ln;
40 andreas 6598
            }
19 andreas 6599
 
10 andreas 6600
            position.width = rwt;
6601
            position.height = rht;
4 andreas 6602
        break;
6603
 
6604
        case 4: // left, middle
10 andreas 6605
            if (cc == SC_TEXT)
40 andreas 6606
            {
10 andreas 6607
                position.left = border;
69 andreas 6608
                position.top = (ht - height) / 2;
40 andreas 6609
            }
6610
            else
6611
                position.top = (ht - rht) / 2;
10 andreas 6612
 
6613
            position.width = rwt;
6614
            position.height = rht;
4 andreas 6615
        break;
6616
 
6617
        case 6: // right, middle
10 andreas 6618
            position.left = wt - rwt;
19 andreas 6619
 
6620
            if (cc == SC_TEXT)
40 andreas 6621
            {
19 andreas 6622
                position.left = (((position.left - border) < 0) ? 0 : position.left - border);
69 andreas 6623
                position.top = (ht - height) / 2;
40 andreas 6624
            }
6625
            else
6626
                position.top = (ht - rht) / 2;
19 andreas 6627
 
10 andreas 6628
            position.width = rwt;
6629
            position.height = rht;
4 andreas 6630
        break;
6631
 
6632
        case 7: // left, bottom
10 andreas 6633
            if (cc == SC_TEXT)
40 andreas 6634
            {
10 andreas 6635
                position.left = border_size;
69 andreas 6636
                position.top = (ht - rht) - height * ln;
40 andreas 6637
            }
6638
            else
6639
                position.top = ht - rht;
10 andreas 6640
 
6641
            position.width = rwt;
6642
            position.height = rht;
4 andreas 6643
        break;
6644
 
6645
        case 8: // center, bottom
10 andreas 6646
            position.left = (wt - rwt) / 2;
40 andreas 6647
 
6648
            if (cc == SC_TEXT)
69 andreas 6649
                position.top = (ht - rht) - height * ln;
40 andreas 6650
            else
6651
                position.top = ht - rht;
6652
 
10 andreas 6653
            position.width = rwt;
6654
            position.height = rht;
4 andreas 6655
        break;
6656
 
6657
        case 9: // right, bottom
10 andreas 6658
            position.left = wt - rwt;
19 andreas 6659
 
6660
            if (cc == SC_TEXT)
40 andreas 6661
            {
19 andreas 6662
                position.left = (((position.left - border) < 0) ? 0 : position.left - border);
69 andreas 6663
                position.top = (ht - rht) - height * ln;
40 andreas 6664
            }
6665
            else
6666
                position.top = ht - rht;
4 andreas 6667
        break;
6668
 
6669
        default: // center, middle
10 andreas 6670
            position.left = (wt - rwt) / 2;
40 andreas 6671
 
6672
            if (cc == SC_TEXT)
69 andreas 6673
                position.top = (ht - height) / 2;
40 andreas 6674
            else
6675
                position.top = (ht - rht) / 2;
6676
 
10 andreas 6677
            position.width = rwt;
6678
            position.height = rht;
4 andreas 6679
    }
6680
 
69 andreas 6681
    if (TStreamError::checkFilter(HLOG_DEBUG))
6682
    {
70 andreas 6683
        string format = getFormatString((TEXT_ORIENTATION)code);
6684
        MSG_DEBUG("Type: " << dbgCC << ", format: " << format <<
69 andreas 6685
            ", PosType=" << code << ", total height=" << ht << ", height object=" << height <<
6686
            ", Position: x=" << position.left << ", y=" << position.top << ", w=" << position.width <<
6687
            ", h=" << position.height << ", Overflow: " << (position.overflow ? "YES" : "NO"));
6688
    }
6689
 
4 andreas 6690
    position.valid = true;
6691
    return position;
6692
}
6693
 
99 andreas 6694
IMAGE_SIZE_t TButton::calcImageSize(int imWidth, int imHeight, int instance, bool aspect)
6695
{
6696
    DECL_TRACER("TButton::calcImageSize(int imWidth, int imHeight, bool aspect)");
6697
 
6698
    int border = getBorderSize(sr[instance].bs);
6699
    IMAGE_SIZE_t isize;
6700
 
6701
    if (!aspect)
6702
    {
6703
        isize.width = wt - border * 2;
6704
        isize.height = ht - border * 2;
6705
    }
6706
    else
6707
    {
6708
        int w = wt - border * 2;
6709
        int h = ht - border * 2;
6710
        double scale;
6711
 
100 andreas 6712
        if (w < h || imWidth > imHeight)
99 andreas 6713
            scale = (double)w / (double)imWidth;
6714
        else
6715
            scale = (double)h / (double)imHeight;
6716
 
6717
        isize.width = (int)((double)imWidth * scale);
6718
        isize.height = (int)((double)imHeight * scale);
6719
    }
6720
 
6721
    MSG_DEBUG("Sizing image: Original: " << imWidth << " x " << imHeight << " to " << isize.width << " x " << isize.height);
6722
    return isize;
6723
}
6724
 
69 andreas 6725
string TButton::getFormatString(TEXT_ORIENTATION to)
6726
{
6727
    DECL_TRACER("TButton::getFormatString(CENTER_CODE cc)");
6728
 
6729
    switch(to)
6730
    {
6731
        case ORI_ABSOLUT:       return "ABSOLUT";
6732
        case ORI_BOTTOM_LEFT:   return "BOTTOM/LEFT";
6733
        case ORI_BOTTOM_MIDDLE: return "BOTTOM/MIDDLE";
6734
        case ORI_BOTTOM_RIGHT:  return "BOTTOM/RIGHT";
6735
        case ORI_CENTER_LEFT:   return "CENTER/LEFT";
6736
        case ORI_CENTER_MIDDLE: return "CENTER/MIDDLE";
6737
        case ORI_CENTER_RIGHT:  return "CENTER/RIGHT";
6738
        case ORI_TOP_LEFT:      return "TOP/LEFT";
6739
        case ORI_TOP_MIDDLE:    return "TOP/MIDDLE";
6740
        case ORI_TOP_RIGHT:     return "TOP/RIGHT";
6741
    }
6742
 
6743
    return "UNKNOWN";   // Should not happen!
6744
}
6745
 
4 andreas 6746
int TButton::getBorderSize(const std::string& name)
6747
{
6748
    DECL_TRACER("TButton::getBorderSize(const std::string& name)");
6749
 
306 andreas 6750
    int width = getBorderWidth(name);
6751
 
6752
    if (width > 0)
6753
        return width;
6754
 
81 andreas 6755
    if (gPageManager && gPageManager->getSystemDraw())
6756
    {
6757
        if (gPageManager->getSystemDraw()->existBorder(name))
6758
            return gPageManager->getSystemDraw()->getBorderWidth(name);
6759
    }
6760
 
4 andreas 6761
    return 0;
6762
}
6763
 
6764
void TButton::calcImageSizePercent(int imWidth, int imHeight, int btWidth, int btHeight, int btFrame, int *realX, int *realY)
6765
{
6766
    DECL_TRACER("TButton::clacImageSizePercent(int imWidth, int imHeight, int btWidth, int btHeight, int btFrame, int *realX, int *realY)");
6767
 
6768
    int spX = btWidth - (btFrame * 2);
6769
    int spY = btHeight - (btFrame * 2);
6770
 
6771
    if (imWidth <= spX && imHeight <= spY)
6772
    {
6773
        *realX = imWidth;
6774
        *realY = imHeight;
6775
        return;
6776
    }
6777
 
6778
    int oversizeX = 0, oversizeY = 0;
6779
 
6780
    if (imWidth > spX)
6781
        oversizeX = imWidth - spX;
6782
 
6783
    if (imHeight > spY)
6784
        oversizeY = imHeight - spY;
6785
 
6786
    double percent = 0.0;
6787
 
6788
    if (oversizeX > oversizeY)
6789
        percent = 100.0 / (double)imWidth * (double)spX;
3 andreas 6790
    else
4 andreas 6791
        percent = 100.0 / (double)imHeight * (double)spY;
6792
 
6793
    *realX = (int)(percent / 100.0 * (double)imWidth);
6794
    *realY = (int)(percent / 100.0 * (double)imHeight);
6795
}
6796
 
10 andreas 6797
SkBitmap TButton::drawImageButton(SkBitmap& imgRed, SkBitmap& imgMask, int width, int height, SkColor col1, SkColor col2)
4 andreas 6798
{
6 andreas 6799
    DECL_TRACER("TButton::drawImageButton(SkImage& imgRed, SkImage& imgMask, int width, int height, SkColor col1, SkColor col2)");
4 andreas 6800
 
35 andreas 6801
    if (width <= 0 || height <= 0)
6802
    {
165 andreas 6803
        MSG_WARNING("Got invalid width of height! (width: " << width << ", height: " << height << ")");
35 andreas 6804
        return SkBitmap();
6805
    }
6806
 
162 andreas 6807
    if (imgRed.empty())
6808
    {
6809
        MSG_WARNING("Missing mask to draw image!");
6810
        return SkBitmap();
6811
    }
6812
 
6 andreas 6813
    SkPixmap pixmapRed = imgRed.pixmap();
7 andreas 6814
    SkPixmap pixmapMask;
163 andreas 6815
    bool haveBothImages = true;
4 andreas 6816
 
7 andreas 6817
    if (!imgMask.empty())
6818
        pixmapMask = imgMask.pixmap();
163 andreas 6819
    else
6820
        haveBothImages = false;
162 andreas 6821
 
7 andreas 6822
    SkBitmap maskBm;
254 andreas 6823
 
6824
    if (!allocPixels(width, height, &maskBm))
6825
        return SkBitmap();
6826
 
69 andreas 6827
    maskBm.eraseColor(SK_ColorTRANSPARENT);
3 andreas 6828
 
4 andreas 6829
    for (int ix = 0; ix < width; ix++)
6830
    {
6831
        for (int iy = 0; iy < height; iy++)
3 andreas 6832
        {
184 andreas 6833
            SkColor pixelRed;
7 andreas 6834
            SkColor pixelMask;
3 andreas 6835
 
184 andreas 6836
            if (ix < pixmapRed.info().width() && iy < pixmapRed.info().height())
240 andreas 6837
                pixelRed = pixmapRed.getColor(ix, iy);
184 andreas 6838
            else
6839
                pixelRed = 0;
6840
 
6841
            if (haveBothImages && !imgMask.empty() &&
6842
                    ix < pixmapMask.info().width() && iy < pixmapMask.info().height())
7 andreas 6843
                pixelMask = pixmapMask.getColor(ix, iy);
6844
            else
164 andreas 6845
                pixelMask = SkColorSetA(SK_ColorWHITE, 0);
3 andreas 6846
 
10 andreas 6847
            SkColor pixel = baseColor(pixelRed, pixelMask, col1, col2);
20 andreas 6848
            uint32_t alpha = SkColorGetA(pixel);
184 andreas 6849
            uint32_t *wpix = nullptr;
35 andreas 6850
 
184 andreas 6851
            if (ix < maskBm.info().width() && iy < maskBm.info().height())
6852
                wpix = maskBm.getAddr32(ix, iy);
6853
 
35 andreas 6854
            if (!wpix)
184 andreas 6855
                continue;
35 andreas 6856
 
20 andreas 6857
            if (alpha == 0)
6858
                pixel = pixelMask;
184 andreas 6859
 
262 andreas 6860
            *wpix = pixel;
3 andreas 6861
        }
6862
    }
6863
 
7 andreas 6864
    return maskBm;
3 andreas 6865
}
6 andreas 6866
 
99 andreas 6867
/**
6868
 * @brief Takes 2 images and combines them to one.
6869
 *
6870
 * The 2 images are a solid base image defining the basic form and an identical
6871
 * image defining the alpha channel.
6872
 *
6873
 * @param base  The base image containing the form as black pixels.
6874
 * @param alpha The image containing just an alpha channel.
6875
 * @param col   The color which should be used instead of a black pixel.
6876
 *
6877
 * @return On success a valid bitmap is returned containing the form.
6878
 * On error an empty bitmap is returned.
6879
 */
6880
SkBitmap TButton::combineImages(SkBitmap& base, SkBitmap& alpha, SkColor col)
6881
{
6882
    DECL_TRACER("TButton::combineImages(SkBitmap& base, SkBitmap& alpha, SkColor col)");
6883
 
6884
    int width = base.info().width();
6885
    int height = base.info().height();
6886
    SkBitmap Bm;    // The new bitmap. It will be returned in the end.
6887
 
6888
    if (width != alpha.info().width() || height != alpha.info().height())
6889
    {
6890
        MSG_ERROR("Mask and alpha have different size! [ " << width << " x " << height << " to " << alpha.info().width() << " x " << alpha.info().height());
6891
        return Bm;
6892
    }
6893
 
254 andreas 6894
    if (!allocPixels(width, height, &Bm))
6895
        return Bm;
6896
 
99 andreas 6897
    Bm.eraseColor(SK_ColorTRANSPARENT);
6898
 
6899
    for (int ix = 0; ix < width; ix++)
6900
    {
6901
        for (int iy = 0; iy < height; iy++)
6902
        {
6903
            SkColor pixelAlpha = alpha.getColor(ix, iy);
100 andreas 6904
            uint32_t *bpix = Bm.getAddr32(ix, iy);
99 andreas 6905
 
100 andreas 6906
            uchar al    = SkColorGetA(pixelAlpha);
99 andreas 6907
            uchar red   = SkColorGetR(col);
6908
            uchar green = SkColorGetG(col);
6909
            uchar blue  = SkColorGetB(col);
6910
 
100 andreas 6911
            if (pixelAlpha == 0)
6912
                red = green = blue = 0;
99 andreas 6913
 
254 andreas 6914
            // Skia reads image files in the natural byte order of the CPU.
6915
            // While on Intel CPUs the byte order is little endian it is
6916
            // mostly big endian on other CPUs. This means that the order of
260 andreas 6917
            // the colors is RGB on big endian CPUs (ARM, ...) and BGR on others.
6918
            // To compensate this, we check the endianess of the CPU and set
6919
            // the byte order according.
262 andreas 6920
 
260 andreas 6921
            if (isBigEndian())
6922
                *bpix = SkColorSetARGB(al, blue, green, red);
6923
            else
6924
                *bpix = SkColorSetARGB(al, red, green, blue);
99 andreas 6925
        }
6926
    }
6927
 
100 andreas 6928
    SkPaint paint;
6929
    paint.setBlendMode(SkBlendMode::kSrcOver);
6930
    SkCanvas can(Bm);
179 andreas 6931
    sk_sp<SkImage> _image = SkImage::MakeFromBitmap(base);
6932
    can.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
99 andreas 6933
    return Bm;
6934
}
6935
 
307 andreas 6936
/**
6937
 * @brief TButton::colorImage: Colorize frame element
6938
 * This method colorizes a frame element. If there is, beside the base picture,
6939
 * also a an alpha mask picture present, the elemnt is colorized by taking the
6940
 * mask to find the pixels to colorize.
6941
 * Otherwise the pixel is melted with the target color. This means a pseudo mask
6942
 * is used.
6943
 *
6944
 * @param base      This is the base image and must be present.
6945
 * @param alpha     This is optional alpha mask. If present it is used to
6946
 *                  define the alpha value of the pixels.
6947
 * @param col       This is the color to be used.
6948
 * @param bg        This is the background color to be used on the transparent
6949
 *                  pixels inside an element. On the transparent pixels on the
6950
 *                  outside of the element the pixel is set to transparent.
6951
 * @param useBG     If this is TRUE, all transparent pixels are set to the
6952
 *                  background color \b bg.
6953
 * @return
6954
 * On success a new image containing the colorized element is returned.
6955
 * Otherwise an empty image is returned.
6956
 */
161 andreas 6957
SkBitmap TButton::colorImage(SkBitmap& base, SkBitmap& alpha, SkColor col, SkColor bg, bool useBG)
80 andreas 6958
{
81 andreas 6959
    DECL_TRACER("TButton::colorImage(SkBitmap *img, int width, int height, SkColor col, SkColor bg, bool useBG)");
80 andreas 6960
 
161 andreas 6961
    int width = base.info().width();
6962
    int height = base.info().height();
6963
 
80 andreas 6964
    if (width <= 0 || height <= 0)
6965
    {
169 andreas 6966
        MSG_WARNING("Got invalid width or height! (width: " << width << ", height: " << height << ")");
161 andreas 6967
        return SkBitmap();
80 andreas 6968
    }
6969
 
169 andreas 6970
    if (!alpha.empty())
161 andreas 6971
    {
169 andreas 6972
        if (width != alpha.info().width() || height != alpha.info().height())
6973
        {
6974
            MSG_ERROR("Base and alpha masks have different size!");
6975
            return SkBitmap();
6976
        }
161 andreas 6977
    }
6978
 
80 andreas 6979
    SkBitmap maskBm;
254 andreas 6980
 
6981
    if (!allocPixels(width, height, &maskBm))
6982
        return SkBitmap();
6983
 
160 andreas 6984
    maskBm.eraseColor(SK_ColorTRANSPARENT);
80 andreas 6985
 
6986
    for (int ix = 0; ix < width; ix++)
6987
    {
6988
        for (int iy = 0; iy < height; iy++)
6989
        {
169 andreas 6990
            SkColor pixelAlpha = 0;
6991
 
6992
            if (!alpha.empty())
6993
                pixelAlpha = alpha.getColor(ix, iy);
6994
            else
6995
                pixelAlpha = base.getColor(ix, iy);
6996
 
80 andreas 6997
            uint32_t *wpix = maskBm.getAddr32(ix, iy);
6998
 
6999
            if (!wpix)
7000
            {
7001
                MSG_ERROR("No pixel buffer!");
7002
                break;
7003
            }
7004
 
169 andreas 7005
            uint32_t ala = SkColorGetA(pixelAlpha);
81 andreas 7006
 
169 andreas 7007
            if (ala == 0 && !useBG)
307 andreas 7008
                pixelAlpha = SK_ColorTRANSPARENT; //col;
169 andreas 7009
            else if (ala == 0)
160 andreas 7010
                pixelAlpha = bg;
81 andreas 7011
            else
7012
            {
307 andreas 7013
                uint32_t red   = SkColorGetR(col);
159 andreas 7014
                uint32_t green = SkColorGetG(col);
307 andreas 7015
                uint32_t blue  = SkColorGetB(col);
169 andreas 7016
                pixelAlpha = SkColorSetARGB(ala, red, green, blue);
81 andreas 7017
            }
7018
 
160 andreas 7019
            *wpix = pixelAlpha;
80 andreas 7020
        }
7021
    }
7022
 
169 andreas 7023
    if (!alpha.empty())
7024
    {
7025
        SkPaint paint;
7026
        paint.setBlendMode(SkBlendMode::kSrcOver);
7027
        SkCanvas can(maskBm);
308 andreas 7028
        sk_sp<SkImage> _image = SkImage::MakeFromBitmap(base);
179 andreas 7029
        can.drawImage(_image, 0, 0, SkSamplingOptions(), &paint);
169 andreas 7030
    }
7031
 
160 andreas 7032
    return maskBm;
80 andreas 7033
}
7034
 
161 andreas 7035
SkBitmap TButton::retrieveBorderImage(const string& pa, const string& pb, SkColor color, SkColor bgColor)
160 andreas 7036
{
161 andreas 7037
    DECL_TRACER("TButton::retrieveBorderImage(const string& pa, const string& pb, SkColor color, SkColor bgColor)");
160 andreas 7038
 
7039
    SkBitmap bm, bma;
7040
 
161 andreas 7041
    if (!pa.empty() && !retrieveImage(pa, &bm))
160 andreas 7042
        return SkBitmap();
7043
 
161 andreas 7044
    if (!pb.empty() && !retrieveImage(pb, &bma))
160 andreas 7045
        return SkBitmap();
7046
 
161 andreas 7047
    return colorImage(bm, bma, color, bgColor, false);
160 andreas 7048
}
7049
 
99 andreas 7050
bool TButton::retrieveImage(const string& path, SkBitmap* image)
7051
{
7052
    DECL_TRACER("TButton::retrieveImage(const string& path, SkBitmap* image)");
7053
 
7054
    sk_sp<SkData> im;
7055
 
7056
    if (!(im = readImage(path)))
7057
        return false;
7058
 
7059
    DecodeDataToBitmap(im, image);
7060
 
7061
    if (image->empty())
7062
    {
7063
        MSG_WARNING("Could not create the image " << path);
7064
        return false;
7065
    }
7066
 
7067
    return true;
7068
}
7069
 
6 andreas 7070
void TButton::show()
7071
{
7072
    DECL_TRACER("TButton::show()");
7073
 
334 andreas 7074
    if (visible && !mChanged)
7075
        return;
7076
 
15 andreas 7077
    visible = true;
7078
    makeElement();
6 andreas 7079
 
15 andreas 7080
    if (isSystemButton() && !mSystemReg)
7081
        registerSystemButton();
7082
}
7083
 
7084
void TButton::showLastButton()
7085
{
7086
    DECL_TRACER("TButton::showLastButton()");
7087
 
7088
    if (mLastImage.empty())
334 andreas 7089
    {
7090
#if TESTMODE == 1
7091
        setScreenDone();
7092
#endif
15 andreas 7093
        return;
334 andreas 7094
    }
15 andreas 7095
 
38 andreas 7096
    if (!_displayButton && gPageManager)
7097
        _displayButton = gPageManager->getCallbackDB();
7098
 
195 andreas 7099
    if (!prg_stopped && visible)
6 andreas 7100
    {
15 andreas 7101
        ulong parent = mHandle & 0xffff0000;
7102
        size_t rowBytes = mLastImage.info().minRowBytes();
26 andreas 7103
        int rwidth = wt;
7104
        int rheight = ht;
7105
        int rleft = lt;
7106
        int rtop = tp;
43 andreas 7107
#ifdef _SCALE_SKIA_
26 andreas 7108
        if (gPageManager && gPageManager->getScaleFactor() != 1.0)
7109
        {
7110
            rwidth = (int)((double)wt * gPageManager->getScaleFactor());
7111
            rheight = (int)((double)ht * gPageManager->getScaleFactor());
7112
            rleft = (int)((double)lt * gPageManager->getScaleFactor());
7113
            rtop = (int)((double)tp * gPageManager->getScaleFactor());
7114
        }
43 andreas 7115
#endif
195 andreas 7116
        if (type == TEXT_INPUT)
7117
        {
7118
            if (gPageManager && gPageManager->getCallbackInputText())
7119
            {
7120
                BITMAP_t bm;
7121
                bm.buffer = (unsigned char *)mLastImage.getPixels();
7122
                bm.rowBytes = rowBytes;
7123
                bm.left = rleft;
7124
                bm.top = rtop;
7125
                bm.width = rwidth;
7126
                bm.height = rheight;
291 andreas 7127
                gPageManager->getCallbackInputText()(this, bm, mBorderWidth);
195 andreas 7128
            }
7129
        }
206 andreas 7130
        else if (type == LISTBOX)
7131
        {
7132
            if (gPageManager && gPageManager->getCallbackListBox())
7133
            {
7134
                BITMAP_t bm;
7135
                bm.buffer = (unsigned char *)mLastImage.getPixels();
7136
                bm.rowBytes = rowBytes;
7137
                bm.left = rleft;
7138
                bm.top = rtop;
7139
                bm.width = rwidth;
7140
                bm.height = rheight;
291 andreas 7141
                gPageManager->getCallbackListBox()(this, bm, mBorderWidth);
206 andreas 7142
            }
7143
        }
291 andreas 7144
        else if (type == SUBPAGE_VIEW)
7145
        {
7146
            if (gPageManager && gPageManager->getDisplayViewButton())
7147
            {
7148
                TBitmap image((unsigned char *)mLastImage.getPixels(), mLastImage.info().width(), mLastImage.info().height());
7149
                TColor::COLOR_T bgcolor = TColor::getAMXColor(sr[mActInstance].cf);
7150
                gPageManager->getDisplayViewButton()(mHandle, getParent(), (on.empty() ? false : true), image, wt, ht, lt, tp, sa, bgcolor);
7151
            }
7152
        }
195 andreas 7153
        else if (_displayButton)
289 andreas 7154
        {
7155
            TBitmap image((unsigned char *)mLastImage.getPixels(), mLastImage.info().width(), mLastImage.info().height());
298 andreas 7156
            _displayButton(mHandle, parent, image, rwidth, rheight, rleft, rtop, isPassThrough());
289 andreas 7157
        }
195 andreas 7158
 
176 andreas 7159
        mChanged = false;
15 andreas 7160
    }
7161
}
7162
 
7163
void TButton::hide(bool total)
7164
{
7165
    DECL_TRACER("TButton::hide()");
7166
 
101 andreas 7167
//    if (type == MULTISTATE_GENERAL && ar == 1)
7168
//        mAniStop = true;
15 andreas 7169
 
21 andreas 7170
    if (!prg_stopped && total)
15 andreas 7171
    {
26 andreas 7172
        int rwidth = wt;
7173
        int rheight = ht;
7174
        int rleft = lt;
7175
        int rtop = tp;
7176
 
38 andreas 7177
        ulong parent = mHandle & 0xffff0000;
7178
        THR_REFRESH_t *tr = _findResource(mHandle, parent, bi);
7179
 
7180
        if (tr && tr->mImageRefresh)
7181
        {
7182
            if (tr->mImageRefresh->isRunning())
7183
                tr->mImageRefresh->stop();
7184
        }
43 andreas 7185
#ifdef _SCALE_SKIA_
26 andreas 7186
        if (gPageManager && gPageManager->getScaleFactor() != 1.0)
7187
        {
7188
            rwidth = (int)((double)wt * gPageManager->getScaleFactor());
7189
            rheight = (int)((double)ht * gPageManager->getScaleFactor());
7190
            rleft = (int)((double)lt * gPageManager->getScaleFactor());
7191
            rtop = (int)((double)tp * gPageManager->getScaleFactor());
7192
        }
43 andreas 7193
#endif
190 andreas 7194
        if (type == TEXT_INPUT)
7195
        {
7196
            if (gPageManager && gPageManager->getCallDropButton())
7197
                gPageManager->getCallDropButton()(mHandle);
7198
 
7199
            visible = false;
7200
            return;
7201
        }
7202
 
28 andreas 7203
        SkBitmap imgButton;
7204
 
165 andreas 7205
        if (rwidth < 0 || rheight < 0)
7206
        {
7207
            MSG_ERROR("Invalid size of image: " << rwidth << " x " << rheight);
7208
            return;
7209
        }
7210
 
7211
        try
7212
        {
254 andreas 7213
            if (!allocPixels(wt, ht, &imgButton))
7214
                return;
7215
 
165 andreas 7216
            imgButton.eraseColor(SK_ColorTRANSPARENT);
7217
        }
7218
        catch (std::exception& e)
7219
        {
7220
            MSG_ERROR("Error creating image: " << e.what());
7221
            visible = false;
7222
            return;
7223
        }
7224
 
38 andreas 7225
        if (!_displayButton && gPageManager)
7226
            _displayButton = gPageManager->getCallbackDB();
7227
 
7228
        if (_displayButton)
176 andreas 7229
        {
289 andreas 7230
            TBitmap image((unsigned char *)imgButton.getPixels(), imgButton.info().width(), imgButton.info().height());
298 andreas 7231
            _displayButton(mHandle, parent, image, rwidth, rheight, rleft, rtop, isPassThrough());
176 andreas 7232
            mChanged = false;
7233
        }
15 andreas 7234
    }
7235
 
7236
    visible = false;
7237
}
7238
 
154 andreas 7239
bool TButton::isClickable(int x, int y)
15 andreas 7240
{
7241
    DECL_TRACER("TButton::isClickable()");
7242
 
154 andreas 7243
    if (mEnabled && /*((cp != 0 && ch != 0) || (lp != 0 && lv != 0) || !cm.empty() || !op.empty() || !pushFunc.empty() || isSystemButton()) &&*/ hs.compare("passThru") != 0)
7244
    {
7245
        if (x != -1 && y != -1 && hs.empty() && !mLastImage.empty() && isPixelTransparent(x, y))
7246
            return false;
150 andreas 7247
 
15 andreas 7248
        return true;
154 andreas 7249
    }
15 andreas 7250
 
7251
    return false;
7252
}
7253
 
7254
/**
7255
 * Handling of system button "connection state". It consists of 12 states
7256
 * indicating the network status. The states have the following meaning:
7257
 *
7258
 * 0      Diconnected (never was connected before since startup)
7259
 * 1 - 6  Connected (blink may be shown with dark and light green)
7260
 * 7, 8   Disconnected (timeout or loss of connection)
7261
 * 9 - 11 Connection in progress
7262
 */
7263
void TButton::funcNetwork(int state)
7264
{
7265
    mutex_sysdraw.lock();
7266
    DECL_TRACER("TButton::funcNetwork(int state)");
7267
 
7268
    mLastLevel = state;
7269
    mActInstance = state;
176 andreas 7270
    mChanged = true;
15 andreas 7271
 
7272
    if (visible)
7273
        makeElement(state);
7274
 
7275
    mutex_sysdraw.unlock();
7276
}
7277
 
7278
/**
7279
 * Handling the timer event from the controller. This comes usualy every
7280
 * 20th part of a second (1 second / 20)
7281
 */
7282
void TButton::funcTimer(const amx::ANET_BLINK& blink)
7283
{
7284
    mutex_sysdraw.lock();
7285
    DECL_TRACER("TButton::funcTimer(const amx::ANET_BLINK& blink)");
7286
 
7287
    string tm;
7288
    std::stringstream sstr;
7289
 
7290
    switch (ad)
7291
    {
7292
        case 141:   // Standard time
7293
            sstr << std::setw(2) << std::setfill('0') << (int)blink.hour << ":"
7294
                 << std::setw(2) << std::setfill('0') << (int)blink.minute << ":"
7295
                 << std::setw(2) << std::setfill('0') << (int)blink.second;
7296
            mLastBlink = blink;
7297
        break;
7298
 
7299
        case 142:   // Time AM/PM
6 andreas 7300
        {
15 andreas 7301
            int hour = (blink.hour > 12) ? (blink.hour - 12) : blink.hour;
7302
            sstr << std::setw(2) << std::setfill('0') << hour << ":"
7303
                 << std::setw(2) << std::setfill('0') << (int)blink.minute << " ";
7304
 
7305
            if (blink.hour <= 12)
7306
                sstr << "AM";
7307
            else
7308
                sstr << "PM";
7309
 
7310
            mLastBlink = blink;
6 andreas 7311
        }
15 andreas 7312
        break;
6 andreas 7313
 
15 andreas 7314
        case 143:   // Time 24 hours
7315
            sstr << std::setw(2) << std::setfill('0') << (int)blink.hour << ":"
7316
                 << std::setw(2) << std::setfill('0') << (int)blink.minute;
7317
            mLastBlink = blink;
7318
        break;
7319
 
7320
        case 151:   // Weekday
7321
            switch (blink.weekday)
7322
            {
7323
                case 0: sstr << "Monday"; break;
7324
                case 1: sstr << "Tuesday"; break;
7325
                case 2: sstr << "Wednesday"; break;
7326
                case 3: sstr << "Thursday"; break;
7327
                case 4: sstr << "Friday"; break;
7328
                case 5: sstr << "Saturday"; break;
7329
                case 6: sstr << "Sunday"; break;
7330
            }
7331
        break;
7332
 
7333
        case 152:   // Date mm/dd
7334
            sstr << (int)blink.month << "/" << (int)blink.day;
7335
        break;
7336
 
7337
        case 153:   // Date dd/mm
7338
            sstr << (int)blink.day << "/" << (int)blink.month;
7339
        break;
7340
 
7341
        case 154:   // Date mm/dd/yyyy
7342
            sstr << (int)blink.month << "/" << (int)blink.day << "/" << (int)blink.year;
7343
        break;
7344
 
7345
        case 155:   // Date dd/mm/yyyy
7346
            sstr << blink.day << "/" << blink.month << "/" << blink.year;
7347
        break;
7348
 
7349
        case 156:   // Date month dd/yyyy
7350
            switch (blink.month)
7351
            {
7352
                case 1:  sstr << "January"; break;
7353
                case 2:  sstr << "February"; break;
7354
                case 3:  sstr << "March"; break;
7355
                case 4:  sstr << "April"; break;
7356
                case 5:  sstr << "May"; break;
7357
                case 6:  sstr << "June"; break;
7358
                case 7:  sstr << "July"; break;
7359
                case 8:  sstr << "August"; break;
7360
                case 9:  sstr << "September"; break;
7361
                case 10:  sstr << "October"; break;
7362
                case 11:  sstr << "November"; break;
7363
                case 12:  sstr << "December"; break;
7364
            }
7365
 
7366
            sstr << " " << (int)blink.day << "/" << (int)blink.year;
7367
        break;
7368
 
7369
        case 157:   // Date dd month yyyy
7370
            sstr << (int)blink.day;
7371
 
7372
            switch (blink.month)
7373
            {
7374
                case 1:  sstr << "January"; break;
7375
                case 2:  sstr << "February"; break;
7376
                case 3:  sstr << "March"; break;
7377
                case 4:  sstr << "April"; break;
7378
                case 5:  sstr << "May"; break;
7379
                case 6:  sstr << "June"; break;
7380
                case 7:  sstr << "July"; break;
7381
                case 8:  sstr << "August"; break;
7382
                case 9:  sstr << "September"; break;
7383
                case 10:  sstr << "October"; break;
7384
                case 11:  sstr << "November"; break;
7385
                case 12:  sstr << "December"; break;
7386
            }
7387
 
7388
            sstr << " " << (int)blink.year;
7389
        break;
7390
 
7391
        case 158:   // Date yyyy-mm-dd
7392
            sstr << (int)blink.year << "-" << (int)blink.month << "-" << (int)blink.day;
7393
        break;
176 andreas 7394
 
7395
        default:
7396
            mutex_sysdraw.unlock();
7397
            return;
6 andreas 7398
    }
15 andreas 7399
 
7400
    vector<SR_T>::iterator iter;
7401
    tm = sstr.str();
7402
 
118 andreas 7403
    for (iter = sr.begin(); iter != sr.end(); ++iter)
15 andreas 7404
        iter->te = tm;
7405
 
176 andreas 7406
    mChanged = true;
7407
 
15 andreas 7408
    if (visible)
7409
        makeElement(mActInstance);
7410
 
7411
    mutex_sysdraw.unlock();
6 andreas 7412
}
7 andreas 7413
 
15 andreas 7414
bool TButton::isPixelTransparent(int x, int y)
7415
{
7416
    DECL_TRACER("TButton::isPixelTransparent(int x, int y)");
7417
 
54 andreas 7418
    // If there is no image we treat it as a non transpararent pixel.
7419
    if (sr[mActInstance].mi.empty() && sr[mActInstance].bm.empty())
7420
        return false;
7421
 
7422
    // The mLastImage must never be empty! Although this should never be true,
7423
    // we treat it as a transparent pixel if it happen.
15 andreas 7424
    if (mLastImage.empty())
7425
    {
7426
        MSG_ERROR("Internal error: No image for button available!");
7427
        return true;
7428
    }
7429
 
54 andreas 7430
    // Make sure the coordinates are inside the bounds. A test for a pixel
7431
    // outside the bounds would lead in an immediate exit because of an assert
7432
    // test in skia. Although this should not happen, we treat the pixel as
7433
    // transparent in this case, because the coordinates didn't hit the button.
31 andreas 7434
    if (x < 0 || x >= mLastImage.info().width() || y < 0 || y >= mLastImage.info().height())
7435
    {
7436
        MSG_ERROR("The X or Y coordinate is out of bounds!");
7437
        MSG_ERROR("X=" << x << ", Y=" << y << ", width=" << mLastImage.info().width() << ", height=" << mLastImage.info().height());
54 andreas 7438
        return true;
31 andreas 7439
    }
7440
 
54 andreas 7441
    float alpha = mLastImage.getAlphaf(x, y);   // Get the alpha value (0.0 to 1.0)
15 andreas 7442
 
7443
    if (alpha != 0.0)
7444
        return false;
7445
 
7446
    return true;
7447
}
7448
 
71 andreas 7449
bool TButton::checkForSound()
7450
{
7451
    DECL_TRACER("TButton::checkForSound()");
7452
 
7453
    vector<SR_T>::iterator iter;
7454
 
7455
    for (iter = sr.begin(); iter != sr.end(); ++iter)
7456
    {
7457
        if (!iter->sd.empty())
7458
            return true;
7459
    }
7460
 
7461
    return false;
7462
}
7463
 
79 andreas 7464
bool TButton::scaleImage(SkBitmap *bm, double scaleWidth, double scaleHeight)
7465
{
7466
    DECL_TRACER("TButton::scaleImage(SkBitmap *bm, double scaleWidth, double scaleHeight)");
7467
 
7468
    if (!bm)
7469
        return false;
7470
 
7471
    if (scaleWidth == 1.0 && scaleHeight == 1.0)
7472
        return true;
7473
 
7474
    SkPaint paint;
7475
    paint.setBlendMode(SkBlendMode::kSrc);
179 andreas 7476
//    paint.setFilterQuality(kHigh_SkFilterQuality);
79 andreas 7477
    // Calculate new dimension
7478
    SkImageInfo info = bm->info();
7479
    int width  = std::max(1, (int)((double)info.width() * scaleWidth));
7480
    int height = std::max(1, (int)((double)info.height() * scaleHeight));
80 andreas 7481
    MSG_DEBUG("Scaling image to size " << width << " x " << height);
79 andreas 7482
    // Create a canvas and draw new image
7483
    sk_sp<SkImage> im = SkImage::MakeFromBitmap(*bm);
254 andreas 7484
 
7485
    if (!allocPixels(width, height, bm))
7486
        return false;
7487
 
79 andreas 7488
    bm->eraseColor(SK_ColorTRANSPARENT);
254 andreas 7489
    SkCanvas can(*bm, SkSurfaceProps());
79 andreas 7490
    SkRect rect = SkRect::MakeXYWH(0, 0, width, height);
179 andreas 7491
    can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
79 andreas 7492
    return true;
7493
}
7494
 
7495
bool TButton::stretchImageWidth(SkBitmap *bm, int width)
7496
{
7497
    DECL_TRACER("TButton::stretchImageWidth(SkBitmap *bm, int width)");
7498
 
80 andreas 7499
    if (!bm)
7500
        return false;
7501
 
157 andreas 7502
    int rwidth = width;
79 andreas 7503
    SkPaint paint;
7504
    paint.setBlendMode(SkBlendMode::kSrc);
179 andreas 7505
//    paint.setFilterQuality(kHigh_SkFilterQuality);
79 andreas 7506
 
7507
    SkImageInfo info = bm->info();
7508
    sk_sp<SkImage> im = SkImage::MakeFromBitmap(*bm);
157 andreas 7509
 
7510
    if (width <= 0)
7511
        rwidth = info.width() + width;
7512
 
7513
    if (rwidth <= 0)
7514
        rwidth = 1;
7515
 
7516
    MSG_DEBUG("Width: " << rwidth << ", Height: " << info.height());
254 andreas 7517
 
7518
    if (!allocPixels(rwidth, info.height(), bm))
7519
        return false;
7520
 
79 andreas 7521
    bm->eraseColor(SK_ColorTRANSPARENT);
254 andreas 7522
    SkCanvas can(*bm, SkSurfaceProps());
157 andreas 7523
    SkRect rect = SkRect::MakeXYWH(0, 0, rwidth, info.height());
179 andreas 7524
    can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
80 andreas 7525
    return true;
79 andreas 7526
}
7527
 
7528
bool TButton::stretchImageHeight(SkBitmap *bm, int height)
7529
{
7530
    DECL_TRACER("TButton::stretchImageHeight(SkBitmap *bm, int height)");
7531
 
80 andreas 7532
    if (!bm)
7533
        return false;
7534
 
157 andreas 7535
    int rheight = height;
79 andreas 7536
    SkPaint paint;
7537
    paint.setBlendMode(SkBlendMode::kSrc);
179 andreas 7538
//    paint.setFilterQuality(kHigh_SkFilterQuality);
79 andreas 7539
 
7540
    SkImageInfo info = bm->info();
157 andreas 7541
 
7542
    if (height <= 0)
7543
        rheight = info.height() + height;
7544
 
7545
    if (rheight <= 0)
7546
        rheight = 1;
7547
 
79 andreas 7548
    sk_sp<SkImage> im = SkImage::MakeFromBitmap(*bm);
157 andreas 7549
    MSG_DEBUG("Width: " << info.width() << ", Height: " << rheight);
254 andreas 7550
 
7551
    if (!allocPixels(info.width(), rheight, bm))
7552
        return false;
7553
 
79 andreas 7554
    bm->eraseColor(SK_ColorTRANSPARENT);
254 andreas 7555
    SkCanvas can(*bm, SkSurfaceProps());
157 andreas 7556
    SkRect rect = SkRect::MakeXYWH(0, 0, info.width(), rheight);
179 andreas 7557
    can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
80 andreas 7558
    return true;
79 andreas 7559
}
7560
 
157 andreas 7561
bool TButton::stretchImageWH(SkBitmap *bm, int width, int height)
7562
{
7563
    DECL_TRACER("TButton::stretchImageWH(SkBitmap *bm, int width, int height)");
7564
 
7565
    if (!bm)
7566
        return false;
7567
 
7568
    int rwidth = width;
7569
    int rheight = height;
7570
    SkPaint paint;
7571
    paint.setBlendMode(SkBlendMode::kSrc);
179 andreas 7572
//    paint.setFilterQuality(kHigh_SkFilterQuality);
157 andreas 7573
 
7574
    SkImageInfo info = bm->info();
7575
 
7576
    if (width <= 0)
7577
        rwidth = info.width() + width;
7578
 
7579
    if (height <= 0)
7580
        rheight = info.height() + height;
7581
 
7582
    if (rheight <= 0)
7583
        rheight = 1;
7584
 
7585
    if (rwidth <= 0)
7586
        rwidth = 1;
7587
 
7588
    sk_sp<SkImage> im = SkImage::MakeFromBitmap(*bm);
7589
    MSG_DEBUG("Width: " << rwidth << ", Height: " << rheight);
254 andreas 7590
 
7591
    if (!allocPixels(rwidth, rheight, bm))
7592
        return false;
7593
 
157 andreas 7594
    bm->eraseColor(SK_ColorTRANSPARENT);
254 andreas 7595
    SkCanvas can(*bm, SkSurfaceProps());
157 andreas 7596
    SkRect rect = SkRect::MakeXYWH(0, 0, rwidth, rheight);
179 andreas 7597
    can.drawImageRect(im, rect, SkSamplingOptions(), &paint);
157 andreas 7598
    return true;
7599
}
7600
 
15 andreas 7601
/**
7602
 * This button got the click because it matches the coordinates of a mouse
7603
 * click. It checkes whether it is clickable or not. If it is clickable, it
7604
 * depends on the type of element what happens.
7605
 */
7606
bool TButton::doClick(int x, int y, bool pressed)
7607
{
146 andreas 7608
    DECL_TRACER("TButton::doClick(int x, int y, bool pressed)");
154 andreas 7609
 
7610
    if (!isClickable(x, y))
7611
        return false;
7612
 
14 andreas 7613
    amx::ANET_SEND scmd;
15 andreas 7614
    int instance = 0;
31 andreas 7615
    int sx = x, sy = y;
71 andreas 7616
    bool isSystem = isSystemButton();
11 andreas 7617
 
289 andreas 7618
    if (pressed && gPageManager && !checkForSound() && (ch > 0 || lv > 0 || !pushFunc.empty() || isSystem))
71 andreas 7619
    {
7620
        TSystemSound sysSound(TConfig::getSystemPath(TConfig::SOUNDS));
7621
 
289 andreas 7622
        if (gPageManager->havePlaySound() && sysSound.getSystemSoundState())
71 andreas 7623
            gPageManager->getCallPlaySound()(sysSound.getTouchFeedbackSound());
7624
    }
7625
 
43 andreas 7626
#ifdef _SCALE_SKIA_
31 andreas 7627
    // To be able to test a button for a transparent pixel, we must scale
7628
    // the coordinates because the test is made on the last drawn image and
7629
    // this image is scaled (if scaling is activated).
7630
    if (TConfig::getScale() && gPageManager && gPageManager->getScaleFactor() != 1.0)
7631
    {
7632
        double scaleFactor = gPageManager->getScaleFactor();
7633
        sx = (int)((double)x * scaleFactor);
7634
        sy = (int)((double)y * scaleFactor);
7635
    }
43 andreas 7636
#endif
292 andreas 7637
 
266 andreas 7638
    if (_buttonPress && mActInstance >= 0 && (size_t)mActInstance < sr.size() && cp == 0 && ch > 0)
268 andreas 7639
        _buttonPress(ch, mHandle, pressed);
266 andreas 7640
 
11 andreas 7641
    if (type == GENERAL)
7642
    {
206 andreas 7643
        MSG_DEBUG("Button type: GENERAL; System button: " << (isSystem ? "YES" : "NO") << "; CH: " << cp << ":" << ch << "; AD: " << ap << ":" << ad);
35 andreas 7644
 
206 andreas 7645
        if (isSystem && ch == SYSTEM_ITEM_SOUNDSWITCH)   // Button sounds on/off
11 andreas 7646
        {
7647
            if (pressed)
71 andreas 7648
            {
7649
                MSG_TRACE("System button sounds are toggled ...");
195 andreas 7650
                TConfig::setTemporary(false);
71 andreas 7651
                bool sstate = TConfig::getSystemSoundState();
7652
 
7653
                if (sstate)
7654
                    mActInstance = instance = 0;
7655
                else
7656
                    mActInstance = instance = 1;
7657
 
7658
                TConfig::saveSystemSoundState(!sstate);
7659
                TConfig::saveSettings();
176 andreas 7660
                mChanged = true;
198 andreas 7661
                drawButton(mActInstance, true);
71 andreas 7662
            }
7663
        }
206 andreas 7664
        else if (isSystem && ch == SYSTEM_ITEM_SETUPPAGE)  // Enter setup page
113 andreas 7665
        {
7666
            if (pressed)
7667
            {
7668
                if (gPageManager && gPageManager->haveSetupPage())
7669
                    gPageManager->callSetupPage();
7670
            }
7671
        }
206 andreas 7672
        else if (isSystem && ch == SYSTEM_ITEM_SHUTDOWN)  // Shutdown program
113 andreas 7673
        {
7674
            if (pressed)
7675
            {
7676
                if (gPageManager && gPageManager->haveShutdown())
7677
                    gPageManager->callShutdown();
7678
            }
7679
        }
206 andreas 7680
        else if (isSystem && ch == SYSTEM_ITEM_VOLUMEUP)     // System volume up
154 andreas 7681
        {
195 andreas 7682
            TConfig::setTemporary(true);
154 andreas 7683
            int vol = TConfig::getSystemVolume() + 10;
7684
 
7685
            if (vol > 100)
7686
                vol = 100;
7687
 
198 andreas 7688
            if (pressed)
7689
                TConfig::saveSystemVolume(vol);
154 andreas 7690
 
7691
            if (pressed)
7692
                mActInstance = instance = 1;
7693
            else
7694
                mActInstance = instance = 0;
7695
 
176 andreas 7696
            mChanged = true;
154 andreas 7697
            drawButton(mActInstance, true);
7698
 
198 andreas 7699
            if (pressed && gPageManager)
154 andreas 7700
            {
198 andreas 7701
                int channel = TConfig::getChannel();
7702
                int system = TConfig::getSystem();
7703
 
154 andreas 7704
                amx::ANET_COMMAND cmd;
7705
                cmd.MC = 0x000a;
7706
                cmd.device1 = channel;
163 andreas 7707
                cmd.port1 = 0;
154 andreas 7708
                cmd.system = system;
7709
                cmd.data.message_value.system = system;
7710
                cmd.data.message_value.value = 9;   // System volume
7711
                cmd.data.message_value.content.integer = vol;
7712
                cmd.data.message_value.device = channel;
163 andreas 7713
                cmd.data.message_value.port = 0;    // Must be the address port of button
154 andreas 7714
                cmd.data.message_value.type = 0x20; // Unsigned int
7715
                gPageManager->doCommand(cmd);
7716
            }
7717
        }
206 andreas 7718
        else if (isSystem && ch == SYSTEM_ITEM_VOLUMEDOWN)     // System volume down
154 andreas 7719
        {
195 andreas 7720
            TConfig::setTemporary(true);
154 andreas 7721
            int vol = TConfig::getSystemVolume() - 10;
7722
 
7723
            if (vol < 0)
7724
                vol = 0;
7725
 
198 andreas 7726
            if (pressed)
7727
                TConfig::saveSystemVolume(vol);
154 andreas 7728
 
7729
            if (pressed)
7730
                mActInstance = instance = 1;
7731
            else
7732
                mActInstance = instance = 0;
7733
 
176 andreas 7734
            mChanged = true;
154 andreas 7735
            drawButton(mActInstance, true);
7736
 
198 andreas 7737
            if (pressed && gPageManager)
154 andreas 7738
            {
198 andreas 7739
                int channel = TConfig::getChannel();
7740
                int system = TConfig::getSystem();
7741
 
154 andreas 7742
                amx::ANET_COMMAND cmd;
7743
                cmd.MC = 0x000a;
7744
                cmd.device1 = channel;
163 andreas 7745
                cmd.port1 = 0;
154 andreas 7746
                cmd.system = system;
7747
                cmd.data.message_value.system = system;
7748
                cmd.data.message_value.value = 9;   // System volume
7749
                cmd.data.message_value.content.integer = vol;
7750
                cmd.data.message_value.device = channel;
163 andreas 7751
                cmd.data.message_value.port = 0;    // Must be the address port of button
154 andreas 7752
                cmd.data.message_value.type = 0x20; // Unsigned int
7753
                gPageManager->doCommand(cmd);
7754
            }
7755
        }
206 andreas 7756
        else if (isSystem && ch == SYSTEM_ITEM_VOLUMEMUTE)     // System mute
141 andreas 7757
        {
7758
            if (pressed)
7759
            {
195 andreas 7760
                TConfig::setTemporary(true);
141 andreas 7761
                bool mute = TConfig::getMuteState();
7762
 
7763
                if (mute)
7764
                    mActInstance = instance = 0;
7765
                else
7766
                    mActInstance = instance = 1;
7767
 
7768
                TConfig::setMuteState(!mute);
7769
 
7770
                if (gPageManager && gPageManager->getCallMuteSound())
7771
                    gPageManager->getCallMuteSound()(!mute);
7772
 
176 andreas 7773
                mChanged = true;
195 andreas 7774
                drawButton(mActInstance, true);
141 andreas 7775
            }
7776
        }
206 andreas 7777
        else if (isSystem && ch == SYSTEM_ITEM_BTSAVESETTINGS)     // System button OK: Save settings
192 andreas 7778
        {
7779
            if (pressed)
7780
            {
7781
                mActInstance = instance = 1;
7782
                TConfig::setTemporary(true);
7783
                TConfig::saveSettings();
198 andreas 7784
                drawButton(mActInstance, true);
192 andreas 7785
 
217 andreas 7786
                if (gPageManager && gPageManager->getSettings() != gPageManager->getSystemSettings())
197 andreas 7787
                    gPageManager->hideSetup();
217 andreas 7788
                else if (gPageManager && gPageManager->getDisplayMessage())
7789
                    gPageManager->getDisplayMessage()("Settings were saved!", "Info");
7790
                else
7791
                    MSG_INFO("Settings were saved.");
192 andreas 7792
            }
7793
            else
7794
            {
7795
                mActInstance = instance = 0;
198 andreas 7796
                drawButton(mActInstance, true);
192 andreas 7797
            }
7798
        }
206 andreas 7799
        else if (isSystem && ch == SYSTEM_ITEM_BTCANCELSETTINGS)     // System button Cancel: Cancel settings changes
192 andreas 7800
        {
7801
            if (pressed)
7802
            {
7803
                mActInstance = instance = 1;
7804
                TConfig::reset();
198 andreas 7805
                drawButton(mActInstance, true);
192 andreas 7806
 
217 andreas 7807
                if (gPageManager && gPageManager->getSettings() != gPageManager->getSystemSettings())
197 andreas 7808
                    gPageManager->hideSetup();
192 andreas 7809
            }
7810
            else
7811
            {
7812
                mActInstance = instance = 0;
198 andreas 7813
                drawButton(mActInstance, true);
192 andreas 7814
            }
7815
        }
206 andreas 7816
        else if (isSystem && ch == SYSTEM_ITEM_SIPENABLE)     // SIP: enabled/disabled
198 andreas 7817
        {
7818
            if (pressed)
7819
            {
7820
                TConfig::setTemporary(true);
7821
                bool st = TConfig::getSIPstatus();
7822
                mActInstance = instance = (st ? 0 : 1);
7823
                mChanged = true;
7824
                TConfig::setSIPstatus(!st);
7825
                drawButton(mActInstance, true);
7826
            }
7827
        }
206 andreas 7828
        else if (isSystem && ch == SYSTEM_ITEM_DEBUGINFO)    // Debug info
192 andreas 7829
        {
7830
            if (pressed)
7831
            {
7832
                TConfig::setTemporary(true);
7833
                uint ll = TConfig::getLogLevelBits();
7834
                bool st = (ll & HLOG_INFO) ? true : false;
7835
                mActInstance = instance = (st ? 0 : 1);
7836
                ll = (st ? (ll &= RLOG_INFO) : (ll |= HLOG_INFO));
7837
                mChanged = true;
7838
                TConfig::saveLogLevel(ll);
195 andreas 7839
                drawButton(mActInstance, true);
192 andreas 7840
            }
7841
        }
206 andreas 7842
        else if (isSystem && ch == SYSTEM_ITEM_DEBUGWARNING)    // Debug warning
192 andreas 7843
        {
7844
            if (pressed)
7845
            {
7846
                TConfig::setTemporary(true);
7847
                uint ll = TConfig::getLogLevelBits();
7848
                bool st = (ll & HLOG_WARNING) ? true : false;
7849
                mActInstance = instance = (st ? 0 : 1);
7850
                ll = (st ? (ll &= RLOG_WARNING) : (ll |= HLOG_WARNING));
7851
                mChanged = true;
7852
                TConfig::saveLogLevel(ll);
195 andreas 7853
                drawButton(mActInstance, true);
192 andreas 7854
            }
7855
        }
206 andreas 7856
        else if (isSystem && ch == SYSTEM_ITEM_DEBUGERROR)    // Debug error
192 andreas 7857
        {
7858
            if (pressed)
7859
            {
7860
                TConfig::setTemporary(true);
7861
                uint ll = TConfig::getLogLevelBits();
7862
                bool st = (ll & HLOG_ERROR) ? true : false;
7863
                mActInstance = instance = (st ? 0 : 1);
7864
                ll = (st ? (ll &= RLOG_ERROR) : (ll |= HLOG_ERROR));
7865
                mChanged = true;
7866
                TConfig::saveLogLevel(ll);
195 andreas 7867
                drawButton(mActInstance, true);
192 andreas 7868
            }
7869
        }
206 andreas 7870
        else if (isSystem && ch == SYSTEM_ITEM_DEBUGTRACE)    // Debug trace
192 andreas 7871
        {
7872
            if (pressed)
7873
            {
7874
                TConfig::setTemporary(true);
7875
                uint ll = TConfig::getLogLevelBits();
7876
                bool st = (ll & HLOG_TRACE) ? true : false;
7877
                mActInstance = instance = (st ? 0 : 1);
7878
                ll = (st ? (ll &= RLOG_TRACE) : (ll |= HLOG_TRACE));
7879
                mChanged = true;
7880
                TConfig::saveLogLevel(ll);
195 andreas 7881
                drawButton(mActInstance, true);
192 andreas 7882
            }
7883
        }
206 andreas 7884
        else if (isSystem && ch == SYSTEM_ITEM_DEBUGDEBUG)    // Debug debug
192 andreas 7885
        {
7886
            if (pressed)
7887
            {
7888
                TConfig::setTemporary(true);
7889
                uint ll = TConfig::getLogLevelBits();
7890
                bool st = (ll & HLOG_DEBUG) ? true : false;
7891
                mActInstance = instance = (st ? 0 : 1);
7892
                ll = (st ? (ll &= RLOG_DEBUG) : (ll |= HLOG_DEBUG));
7893
                mChanged = true;
7894
                TConfig::saveLogLevel(ll);
195 andreas 7895
                drawButton(mActInstance, true);
192 andreas 7896
            }
7897
        }
206 andreas 7898
        else if (isSystem && ch == SYSTEM_ITEM_DEBUGPROTOCOL)    // Debug protocol
192 andreas 7899
        {
7900
            if (pressed)
7901
            {
7902
                TConfig::setTemporary(true);
7903
                uint ll = TConfig::getLogLevelBits();
7904
                bool st = (ll & HLOG_PROTOCOL) == HLOG_PROTOCOL ? true : false;
7905
                mActInstance = instance = (st ? 0 : 1);
7906
                ll = (st ? (ll &= RLOG_PROTOCOL) : (ll |= HLOG_PROTOCOL));
7907
                mChanged = true;
7908
                TConfig::saveLogLevel(ll);
195 andreas 7909
                drawButton(mActInstance, true);
192 andreas 7910
 
7911
                if (gPageManager)
7912
                    gPageManager->updateActualPage();
7913
            }
7914
        }
206 andreas 7915
        else if (isSystem && ch == SYSTEM_ITEM_DEBUGALL)    // Debug all
192 andreas 7916
        {
7917
            if (pressed)
7918
            {
7919
                TConfig::setTemporary(true);
7920
                uint ll = TConfig::getLogLevelBits();
7921
                bool st = (ll & HLOG_ALL) == HLOG_ALL ? true : false;
7922
                mActInstance = instance = (st ? 0 : 1);
7923
                ll = (st ? (ll &= RLOG_ALL) : (ll |= HLOG_ALL));
7924
                mChanged = true;
7925
                TConfig::saveLogLevel(ll);
195 andreas 7926
                drawButton(mActInstance, true);
192 andreas 7927
 
7928
                if (gPageManager)
7929
                    gPageManager->updateActualPage();
7930
            }
7931
        }
206 andreas 7932
        else if (isSystem && ch == SYSTEM_ITEM_DEBUGPROFILE)    // Log profiling
192 andreas 7933
        {
7934
            if (pressed)
7935
            {
7936
                TConfig::setTemporary(true);
7937
                bool st = TConfig::getProfiling();
7938
                mActInstance = instance = (st ? 0 : 1);
7939
                mChanged = true;
7940
                TConfig::saveProfiling(!st);
195 andreas 7941
                drawButton(mActInstance, true);
192 andreas 7942
            }
7943
        }
206 andreas 7944
        else if (isSystem && ch == SYSTEM_ITEM_DEBUGLONG)    // Log long format
192 andreas 7945
        {
7946
            if (pressed)
7947
            {
7948
                TConfig::setTemporary(true);
7949
                bool st = TConfig::isLongFormat();
7950
                mActInstance = instance = (st ? 0 : 1);
7951
                mChanged = true;
7952
                TConfig::saveFormat(!st);
195 andreas 7953
                drawButton(mActInstance, true);
192 andreas 7954
            }
7955
        }
208 andreas 7956
        else if (isSystem && ch == SYSTEM_ITEM_LOGRESET)    // Log reset path
7957
        {
209 andreas 7958
            if (pressed)
208 andreas 7959
            {
209 andreas 7960
                char *HOME = getenv("HOME");
7961
                string logFile = TConfig::getLogFile();
208 andreas 7962
 
209 andreas 7963
                if (HOME)
7964
                {
7965
                    logFile = HOME;
7966
                    logFile += "/tpanel/tpanel.log";
7967
                }
208 andreas 7968
 
209 andreas 7969
                ulong handle = (SYSTEM_PAGE_LOGGING << 16) | SYSTEM_PAGE_LOG_TXLOGFILE;
7970
                TConfig::setTemporary(true);
7971
                TConfig::saveLogFile(logFile);
271 andreas 7972
                MSG_DEBUG("Setting text \"" << logFile << "\" to button " << handleToString(handle));
209 andreas 7973
 
7974
                if (gPageManager)
7975
                    gPageManager->setTextToButton(handle, logFile, true);
7976
            }
208 andreas 7977
        }
7978
        else if (isSystem && ch == SYSTEM_ITEM_LOGFILEOPEN) // Log file dialog
7979
        {
209 andreas 7980
            if (pressed && gPageManager && gPageManager->getFileDialogFunction())
7981
            {
7982
                TConfig::setTemporary(true);
7983
                ulong handle = (SYSTEM_PAGE_LOGGING << 16) | SYSTEM_PAGE_LOG_TXLOGFILE;
7984
                string currFile = TConfig::getLogFile();
7985
                gPageManager->getFileDialogFunction()(handle, currFile, "*.log *.txt", "log");
7986
            }
208 andreas 7987
        }
206 andreas 7988
        else if (isSystem && ch == SYSTEM_ITEM_FTPDOWNLOAD)    // FTP download surface button
195 andreas 7989
        {
7990
            if (pressed)
7991
            {
206 andreas 7992
                TConfig::setTemporary(false);
7993
                string surfaceOld = TConfig::getFtpSurface();
7994
                TConfig::setTemporary(true);
7995
                string surfaceNew = TConfig::getFtpSurface();
7996
 
7997
                MSG_DEBUG("Surface difference: Old: " << surfaceOld << ", New: " << surfaceNew);
7998
 
7999
                if (gPageManager && gPageManager->getDownloadSurface())
8000
                {
8001
                    size_t size = gPageManager->getFtpSurfaceSize(surfaceNew);
208 andreas 8002
                    gPageManager->getDownloadSurface()(surfaceNew, size);
206 andreas 8003
                }
8004
            }
8005
        }
8006
        else if (isSystem && ch == SYSTEM_ITEM_FTPPASSIVE)    // FTP passive mode
8007
        {
8008
            if (pressed)
8009
            {
8010
                TConfig::setTemporary(true);
195 andreas 8011
                bool st = TConfig::getFtpPassive();
8012
                mActInstance = instance = (st ? 0 : 1);
8013
                mChanged = true;
8014
                TConfig::saveFtpPassive(!st);
8015
                drawButton(mActInstance, true);
8016
            }
8017
        }
206 andreas 8018
        else if (isSystem && ch == SYSTEM_ITEM_SOUNDPLAYSYSSOUND)    // Play system sound
195 andreas 8019
        {
8020
            if (pressed)
8021
            {
8022
                TConfig::setTemporary(true);
223 andreas 8023
                string sound = TConfig::getProjectPath() + "/__system/graphics/sounds/" + TConfig::getSystemSound();
195 andreas 8024
 
223 andreas 8025
                if (!sound.empty() && gPageManager && gPageManager->getCallPlaySound())
195 andreas 8026
                    gPageManager->getCallPlaySound()(sound);
8027
            }
8028
        }
206 andreas 8029
        else if (isSystem && ch == SYSTEM_ITEM_SOUNDPLAYBEEP)    // Play single beep
195 andreas 8030
        {
8031
            if (pressed)
8032
            {
8033
                TConfig::setTemporary(true);
223 andreas 8034
                string sound = TConfig::getProjectPath() + "/__system/graphics/sounds/" + TConfig::getSingleBeepSound();
195 andreas 8035
 
8036
                if (!sound.empty() && gPageManager && gPageManager->getCallPlaySound())
8037
                    gPageManager->getCallPlaySound()(sound);
8038
            }
8039
        }
206 andreas 8040
        else if (isSystem && ch == SYSTEM_ITEM_SOUNDPLAYDBEEP)    // Play double beep
195 andreas 8041
        {
8042
            if (pressed)
8043
            {
8044
                TConfig::setTemporary(true);
223 andreas 8045
                string sound = TConfig::getProjectPath() + "/__system/graphics/sounds/" + TConfig::getDoubleBeepSound();
195 andreas 8046
 
8047
                if (!sound.empty() && gPageManager && gPageManager->getCallPlaySound())
8048
                    gPageManager->getCallPlaySound()(sound);
8049
            }
8050
        }
223 andreas 8051
        else if (isSystem && ch == SYSTEM_ITEM_SOUNDPLAYTESTSOUND)    // Play test sound
8052
        {
8053
            if (pressed)
8054
            {
8055
                TConfig::setTemporary(true);
8056
                string sound = TConfig::getProjectPath() + "/__system/graphics/sounds/audioTest.wav";
8057
 
8058
                if (gPageManager && gPageManager->getCallPlaySound())
8059
                    gPageManager->getCallPlaySound()(sound);
8060
            }
8061
        }
206 andreas 8062
        else if (isSystem && ch == SYSTEM_ITEM_SIPIPV4)    // SIP: IPv4
198 andreas 8063
        {
8064
            if (pressed)
8065
            {
8066
                TConfig::setTemporary(true);
8067
                bool st = TConfig::getSIPnetworkIPv4();
8068
                mActInstance = instance = (st ? 0 : 1);
8069
                mChanged = true;
8070
                TConfig::setSIPnetworkIPv4(!st);
8071
                drawButton(mActInstance, true);
8072
            }
8073
        }
206 andreas 8074
        else if (isSystem && ch == SYSTEM_ITEM_SIPIPV6)    // SIP: IPv6
198 andreas 8075
        {
8076
            if (pressed)
8077
            {
8078
                TConfig::setTemporary(true);
8079
                bool st = TConfig::getSIPnetworkIPv6();
8080
                mActInstance = instance = (st ? 0 : 1);
8081
                mChanged = true;
8082
                TConfig::setSIPnetworkIPv6(!st);
8083
                drawButton(mActInstance, true);
8084
            }
8085
        }
206 andreas 8086
        else if (isSystem && ch == SYSTEM_ITEM_SIPIPHONE)    // SIP: internal phone
198 andreas 8087
        {
8088
            if (pressed)
8089
            {
8090
                TConfig::setTemporary(true);
8091
                bool st = TConfig::getSIPiphone();
8092
                mActInstance = instance = (st ? 0 : 1);
8093
                mChanged = true;
8094
                TConfig::setSIPiphone(!st);
8095
                drawButton(mActInstance, true);
8096
            }
8097
        }
195 andreas 8098
#ifdef __ANDROID__
206 andreas 8099
        else if (isSystem && ch == SYSTEM_ITEM_VIEWSCALEFIT)    // Scale to fit
195 andreas 8100
        {
8101
            if (pressed)
8102
            {
8103
                TConfig::setTemporary(true);
8104
                bool st = TConfig::getScale();
8105
                mActInstance = instance = (st ? 0 : 1);
8106
                mChanged = true;
8107
                TConfig::saveScale(!st);
8108
                drawButton(mActInstance, true);
8109
            }
8110
        }
206 andreas 8111
        else if (isSystem && ch == SYSTEM_ITEM_VIEWBANNER)    // Show banner (disabled)
195 andreas 8112
        {
8113
            if (sr[0].oo < 0)
8114
            {
8115
                sr[0].oo = 128;
8116
                mChanged = true;
8117
                mActInstance = 0;
8118
                drawButton(mActInstance, true);
8119
            }
8120
        }
8121
#else
206 andreas 8122
        else if (isSystem && ch == SYSTEM_ITEM_VIEWSCALEFIT)    // Scale to fit (disabled)
195 andreas 8123
        {
8124
            if (sr[0].oo < 0)
8125
            {
8126
                sr[0].oo = 128;
8127
                mChanged = true;
8128
                mActInstance = 0;
8129
                drawButton(mActInstance, true);
8130
            }
8131
        }
206 andreas 8132
        else if (isSystem && ch == SYSTEM_ITEM_VIEWBANNER)    // Show banner
195 andreas 8133
        {
8134
            if (pressed)
8135
            {
8136
                TConfig::setTemporary(true);
8137
                bool st = TConfig::showBanner();
8138
                mActInstance = instance = (st ? 0 : 1);
8139
                mChanged = true;
8140
                TConfig::saveBanner(st);
8141
                drawButton(mActInstance, true);
8142
            }
8143
        }
8144
#endif
206 andreas 8145
        else if (isSystem && ch == SYSTEM_ITEM_VIEWNOTOOLBAR)    // Suppress toolbar
195 andreas 8146
        {
8147
            if (pressed)
8148
            {
8149
                TConfig::setTemporary(true);
8150
                bool st = TConfig::getToolbarSuppress();
8151
                mActInstance = instance = (st ? 0 : 1);
8152
                mChanged = true;
8153
                TConfig::saveToolbarSuppress(!st);
8154
                drawButton(mActInstance, true);
8155
            }
8156
        }
206 andreas 8157
        else if (isSystem && ch == SYSTEM_ITEM_VIEWTOOLBAR)    // Force toolbar
195 andreas 8158
        {
8159
            if (pressed)
8160
            {
8161
                TConfig::setTemporary(true);
198 andreas 8162
 
8163
                if (TConfig::getToolbarSuppress())
8164
                {
8165
                    if (sr[0].oo < 0)
8166
                    {
8167
                        sr[0].oo = 128;
8168
                        mChanged = true;
8169
                        mActInstance = 0;
8170
                        drawButton(mActInstance, true);
8171
                    }
8172
                }
8173
                else
8174
                {
8175
                    if (sr[0].oo >= 0)
8176
                        sr[0].oo = -1;
8177
 
8178
                    bool st = TConfig::getToolbarForce();
8179
                    mActInstance = instance = (st ? 0 : 1);
8180
                    mChanged = true;
8181
                    TConfig::saveToolbarForce(!st);
8182
                    drawButton(mActInstance, true);
8183
                }
195 andreas 8184
            }
8185
        }
206 andreas 8186
        else if (isSystem && ch == SYSTEM_ITEM_VIEWROTATE)    // Lock rotation
195 andreas 8187
        {
8188
            if (pressed)
8189
            {
8190
                TConfig::setTemporary(true);
8191
                bool st = TConfig::getRotationFixed();
8192
                mActInstance = instance = (st ? 0 : 1);
8193
                mChanged = true;
8194
                TConfig::setRotationFixed(!st);
8195
                drawButton(mActInstance, true);
8196
            }
8197
        }
71 andreas 8198
        else if (fb == FB_MOMENTARY)
8199
        {
8200
            if (pressed)
15 andreas 8201
                instance = 1;
14 andreas 8202
            else
15 andreas 8203
                instance = 0;
8204
 
71 andreas 8205
            MSG_DEBUG("Flavor FB_MOMENTARY, instance=" << instance);
15 andreas 8206
            mActInstance = instance;
176 andreas 8207
            mChanged = true;
163 andreas 8208
 
8209
            if (pushFunc.empty() || (!pushFunc.empty() && instance == 0))
8210
                drawButton(instance);
8211
 
15 andreas 8212
            // If there is nothing in "hs", then it depends on the pixel of the
8213
            // layer. Only if the pixel the coordinates point to are not
8214
            // transparent, the button takes the click.
31 andreas 8215
            if (hs.empty() && isPixelTransparent(sx, sy))
15 andreas 8216
                return false;
8217
 
79 andreas 8218
            // Play sound, if one is defined
90 andreas 8219
            if (gPageManager)
8220
            {
165 andreas 8221
                if (pressed && gPageManager->havePlaySound() && !sr[0].sd.empty() && strCaseCompare(sr[0].sd, "None") != 0)
141 andreas 8222
                    gPageManager->getCallPlaySound()(TConfig::getProjectPath() + "/sounds/" + sr[0].sd);
165 andreas 8223
                else if (!pressed && gPageManager->havePlaySound() && !sr[1].sd.empty() && strCaseCompare(sr[1].sd, "None") != 0)
141 andreas 8224
                    gPageManager->getCallPlaySound()(TConfig::getProjectPath() + "/sounds/" + sr[1].sd);
90 andreas 8225
            }
79 andreas 8226
 
15 andreas 8227
            if (pushFunc.empty())   // Don't draw the button if it has a push function defined
8228
                showLastButton();
8229
            else
14 andreas 8230
                mActInstance = 0;
15 andreas 8231
        }
8232
        else if (fb == FB_CHANNEL || fb == FB_NONE)
8233
        {
8234
            if (pressed)
8235
                instance = 1;
8236
            else
8237
                instance = 0;
14 andreas 8238
 
71 andreas 8239
            MSG_DEBUG("Flavor FB_CHANNEL, instance=" << instance);
15 andreas 8240
            // If there is nothing in "hs", then it depends on the pixel of the
8241
            // layer. Only if the pixel the coordinates point to are not
8242
            // transparent, the button takes the click.
31 andreas 8243
            if (hs.empty() && isPixelTransparent(sx, sy))
15 andreas 8244
                return false;
14 andreas 8245
        }
15 andreas 8246
        else if (fb == FB_INV_CHANNEL)
8247
        {
8248
            if (pressed)
8249
                instance = 0;
8250
            else
8251
                instance = 1;
14 andreas 8252
 
71 andreas 8253
            MSG_DEBUG("Flavor FB_INV_CHANNEL, instance=" << instance);
15 andreas 8254
            // If there is nothing in "hs", then it depends on the pixel of the
8255
            // layer. Only if the pixel the coordinates point to are not
8256
            // transparent, the button takes the click.
31 andreas 8257
            if (hs.empty() && isPixelTransparent(sx, sy))
15 andreas 8258
                return false;
79 andreas 8259
 
8260
            // Play sound, if one is defined
90 andreas 8261
            if (gPageManager)
8262
            {
165 andreas 8263
                if (pressed && gPageManager->havePlaySound() && !sr[1].sd.empty() && strCaseCompare(sr[0].sd, "None") != 0)
141 andreas 8264
                    gPageManager->getCallPlaySound()(TConfig::getProjectPath() + "/sounds/" + sr[1].sd);
165 andreas 8265
                else if (!pressed && gPageManager->havePlaySound() && !sr[0].sd.empty() && strCaseCompare(sr[1].sd, "None") != 0)
141 andreas 8266
                    gPageManager->getCallPlaySound()(TConfig::getProjectPath() + "/sounds/" + sr[0].sd);
90 andreas 8267
            }
15 andreas 8268
        }
8269
        else if (fb == FB_ALWAYS_ON)
14 andreas 8270
        {
154 andreas 8271
            int oldInst = mActInstance;
15 andreas 8272
            instance = 1;
8273
            mActInstance = 1;
71 andreas 8274
            MSG_DEBUG("Flavor FB_ALWAYS_ON, instance=" << instance);
154 andreas 8275
 
8276
            if (oldInst != mActInstance)        // This should never become true!
176 andreas 8277
            {
8278
                mChanged = true;
154 andreas 8279
                drawButton(instance, false);
176 andreas 8280
            }
154 andreas 8281
 
15 andreas 8282
            // If there is nothing in "hs", then it depends on the pixel of the
8283
            // layer. Only if the pixel the coordinates point to are not
8284
            // transparent, the button takes the click.
31 andreas 8285
            if (hs.empty() && isPixelTransparent(sx, sy))
15 andreas 8286
                return false;
8287
 
79 andreas 8288
            // Play sound, if one is defined
165 andreas 8289
            if (pressed && gPageManager && gPageManager->havePlaySound() && !sr[1].sd.empty() && strCaseCompare(sr[1].sd, "None") != 0)
141 andreas 8290
                gPageManager->getCallPlaySound()(TConfig::getProjectPath() + "/sounds/" + sr[1].sd);
71 andreas 8291
        }
8292
 
15 andreas 8293
        if ((cp && ch) || !op.empty())
8294
        {
14 andreas 8295
            scmd.device = TConfig::getChannel();
8296
            scmd.port = cp;
8297
            scmd.channel = ch;
8298
 
15 andreas 8299
            if (op.empty())
8300
            {
8301
                if (instance)
8302
                    scmd.MC = 0x0084;
8303
                else
8304
                    scmd.MC = 0x0085;
8305
            }
14 andreas 8306
            else
15 andreas 8307
            {
8308
                scmd.MC = 0x008b;
8309
                scmd.msg = op;
8310
            }
14 andreas 8311
 
271 andreas 8312
            MSG_DEBUG("Button " << bi << ", " << na << " with handle " << handleToString(mHandle));
14 andreas 8313
            MSG_DEBUG("Sending to device <" << scmd.device << ":" << scmd.port << ":0> channel " << scmd.channel << " value 0x" << std::setw(2) << std::setfill('0') << std::hex << scmd.MC << " (" << (pressed?"PUSH":"RELEASE") << ")");
8314
 
8315
            if (gAmxNet)
15 andreas 8316
            {
8317
                if (scmd.MC != 0x008b || (pressed && scmd.MC == 0x008b))
8318
                    gAmxNet->sendCommand(scmd);
8319
            }
14 andreas 8320
            else
8321
                MSG_WARNING("Missing global class TAmxNet. Can't send a message!");
8322
        }
8323
    }
15 andreas 8324
    else if (type == MULTISTATE_GENERAL)
8325
    {
79 andreas 8326
        // Play sound, if one is defined
165 andreas 8327
        if (pressed && gPageManager && gPageManager->havePlaySound() && !sr[mActInstance].sd.empty() && strCaseCompare(sr[mActInstance].sd, "None") != 0)
141 andreas 8328
            gPageManager->getCallPlaySound()(TConfig::getProjectPath() + "/sounds/" + sr[mActInstance].sd);
79 andreas 8329
 
15 andreas 8330
        if ((cp && ch) || !op.empty())
8331
        {
8332
            scmd.device = TConfig::getChannel();
8333
            scmd.port = cp;
8334
            scmd.channel = ch;
14 andreas 8335
 
15 andreas 8336
            if (op.empty())
8337
            {
8338
                if (pressed || fb == FB_ALWAYS_ON)
8339
                    scmd.MC = 0x0084;
8340
                else
8341
                    scmd.MC = 0x0085;
8342
            }
8343
            else
8344
            {
8345
                scmd.MC = 0x008b;
8346
                scmd.msg = op;
8347
            }
8348
 
271 andreas 8349
            MSG_DEBUG("Button " << bi << ", " << na << " with handle " << handleToString(mHandle));
15 andreas 8350
            MSG_DEBUG("Sending to device <" << scmd.device << ":" << scmd.port << ":0> channel " << scmd.channel << " value 0x" << std::setw(2) << std::setfill('0') << std::hex << scmd.MC << " (" << (pressed?"PUSH":"RELEASE") << ")");
8351
 
8352
            if (gAmxNet)
8353
            {
8354
                if (scmd.MC != 0x008b || (pressed && scmd.MC == 0x008b))
8355
                    gAmxNet->sendCommand(scmd);
8356
            }
8357
            else
8358
                MSG_WARNING("Missing global class TAmxNet. Can't send a message!");
8359
        }
8360
    }
49 andreas 8361
    else if (type == BARGRAPH && lf.find("active") != string::npos)
8362
    {
8363
        // Find the click position
8364
        int level = 0;
15 andreas 8365
 
49 andreas 8366
        if (dr.compare("horizontal") == 0)
8367
        {
8368
            level = (ri ? (wt - x) : x);
8369
            level = (int)((double)(rh - rl) / (double)wt * (double)level);
8370
        }
8371
        else
8372
        {
8373
            level = (ri ? y : (ht - y));
8374
            level = (int)((double)(rh - rl) / (double)ht * (double)level);
8375
        }
8376
 
8377
        // Draw the bargraph
8378
        if (!drawBargraph(mActInstance, level, visible))
8379
            return false;
8380
 
8381
        // Handle click
192 andreas 8382
        if (isSystem && lv == 9)    // System volume button
49 andreas 8383
        {
141 andreas 8384
            TConfig::saveSystemVolume(level);
8385
            TConfig::saveSettings();
8386
        }
8387
        else if ((cp && ch) || !op.empty())
8388
        {
49 andreas 8389
            scmd.device = TConfig::getChannel();
8390
            scmd.port = cp;
8391
            scmd.channel = ch;
8392
 
8393
            if (op.empty())
8394
            {
8395
                if (pressed || fb == FB_ALWAYS_ON)
8396
                    scmd.MC = 0x0084;
8397
                else
8398
                    scmd.MC = 0x0085;
8399
            }
8400
            else
8401
            {
8402
                scmd.MC = 0x008b;
8403
                scmd.msg = op;
8404
            }
8405
 
8406
            if (gAmxNet)
8407
            {
8408
                if (scmd.MC != 0x008b || (pressed && scmd.MC == 0x008b))
8409
                    gAmxNet->sendCommand(scmd);
8410
            }
8411
            else
8412
                MSG_WARNING("Missing global class TAmxNet. Can't send a message!");
8413
        }
8414
 
8415
        // Send the level
318 andreas 8416
        if (lp && lv && gPageManager && gPageManager->getLevelSendState())
49 andreas 8417
        {
8418
            scmd.device = TConfig::getChannel();
8419
            scmd.port = lp;
8420
            scmd.channel = lv;
8421
            scmd.level = lv;
8422
            scmd.value = level;
8423
            scmd.MC = 0x008a;
8424
 
8425
            if (gAmxNet)
8426
                gAmxNet->sendCommand(scmd);
8427
        }
8428
    }
50 andreas 8429
    else if (type == TEXT_INPUT)
8430
    {
8431
        MSG_DEBUG("Text area detected. Switching on keyboard");
8432
        // Drawing background graphic (visible part of area)
8433
        drawTextArea(mActInstance);
8434
    }
49 andreas 8435
 
15 andreas 8436
    /* FIXME: Move the following to class TPageManager!
8437
     *        To do that, the preconditions are to be implemented. It must be
8438
     *        possible to find the button and get access to the credentials
8439
     *        of it.
8440
     */
14 andreas 8441
    if (!pushFunc.empty() && pressed)
8442
    {
53 andreas 8443
        MSG_DEBUG("Executing a push function ...");
14 andreas 8444
        vector<PUSH_FUNC_T>::iterator iter;
8445
 
118 andreas 8446
        for (iter = pushFunc.begin(); iter != pushFunc.end(); ++iter)
14 andreas 8447
        {
168 andreas 8448
            MSG_DEBUG("Testing for function \"" << iter->pfType << "\"");
53 andreas 8449
 
163 andreas 8450
            if (fb == FB_MOMENTARY || fb == FB_NONE)
8451
                mActInstance = 0;
8452
            else if (fb == FB_ALWAYS_ON || fb == FB_INV_CHANNEL)
8453
                mActInstance = 1;
8454
 
168 andreas 8455
            if (strCaseCompare(iter->pfType, "SSHOW") == 0)            // show popup
11 andreas 8456
            {
14 andreas 8457
                if (gPageManager)
8458
                    gPageManager->showSubPage(iter->pfName);
11 andreas 8459
            }
168 andreas 8460
            else if (strCaseCompare(iter->pfType, "SHIDE") == 0)       // hide popup
11 andreas 8461
            {
14 andreas 8462
                if (gPageManager)
8463
                    gPageManager->hideSubPage(iter->pfName);
11 andreas 8464
            }
168 andreas 8465
            else if (strCaseCompare(iter->pfType, "SCGROUP") == 0)     // hide group
14 andreas 8466
            {
8467
                if (gPageManager)
8468
                    gPageManager->closeGroup(iter->pfName);
8469
            }
271 andreas 8470
            else if (strCaseCompare(iter->pfType, "SCPAGE") == 0)      // flip to page
8471
            {
8472
                if (gPageManager && !iter->pfName.empty())
8473
                    gPageManager->setPage(iter->pfName);
8474
            }
168 andreas 8475
            else if (strCaseCompare(iter->pfType, "STAN") == 0)        // Flip to standard page
14 andreas 8476
            {
8477
                if (gPageManager)
8478
                {
168 andreas 8479
                    if (!iter->pfName.empty())
8480
                        gPageManager->setPage(iter->pfName);
8481
                    else
15 andreas 8482
                    {
168 andreas 8483
                        TPage *page = gPageManager->getActualPage();
15 andreas 8484
 
168 andreas 8485
                        if (!page)
8486
                        {
8487
                            MSG_DEBUG("Internal error: No actual page found!");
8488
                            return false;
8489
                        }
15 andreas 8490
 
168 andreas 8491
                        TSettings *settings = gPageManager->getSettings();
8492
 
205 andreas 8493
                        if (settings && settings->getPowerUpPage().compare(page->getName()) != 0)
168 andreas 8494
                            gPageManager->setPage(settings->getPowerUpPage());
8495
                    }
15 andreas 8496
                }
8497
            }
168 andreas 8498
            else if (strCaseCompare(iter->pfType, "FORGET") == 0)      // Flip to page and forget
15 andreas 8499
            {
168 andreas 8500
                if (gPageManager && !iter->pfName.empty())
8501
                        gPageManager->setPage(iter->pfName, true);
8502
            }
8503
            else if (strCaseCompare(iter->pfType, "PREV") == 0)        // Flip to previous page
8504
            {
15 andreas 8505
                if (gPageManager)
8506
                {
8507
                    int old = gPageManager->getPreviousPageNumber();
8508
 
8509
                    if (old > 0)
8510
                        gPageManager->setPage(old);
8511
                }
8512
            }
168 andreas 8513
            else if (strCaseCompare(iter->pfType, "STOGGLE") == 0)     // Toggle popup state
15 andreas 8514
            {
146 andreas 8515
                if (!iter->pfName.empty() && gPageManager)
15 andreas 8516
                {
14 andreas 8517
                    TSubPage *page = gPageManager->getSubPage(iter->pfName);
11 andreas 8518
 
146 andreas 8519
                    if (!page)      // Is the page not in cache?
8520
                    {               // No, then load it
8521
                        gPageManager->showSubPage(iter->pfName);
8522
                        return true;
8523
                    }
8524
 
8525
                    if (page->isVisible())
14 andreas 8526
                        gPageManager->hideSubPage(iter->pfName);
146 andreas 8527
                    else
14 andreas 8528
                        gPageManager->showSubPage(iter->pfName);
8529
                }
8530
            }
168 andreas 8531
            else if (strCaseCompare(iter->pfType, "SCPANEL") == 0)   // Hide all popups
146 andreas 8532
            {
8533
                if (gPageManager)
8534
                {
8535
                    TSubPage *page = gPageManager->getFirstSubPage();
8536
 
8537
                    while (page)
8538
                    {
8539
                        page->drop();
8540
                        page = gPageManager->getNextSubPage();
8541
                    }
8542
                }
8543
            }
8544
            else
8545
            {
8546
                MSG_WARNING("Unknown page flip command " << iter->pfType);
8547
            }
11 andreas 8548
        }
8549
    }
15 andreas 8550
 
147 andreas 8551
    if (!cm.empty() && co == 0 && pressed)      // Feed command to ourself?
8552
    {                                           // Yes, then feed it into command queue.
149 andreas 8553
        MSG_DEBUG("Button has a self feed command");
147 andreas 8554
 
151 andreas 8555
        int channel = TConfig::getChannel();
8556
        int system = TConfig::getSystem();
8557
 
147 andreas 8558
        if (gPageManager)
8559
        {
8560
            amx::ANET_COMMAND cmd;
8561
            cmd.MC = 0x000c;
151 andreas 8562
            cmd.device1 = channel;
301 andreas 8563
            cmd.port1 = 1;
151 andreas 8564
            cmd.system = system;
8565
            cmd.data.message_string.device = channel;
301 andreas 8566
            cmd.data.message_string.port = 1;   // Must be 1
151 andreas 8567
            cmd.data.message_string.system = system;
8568
            cmd.data.message_string.type = 1;   // 8 bit char string
149 andreas 8569
 
8570
            vector<string>::iterator iter;
8571
 
8572
            for (iter = cm.begin(); iter != cm.end(); ++iter)
8573
            {
8574
                cmd.data.message_string.length = iter->length();
8575
                memset(&cmd.data.message_string.content, 0, sizeof(cmd.data.message_string.content));
205 andreas 8576
                strncpy((char *)&cmd.data.message_string.content, iter->c_str(), sizeof(cmd.data.message_string.content)-1);
318 andreas 8577
                MSG_DEBUG("Executing system command: " << *iter);
149 andreas 8578
                gPageManager->doCommand(cmd);
8579
            }
147 andreas 8580
        }
8581
    }
8582
    else if (!cm.empty() && pressed)
8583
    {
149 andreas 8584
        MSG_DEBUG("Button sends a command on port " << co);
147 andreas 8585
 
8586
        if (gPageManager)
149 andreas 8587
        {
8588
            vector<string>::iterator iter;
8589
 
8590
            for (iter = cm.begin(); iter != cm.end(); ++iter)
8591
                gPageManager->sendCommandString(co, *iter);
8592
        }
147 andreas 8593
    }
8594
 
15 andreas 8595
    return true;
11 andreas 8596
}
8597
 
7 andreas 8598
/**
8599
 * Based on the pixels in the \a basePix, the function decides whether to return
8600
 * the value of \a col1 or \a col2. A red pixel returns the color \a col1 and
8601
 * a green pixel returns the color \a col2. If there is no red and no green
8602
 * pixel, a transparent pixel is returned.
8603
 *
8604
 * @param basePix
8605
 * This is a pixel from a mask containing red and/or green pixels.
8606
 *
8607
 * @param maskPix
8608
 * This is a pixel from a mask containing more or less tranparent pixels. If
8609
 * the alpha channel of \a basePix is 0 (transparent) this pixel is returned.
8610
 *
8611
 * @param col1
8612
 * The first color.
8613
 *
8614
 * @param col2
8615
 * The second color.
8616
 *
8617
 * @return
8618
 * An array containing the color for one pixel.
8619
 */
10 andreas 8620
SkColor TButton::baseColor(SkColor basePix, SkColor maskPix, SkColor col1, SkColor col2)
7 andreas 8621
{
8622
    uint alpha = SkColorGetA(basePix);
23 andreas 8623
    uint green = SkColorGetG(basePix);
260 andreas 8624
    uint red = 0;
8625
//#if (defined(__x86_64__) || defined(_M_X64)) && !defined(__MACH__)
8626
    if (isBigEndian())
8627
        red = SkColorGetB(basePix);
8628
    else
8629
        red = SkColorGetR(basePix);
8630
//#endif
7 andreas 8631
 
241 andreas 8632
    if (alpha == 0)
7 andreas 8633
        return maskPix;
8634
 
8635
    if (red && green)
8636
    {
241 andreas 8637
        if (red < green)
8638
            return col2;
8639
 
171 andreas 8640
        return col1;
7 andreas 8641
    }
8642
 
8643
    if (red)
8644
        return col1;
8645
 
8646
    if (green)
8647
        return col2;
8648
 
8649
    return SK_ColorTRANSPARENT; // transparent pixel
8650
}
8651
 
8652
TEXT_EFFECT TButton::textEffect(const std::string& effect)
8653
{
8654
    DECL_TRACER("TButton::textEffect(const std::string& effect)");
8655
 
8656
    if (effect == "Outline-S")
8657
        return EFFECT_OUTLINE_S;
8658
    else if (effect == "Outline-M")
8659
        return EFFECT_OUTLINE_M;
8660
    else if (effect == "Outline-L")
8661
        return EFFECT_OUTLINE_L;
8662
    else if (effect == "Outline-X")
8663
        return EFFECT_OUTLINE_X;
8664
    else if (effect == "Glow-S")
8665
        return EFFECT_GLOW_S;
8666
    else if (effect == "Glow-M")
8667
        return EFFECT_GLOW_M;
8668
    else if (effect == "Glow-L")
8669
        return EFFECT_GLOW_L;
8670
    else if (effect == "Glow-X")
8671
        return EFFECT_GLOW_X;
8672
    else if (effect == "Soft Drop Shadow 1")
8673
        return EFFECT_SOFT_DROP_SHADOW_1;
8674
    else if (effect == "Soft Drop Shadow 2")
8675
        return EFFECT_SOFT_DROP_SHADOW_2;
8676
    else if (effect == "Soft Drop Shadow 3")
8677
        return EFFECT_SOFT_DROP_SHADOW_3;
8678
    else if (effect == "Soft Drop Shadow 4")
8679
        return EFFECT_SOFT_DROP_SHADOW_4;
8680
    else if (effect == "Soft Drop Shadow 5")
8681
        return EFFECT_SOFT_DROP_SHADOW_5;
8682
    else if (effect == "Soft Drop Shadow 6")
8683
        return EFFECT_SOFT_DROP_SHADOW_6;
8684
    else if (effect == "Soft Drop Shadow 7")
8685
        return EFFECT_SOFT_DROP_SHADOW_7;
8686
    else if (effect == "Soft Drop Shadow 8")
8687
        return EFFECT_SOFT_DROP_SHADOW_8;
8688
    else if (effect == "Medium Drop Shadow 1")
8689
        return EFFECT_MEDIUM_DROP_SHADOW_1;
8690
    else if (effect == "Medium Drop Shadow 2")
8691
        return EFFECT_MEDIUM_DROP_SHADOW_2;
8692
    else if (effect == "Medium Drop Shadow 3")
8693
        return EFFECT_MEDIUM_DROP_SHADOW_3;
8694
    else if (effect == "Medium Drop Shadow 4")
8695
        return EFFECT_MEDIUM_DROP_SHADOW_4;
8696
    else if (effect == "Medium Drop Shadow 5")
8697
        return EFFECT_MEDIUM_DROP_SHADOW_5;
8698
    else if (effect == "Medium Drop Shadow 6")
8699
        return EFFECT_MEDIUM_DROP_SHADOW_6;
8700
    else if (effect == "Medium Drop Shadow 7")
8701
        return EFFECT_MEDIUM_DROP_SHADOW_7;
8702
    else if (effect == "Medium Drop Shadow 8")
8703
        return EFFECT_MEDIUM_DROP_SHADOW_8;
8704
    else if (effect == "Hard Drop Shadow 1")
8705
        return EFFECT_HARD_DROP_SHADOW_1;
8706
    else if (effect == "Hard Drop Shadow 2")
8707
        return EFFECT_HARD_DROP_SHADOW_2;
8708
    else if (effect == "Hard Drop Shadow 3")
8709
        return EFFECT_HARD_DROP_SHADOW_3;
8710
    else if (effect == "Hard Drop Shadow 4")
8711
        return EFFECT_HARD_DROP_SHADOW_4;
8712
    else if (effect == "Hard Drop Shadow 5")
8713
        return EFFECT_HARD_DROP_SHADOW_5;
8714
    else if (effect == "Hard Drop Shadow 6")
8715
        return EFFECT_HARD_DROP_SHADOW_6;
8716
    else if (effect == "Hard Drop Shadow 7")
8717
        return EFFECT_HARD_DROP_SHADOW_7;
8718
    else if (effect == "Hard Drop Shadow 8")
8719
        return EFFECT_HARD_DROP_SHADOW_8;
8720
    else if (effect == "Soft Drop Shadow 1 with outline")
8721
        return EFFECT_SOFT_DROP_SHADOW_1_WITH_OUTLINE;
8722
    else if (effect == "Soft Drop Shadow 2 with outline")
8723
        return EFFECT_SOFT_DROP_SHADOW_2_WITH_OUTLINE;
8724
    else if (effect == "Soft Drop Shadow 3 with outline")
8725
        return EFFECT_SOFT_DROP_SHADOW_3_WITH_OUTLINE;
8726
    else if (effect == "Soft Drop Shadow 4 with outline")
8727
        return EFFECT_SOFT_DROP_SHADOW_4_WITH_OUTLINE;
8728
    else if (effect == "Soft Drop Shadow 5 with outline")
8729
        return EFFECT_SOFT_DROP_SHADOW_5_WITH_OUTLINE;
8730
    else if (effect == "Soft Drop Shadow 6 with outline")
8731
        return EFFECT_SOFT_DROP_SHADOW_6_WITH_OUTLINE;
8732
    else if (effect == "Soft Drop Shadow 7 with outline")
8733
        return EFFECT_SOFT_DROP_SHADOW_7_WITH_OUTLINE;
8734
    else if (effect == "Soft Drop Shadow 8 with outline")
8735
        return EFFECT_SOFT_DROP_SHADOW_8_WITH_OUTLINE;
8736
    else if (effect == "Medium Drop Shadow 1 with outline")
8737
        return EFFECT_MEDIUM_DROP_SHADOW_1_WITH_OUTLINE;
8738
    else if (effect == "Medium Drop Shadow 2 with outline")
8739
        return EFFECT_MEDIUM_DROP_SHADOW_2_WITH_OUTLINE;
8740
    else if (effect == "Medium Drop Shadow 3 with outline")
8741
        return EFFECT_MEDIUM_DROP_SHADOW_3_WITH_OUTLINE;
8742
    else if (effect == "Medium Drop Shadow 4 with outline")
8743
        return EFFECT_MEDIUM_DROP_SHADOW_4_WITH_OUTLINE;
8744
    else if (effect == "Medium Drop Shadow 5 with outline")
8745
        return EFFECT_MEDIUM_DROP_SHADOW_5_WITH_OUTLINE;
8746
    else if (effect == "Medium Drop Shadow 6 with outline")
8747
        return EFFECT_MEDIUM_DROP_SHADOW_6_WITH_OUTLINE;
8748
    else if (effect == "Medium Drop Shadow 7 with outline")
8749
        return EFFECT_MEDIUM_DROP_SHADOW_7_WITH_OUTLINE;
8750
    else if (effect == "Medium Drop Shadow 8 with outline")
8751
        return EFFECT_MEDIUM_DROP_SHADOW_8_WITH_OUTLINE;
8752
    else if (effect == "Hard Drop Shadow 1 with outline")
8753
        return EFFECT_HARD_DROP_SHADOW_1_WITH_OUTLINE;
8754
    else if (effect == "Hard Drop Shadow 2 with outline")
8755
        return EFFECT_HARD_DROP_SHADOW_2_WITH_OUTLINE;
8756
    else if (effect == "Hard Drop Shadow 3 with outline")
8757
        return EFFECT_HARD_DROP_SHADOW_3_WITH_OUTLINE;
8758
    else if (effect == "Hard Drop Shadow 4 with outline")
8759
        return EFFECT_HARD_DROP_SHADOW_4_WITH_OUTLINE;
8760
    else if (effect == "Hard Drop Shadow 5 with outline")
8761
        return EFFECT_HARD_DROP_SHADOW_5_WITH_OUTLINE;
8762
    else if (effect == "Hard Drop Shadow 6 with outline")
8763
        return EFFECT_HARD_DROP_SHADOW_6_WITH_OUTLINE;
8764
    else if (effect == "Hard Drop Shadow 7 with outline")
8765
        return EFFECT_HARD_DROP_SHADOW_7_WITH_OUTLINE;
8766
    else if (effect == "Hard Drop Shadow 8 with outline")
8767
        return EFFECT_HARD_DROP_SHADOW_8_WITH_OUTLINE;
8768
 
8769
    return EFFECT_NONE;
8770
}
15 andreas 8771
 
8772
bool TButton::isSystemButton()
8773
{
8774
    DECL_TRACER("TButton::isSystemButton()");
8775
 
195 andreas 8776
    if (type == MULTISTATE_BARGRAPH && lp == 0 && TSystem::isSystemButton(lv))
8777
        return true;
8778
    else if (type == BARGRAPH && lp == 0 && TSystem::isSystemButton(lv))
8779
        return true;
206 andreas 8780
    else if (type == LISTBOX && ap == 0 && ad > 0 && ti >= SYSTEM_PAGE_START)
198 andreas 8781
        return true;
195 andreas 8782
    else if (ap == 0 && TSystem::isSystemButton(ad))
8783
        return true;
8784
    else if (cp == 0 && TSystem::isSystemButton(ch))
8785
        return true;
15 andreas 8786
 
8787
    return false;
8788
}
21 andreas 8789
 
8790
THR_REFRESH_t *TButton::_addResource(TImageRefresh* refr, ulong handle, ulong parent, int bi)
8791
{
8792
    DECL_TRACER("TButton::_addResource(TImageRefresh* refr, ulong handle, ulong parent, int bi)");
8793
 
8794
    THR_REFRESH_t *p = mThrRefresh;
8795
    THR_REFRESH_t *r, *last = p;
8796
 
8797
    if (!refr || !handle || !parent || bi <= 0)
8798
    {
8799
        MSG_ERROR("Invalid parameter!");
8800
        return nullptr;
8801
    }
8802
 
8803
    r = new THR_REFRESH_t;
8804
    r->mImageRefresh = refr;
8805
    r->handle = handle;
8806
    r->parent = parent;
8807
    r->bi = bi;
8808
    r->next = nullptr;
8809
 
8810
    // If the chain is empty, add the new item;
8811
    if (!mThrRefresh)
8812
        mThrRefresh = r;
8813
    else    // Find the end and append the item
8814
    {
8815
        while (p)
8816
        {
8817
            last = p;
8818
 
8819
            if (p->handle == handle && p->parent == parent && p->bi == bi)
8820
            {
8821
                MSG_WARNING("Duplicate button found! Didn't add it again.");
8822
                delete r;
8823
                return p;
8824
            }
8825
 
8826
            p = p->next;
8827
        }
8828
 
8829
        last->next = r;
8830
    }
8831
 
8832
    MSG_DEBUG("New dynamic button added.");
8833
    return r;
8834
}
8835
 
8836
THR_REFRESH_t *TButton::_findResource(ulong handle, ulong parent, int bi)
8837
{
8838
    DECL_TRACER("TButton::_findResource(ulong handle, ulong parent, int bi)");
8839
 
8840
    THR_REFRESH_t *p = mThrRefresh;
8841
 
8842
    while (p)
8843
    {
8844
        if (p->handle == handle && p->parent == parent && p->bi == bi)
8845
            return p;
8846
 
8847
        p = p->next;
8848
    }
8849
 
8850
    return nullptr;
8851
}
94 andreas 8852
 
8853
void TButton::addToBitmapCache(BITMAP_CACHE& bc)
8854
{
8855
    DECL_TRACER("TButton::addToBitmapCache(BITMAP_CACHE& bc)");
8856
 
8857
    mutex_bmCache.lock();
8858
 
8859
    if (nBitmapCache.size() == 0)
8860
    {
8861
        nBitmapCache.push_back(bc);
8862
        mutex_bmCache.unlock();
8863
        return;
8864
    }
8865
 
8866
    vector<BITMAP_CACHE>::iterator iter;
8867
 
8868
    for (iter = nBitmapCache.begin(); iter != nBitmapCache.end(); ++iter)
8869
    {
8870
        if (iter->handle == bc.handle && iter->parent == bc.parent && iter->bi == bc.bi)
8871
        {
97 andreas 8872
            nBitmapCache.erase(iter);
8873
            nBitmapCache.push_back(bc);
94 andreas 8874
            mutex_bmCache.unlock();
8875
            return;
8876
        }
8877
    }
8878
 
8879
    nBitmapCache.push_back(bc);
8880
    mutex_bmCache.unlock();
8881
}
8882
 
8883
BITMAP_CACHE& TButton::getBCentryByHandle(ulong handle, ulong parent)
8884
{
8885
    DECL_TRACER("TButton::getBCentryByHandle(ulong handle, ulong parent)");
8886
 
8887
    mutex_bmCache.lock();
8888
 
8889
    if (nBitmapCache.size() == 0)
8890
    {
8891
        mutex_bmCache.unlock();
8892
        return mBCDummy;
8893
    }
8894
 
8895
    vector<BITMAP_CACHE>::iterator iter;
8896
 
8897
    for (iter = nBitmapCache.begin(); iter != nBitmapCache.end(); ++iter)
8898
    {
8899
        if (iter->handle == handle && iter->parent == parent)
8900
        {
8901
            mutex_bmCache.unlock();
8902
            return *iter;
8903
        }
8904
    }
8905
 
8906
    mutex_bmCache.unlock();
8907
    return mBCDummy;
8908
}
8909
 
8910
BITMAP_CACHE& TButton::getBCentryByBI(int bIdx)
8911
{
8912
    DECL_TRACER("TButton::getBCentryByBI(int bIdx)");
8913
 
8914
    mutex_bmCache.lock();
8915
 
8916
    if (nBitmapCache.size() == 0)
8917
    {
8918
        mutex_bmCache.unlock();
8919
        return mBCDummy;
8920
    }
8921
 
8922
    vector<BITMAP_CACHE>::iterator iter;
8923
 
8924
    for (iter = nBitmapCache.begin(); iter != nBitmapCache.end(); ++iter)
8925
    {
8926
        if (iter->bi == bIdx)
8927
        {
8928
            mutex_bmCache.unlock();
8929
            return *iter;
8930
        }
8931
    }
8932
 
8933
    mutex_bmCache.unlock();
8934
    return mBCDummy;
8935
}
8936
 
8937
void TButton::removeBCentry(std::vector<BITMAP_CACHE>::iterator *elem)
8938
{
8939
    DECL_TRACER("TButton::removeBCentry(std::vector<BITMAP_CACHE>::iterator *elem)");
8940
 
8941
    if (nBitmapCache.size() == 0 || !elem)
8942
        return;
8943
 
8944
    mutex_bmCache.lock();
8945
    vector<BITMAP_CACHE>::iterator iter;
8946
 
8947
    for (iter = nBitmapCache.begin(); iter != nBitmapCache.end(); ++iter)
8948
    {
8949
        if (iter == *elem)
8950
        {
8951
            nBitmapCache.erase(iter);
8952
            mutex_bmCache.unlock();
8953
            return;
8954
        }
8955
    }
8956
 
8957
    mutex_bmCache.unlock();
8958
}
8959
 
8960
void TButton::setReady(ulong handle)
8961
{
8962
    DECL_TRACER("TButton::setReady(ulong handle)");
8963
 
8964
    if (nBitmapCache.size() == 0)
8965
        return;
8966
 
8967
    mutex_bmCache.lock();
8968
    vector<BITMAP_CACHE>::iterator iter;
8969
 
8970
    for (iter = nBitmapCache.begin(); iter != nBitmapCache.end(); ++iter)
8971
    {
8972
        if (iter->handle == handle)
8973
        {
8974
            iter->ready = true;
8975
            mutex_bmCache.unlock();
8976
            return;
8977
        }
8978
    }
8979
 
8980
    mutex_bmCache.unlock();
8981
}
8982
 
97 andreas 8983
void TButton::setInvalid(ulong handle)
8984
{
8985
    DECL_TRACER("TButton::setInvalid(ulong handle)");
8986
 
8987
    if (nBitmapCache.size() == 0)
8988
        return;
8989
 
8990
    mutex_bmCache.lock();
8991
    vector<BITMAP_CACHE>::iterator iter;
8992
 
8993
    for (iter = nBitmapCache.begin(); iter != nBitmapCache.end(); ++iter)
8994
    {
8995
        if (iter->handle == handle)
8996
        {
8997
            nBitmapCache.erase(iter);
8998
            mutex_bmCache.unlock();
8999
            return;
9000
        }
9001
    }
9002
 
9003
    mutex_bmCache.unlock();
9004
}
9005
 
94 andreas 9006
void TButton::setBCBitmap(ulong handle, SkBitmap& bm)
9007
{
9008
    DECL_TRACER("TButton::setBCBitmap(ulong handle, SkBitmap& bm)");
9009
 
9010
    if (nBitmapCache.size() == 0)
9011
        return;
9012
 
9013
    mutex_bmCache.lock();
9014
    vector<BITMAP_CACHE>::iterator iter;
9015
 
9016
    for (iter = nBitmapCache.begin(); iter != nBitmapCache.end(); ++iter)
9017
    {
9018
        if (iter->handle == handle)
9019
        {
9020
            iter->bitmap = bm;
9021
            mutex_bmCache.unlock();
9022
            return;
9023
        }
9024
    }
9025
 
9026
    mutex_bmCache.unlock();
9027
}
9028
 
9029
void TButton::showBitmapCache()
9030
{
9031
    DECL_TRACER("TButton::showBitmapCache()");
9032
 
9033
    mutex_bmCache.lock();
9034
    vector<BITMAP_CACHE>::iterator iter;
9035
    bool found;
9036
 
9037
    while (nBitmapCache.size() > 0)
9038
    {
9039
        found = false;
9040
 
9041
        for (iter = nBitmapCache.begin(); iter != nBitmapCache.end(); ++iter)
9042
        {
9043
            if (iter->ready)
9044
            {
9045
                if (_displayButton)
176 andreas 9046
                {
289 andreas 9047
                    TBitmap image((unsigned char *)iter->bitmap.getPixels(), iter->bitmap.info().width(), iter->bitmap.info().height());
298 andreas 9048
                    _displayButton(iter->handle, iter->parent, image, iter->width, iter->height, iter->left, iter->top, isPassThrough());
176 andreas 9049
                    mChanged = false;
9050
                }
94 andreas 9051
 
9052
                nBitmapCache.erase(iter);
9053
                found = true;
9054
                break;
9055
            }
9056
        }
9057
 
9058
        if (!found)
9059
            break;
9060
    }
9061
 
9062
    mutex_bmCache.unlock();
9063
}
159 andreas 9064
 
9065
uint32_t TButton::pixelMix(uint32_t s, uint32_t d, uint32_t a, PMIX mix)
9066
{
9067
    DECL_TRACER("TButton::pixelMultiply(uint32_t s, uint32_t d)");
9068
 
9069
    uint32_t r = 0;
9070
 
9071
    switch(mix)
9072
    {
9073
        case PMIX_SRC:          r = s; break;                                                   // SRC
9074
        case PMIX_DST:          r = d; break;                                                   // DST
9075
        case PMIX_MULTIPLY:     r = s * (255 - (d * a)) + d * (255 - (s * a)) + s * d; break;   // Multiply
9076
        case PMIX_PLUS:         r = std::min(s + d, (uint32_t)255); break;                      // plus
9077
        case PMIX_XOR:          r = s * (255 - (d * a)) + d * (255 - (s * a)); break;           // XOr
9078
        case PMIX_DSTTOP:       r = d * (s * a) + s * (255 - (d * a)); break;                   // DstATop
9079
        case PMIX_SRCTOP:       r = s * (d * a) + d * (255 - (s * a)); break;                   // SrcATop
9080
        case PMIX_SRCOVER:      r = s + (255 - (s * a)) * d; break;                             // SrcOver
9081
        case PMIX_SCREEN:       r = s + d - s * d; break;                                       // Screen
9082
    }
9083
 
9084
    return r & 0x00ff;
9085
}
225 andreas 9086
 
298 andreas 9087
bool TButton::isPassThrough()
9088
{
9089
    DECL_TRACER("TButton::isPassThrough()");
9090
 
9091
    if (hs.empty())
9092
        return false;
9093
 
9094
    if (strCaseCompare(hs, "passThru") == 0)
9095
        return true;
9096
 
9097
    return false;
9098
}
9099
 
225 andreas 9100
bool TButton::setListSource(const string &source, const vector<string>& configs)
9101
{
9102
    DECL_TRACER("TButton::setListSource(const string &source, const vector<string>& configs)");
9103
 
9104
    TUrl url;
9105
 
227 andreas 9106
    listSourceUser.clear();
9107
    listSourcePass.clear();
9108
    listSourceCsv = false;
9109
    listSourceHasHeader = false;
9110
 
9111
    if (configs.size() > 0)
9112
    {
9113
        vector<string>::const_iterator iter;
9114
 
9115
        for (iter = configs.begin(); iter != configs.end(); ++iter)
9116
        {
9117
            size_t pos;
9118
 
9119
            if ((pos = iter->find("user=")) != string::npos)
9120
                listSourceUser = iter->substr(pos + 5);
9121
            else if ((pos = iter->find("pass=")) != string::npos)
9122
                listSourcePass = iter->substr(pos + 5);
9123
            else if (iter->find("csv=") != string::npos)
9124
            {
9125
                string str = *iter;
9126
                string low = toLower(str);
9127
 
9128
                if (low.find("true") != string::npos || low.find("1") != string::npos)
9129
                    listSourceCsv = true;
9130
            }
9131
            else if (iter->find("has_header=") != string::npos)
9132
            {
9133
                string str = *iter;
9134
                string low = toLower(str);
9135
 
9136
                if (low.find("true") != string::npos || low.find("1") != string::npos)
9137
                    listSourceHasHeader = true;
9138
            }
9139
        }
9140
    }
9141
 
225 andreas 9142
    if (!url.setUrl(source))    // Dynamic source?
9143
    {
9144
        size_t idx = 0;
9145
 
9146
        if (!gPrjResources)
9147
            return false;
9148
 
9149
        if ((idx = gPrjResources->getResourceIndex("image")) == TPrjResources::npos)
9150
        {
9151
            MSG_ERROR("There exists no image resource!");
9152
            return false;
9153
        }
9154
 
9155
        RESOURCE_T resource = gPrjResources->findResource(idx, source);
9156
 
9157
        if (resource.protocol.empty())
9158
        {
9159
            MSG_WARNING("Resource " << source << " not found!");
9160
            return false;
9161
        }
9162
 
9163
        listSource = resource.protocol + "://";
9164
 
227 andreas 9165
        if (!resource.user.empty() || !listSourceUser.empty())
225 andreas 9166
        {
227 andreas 9167
            listSource += ((listSourceUser.empty() == false) ? listSourceUser : resource.user);
225 andreas 9168
 
227 andreas 9169
            if ((!resource.password.empty() && !resource.encrypted) || !listSourcePass.empty())
9170
                listSource += ":" + ((listSourcePass.empty() == false) ? listSourcePass : resource.password);
225 andreas 9171
 
9172
            listSource += "@";
9173
        }
9174
 
9175
        listSource += resource.host;
9176
 
9177
        if (!resource.path.empty())
9178
            listSource += "/" + resource.path;
9179
 
9180
        if (!resource.file.empty())
9181
            listSource += "/" + resource.file;
9182
 
9183
        return true;
9184
    }
9185
 
9186
    listSource = source;
9187
    return true;
9188
}
227 andreas 9189
 
9190
bool TButton::setListSourceFilter(const string& filter)
9191
{
9192
    DECL_TRACER("TButton::setListSourceFilter(const string& filter)");
9193
 
9194
    if (filter.empty())
9195
        return false;
9196
 
230 andreas 9197
    listFilter = filter;
9198
    MSG_DEBUG("listSourceFilter: " << listFilter);
227 andreas 9199
    return true;
9200
}
233 andreas 9201
 
9202
void TButton::setListViewColumns(int cols)
9203
{
9204
    DECL_TRACER("TButton::setListViewColumns(int cols)");
9205
 
9206
    if (cols <= 0)
9207
        return;
9208
 
9209
    tc = cols;
9210
}
9211
 
9212
void TButton::setListViewLayout(int layout)
9213
{
9214
    DECL_TRACER("TButton::setListViewLayout(int layout)");
9215
 
9216
    if (layout < 1 || layout > 6)
9217
        return;
9218
 
9219
    listLayout = layout;
9220
}
9221
 
9222
void TButton::setListViewComponent(int comp)
9223
{
9224
    DECL_TRACER("TButton::setListViewComponent(int comp)");
9225
 
9226
    if (comp < 0 || comp > 7)
9227
        return;
9228
 
9229
    listComponent = comp;
9230
}
9231
 
9232
void TButton::setListViewCellheight(int height, bool percent)
9233
{
9234
    DECL_TRACER("TButton::setListViewCellheight(int height, bool percent)");
9235
 
9236
    int minHeight = ht / tr;    // Total height / number of rows
9237
    int maxHeight = (int)((double)ht / 100.0 * 95.0);
9238
 
9239
    if (!percent && (height < minHeight || height > maxHeight))
9240
        return;
9241
 
9242
    if (percent)
9243
    {
9244
        int h = (int)((double)ht / 100.0 * (double)height);
9245
 
9246
        if (h >= minHeight && h <= maxHeight)
9247
            tj = h;
9248
 
9249
        return;
9250
    }
9251
 
9252
    tj = height;
9253
}
9254
 
9255
void TButton::setListViewFilterHeight(int height, bool percent)
9256
{
9257
    DECL_TRACER("TButton::setListViewFilterHeight(int height, bool percent)");
9258
 
9259
    if (percent && (height < 5 || height > 25))
9260
        return;
9261
 
9262
    if (!percent && height < 24)
9263
        return;
9264
 
9265
    if (percent)
9266
    {
9267
        listViewColFilterHeight = (int)((double)ht / 100.0 * (double)height);
9268
        return;
9269
    }
9270
    else
9271
    {
9272
        int maxHeight = (int)((double)ht / 100.0 * 25.0);
9273
 
9274
        if (height < maxHeight)
9275
            listViewColFilterHeight = height;
9276
    }
9277
}
9278
 
9279
void TButton::setListViewP1(int p1)
9280
{
9281
    DECL_TRACER("TButton::setListViewP1(int p1)");
9282
 
9283
    if (p1 < 10 || p1 > 90)
9284
        return;
9285
 
9286
    listViewP1 = p1;
9287
}
9288
 
9289
void TButton::setListViewP2(int p2)
9290
{
9291
    DECL_TRACER("TButton::setListViewP2(int p2)");
9292
 
9293
    if (p2 < 10 || p2 > 90)
9294
        return;
9295
 
9296
    listViewP2 = p2;
9297
}
9298
 
9299
void TButton::listViewNavigate(const string &command, bool select)
9300
{
9301
    DECL_TRACER("TButton::listViewNavigate(const string &command, bool select)");
9302
 
9303
    string cmd = command;
9304
    string upCmd = toUpper(cmd);
9305
 
9306
    if (upCmd != "T" && upCmd != "B" && upCmd != "D" && upCmd != "U" && !isNumeric(upCmd, true))
9307
        return;
9308
 
9309
    // TODO: Add code to navigate a list
9310
    MSG_WARNING("ListView navigation is not supported!" << " [" << upCmd << ", " << (select ? "TRUE" : "FALSE") << "]");
9311
}
9312
 
9313
void TButton::listViewRefresh(int interval, bool force)
9314
{
9315
    DECL_TRACER("TButton::listViewRefresh(int interval, bool force)");
9316
 
238 andreas 9317
    Q_UNUSED(interval);
9318
    Q_UNUSED(force);
9319
 
233 andreas 9320
    // TODO: Add code to load list data and display / refresh them
9321
}
9322
 
9323
void TButton::listViewSortData(const vector<string> &columns, LIST_SORT order, const string &override)
9324
{
9325
    DECL_TRACER("TButton::listViewSortData(const vector<string> &columns, LIST_SORT order, const string &override)");
9326
 
238 andreas 9327
    Q_UNUSED(columns);
9328
    Q_UNUSED(order);
9329
    Q_UNUSED(override);
9330
 
233 andreas 9331
    // TODO: Insert code to sort the data in the list
9332
}
279 andreas 9333