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