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