Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

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