Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

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