Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

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