Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

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