Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

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