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