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