Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

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