Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

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