Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

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