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