Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 andreas 1
/*
201 andreas 2
 * Copyright (C) 2020 to 2022 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
 */
18
 
19
#include <sys/types.h>
20
#include <sys/stat.h>
21
#include <unistd.h>
55 andreas 22
 
23
#include <include/core/SkFont.h>
24
#include <include/core/SkFontMetrics.h>
25
#include <include/core/SkTextBlob.h>
26
 
5 andreas 27
#include "tresources.h"
26 andreas 28
#include "tpagemanager.h"
2 andreas 29
#include "tpage.h"
66 andreas 30
#include "tdrawimage.h"
76 andreas 31
#include "texpat++.h"
147 andreas 32
#include "tobject.h"
211 andreas 33
#include "tconfig.h"
2 andreas 34
 
186 andreas 35
#if __cplusplus < 201402L
36
#   error "This module requires at least C++14 standard!"
37
#else
38
#   if __cplusplus < 201703L
39
#       include <experimental/filesystem>
40
namespace fs = std::experimental::filesystem;
41
#       warning "Support for C++14 and experimental filesystem will be removed in a future version!"
42
#   else
43
#       include <filesystem>
44
#       ifdef __ANDROID__
45
namespace fs = std::__fs::filesystem;
46
#       else
47
namespace fs = std::filesystem;
48
#       endif
49
#   endif
50
#endif
51
 
3 andreas 52
using std::string;
55 andreas 53
using std::vector;
151 andreas 54
using std::map;
55
using std::pair;
3 andreas 56
using namespace Button;
76 andreas 57
using namespace Expat;
3 andreas 58
 
26 andreas 59
extern TPageManager *gPageManager;
60
 
3 andreas 61
TPage::TPage(const string& name)
2 andreas 62
{
3 andreas 63
    DECL_TRACER("TPage::TPage(const string& name)");
14 andreas 64
    TError::clear();
38 andreas 65
 
66
    if (gPageManager)
67
    {
68
        if (!_setBackground)
69
            _setBackground = gPageManager->getCallbackBG();
70
 
71
        if (!_displayButton)
72
            _displayButton = gPageManager->getCallbackDB();
73
 
74
        if (!_callDropPage)
75
            _callDropPage = gPageManager->getCallDropPage();
76
 
77
        if (!_callDropSubPage)
78
            _callDropSubPage = gPageManager->getCallDropSubPage();
79
 
80
        if (!_playVideo)
81
            _playVideo = gPageManager->getCallbackPV();
82
    }
83
 
43 andreas 84
    if (name.compare("_progress") == 0)
85
    {
86
        addProgress();
87
        return ;
88
    }
89
 
3 andreas 90
    initialize(name);
91
}
2 andreas 92
 
3 andreas 93
TPage::~TPage()
94
{
5 andreas 95
    DECL_TRACER("TPage::~TPage()");
96
 
201 andreas 97
    MSG_DEBUG("Destroing page " << mPage.pageID << ": " << mPage.name);
98
    BUTTONS_T *p = getButtons();
3 andreas 99
    BUTTONS_T *next = nullptr;
2 andreas 100
 
3 andreas 101
    while (p)
102
    {
103
        next = p->next;
104
        delete p->button;
105
        delete p;
106
        p = next;
107
    }
2 andreas 108
 
201 andreas 109
    setButtons(nullptr);
3 andreas 110
 
111
    PAGECHAIN_T *pc = mSubPages;
112
    PAGECHAIN_T *pc_next = nullptr;
113
 
114
    // We're not allowd to delete the subpages here, because they're managed
115
    // by the TPageManager.
116
    while (pc)
117
    {
118
        pc_next = pc->next;
119
        delete pc;
120
        pc = pc_next;
121
    }
122
 
123
    mSubPages = nullptr;
124
}
125
 
126
void TPage::initialize(const string& nm)
127
{
128
    DECL_TRACER("TPage::initialize(const string& name)");
129
 
197 andreas 130
    string projectPath = ((gPageManager && gPageManager->isSetupActive()) ? TConfig::getSystemProjectPath() : TConfig::getProjectPath());
186 andreas 131
 
132
    if (!fs::exists(projectPath + "/prj.xma"))
197 andreas 133
    {
134
        MSG_ERROR("Directory " << projectPath << " doesn't exist!");
135
        return;
136
    }
186 andreas 137
 
138
    makeFileName(projectPath, nm);
139
 
194 andreas 140
    MSG_DEBUG("Using path: " << projectPath << " and file: " << nm);
141
 
3 andreas 142
    if (isValidFile())
143
        mPath = getFileName();
144
 
76 andreas 145
    TExpat xml(mPath);
146
    xml.setEncoding(ENC_CP1250);
3 andreas 147
 
76 andreas 148
    if (!xml.parse())
3 andreas 149
        return;
150
 
76 andreas 151
    int depth = 0;
152
    size_t index = 0;
153
    size_t oldIndex = 0;
154
    vector<ATTRIBUTE_t> attrs;
3 andreas 155
 
76 andreas 156
    if ((index = xml.getElementIndex("page", &depth)) == TExpat::npos)
3 andreas 157
    {
158
        MSG_ERROR("Element \"page\" with attribute \"type\" was not found!");
159
        TError::setError();
160
        return;
161
    }
162
 
76 andreas 163
    attrs = xml.getAttributes();
164
    string type = xml.getAttribute("type", attrs);
3 andreas 165
 
166
    if (type.compare("page") != 0)
167
    {
168
        MSG_ERROR("Invalid page type \"" << type << "\"!");
169
        TError::setError();
170
        return;
171
    }
172
 
76 andreas 173
    depth++;
174
    string ename, content;
3 andreas 175
 
76 andreas 176
    while ((index = xml.getNextElementFromIndex(index, &ename, &content, &attrs)) != TExpat::npos)
3 andreas 177
    {
76 andreas 178
        string e = ename;
3 andreas 179
 
180
        if (e.compare("pageID") == 0)
201 andreas 181
            mPage.pageID = xml.convertElementToInt(content);
3 andreas 182
        else if (e.compare("name") == 0)
201 andreas 183
            mPage.name = content;
3 andreas 184
        else if (e.compare("width") == 0)
201 andreas 185
            mPage.width = xml.convertElementToInt(content);
3 andreas 186
        else if (e.compare("height") == 0)
201 andreas 187
            mPage.height = xml.convertElementToInt(content);
3 andreas 188
        else if (e.compare("button") == 0)
189
        {
190
            TButton *button = new TButton();
204 andreas 191
            TPageInterface::registerListCallback<TPage>(button, this);
198 andreas 192
 
4 andreas 193
            button->setPalette(mPalette);
201 andreas 194
            button->setFonts(getFonts());
7 andreas 195
            button->registerCallback(_displayButton);
21 andreas 196
            button->regCallPlayVideo(_playVideo);
76 andreas 197
            index = button->initialize(&xml, index);
201 andreas 198
            button->setParentSize(mPage.width, mPage.height);
3 andreas 199
 
200
            if (TError::isError())
201
            {
23 andreas 202
                MSG_WARNING("Button \"" << button->getButtonName() << "\" deleted because of an error!");
3 andreas 203
                delete button;
204
                return;
205
            }
206
 
201 andreas 207
            button->setHandle(((mPage.pageID << 16) & 0xffff0000) | button->getButtonIndex());
14 andreas 208
            button->createButtons();
3 andreas 209
            addButton(button);
76 andreas 210
            index++;        // Jump over the end tag of the button.
3 andreas 211
        }
212
        else if (e.compare("sr") == 0)
213
        {
214
            SR_T bsr;
76 andreas 215
            bsr.number = xml.getAttributeInt("number", attrs);
216
            index++;
3 andreas 217
 
76 andreas 218
            while ((index = xml.getNextElementFromIndex(index, &ename, &content, &attrs)) != TExpat::npos)
3 andreas 219
            {
220
                if (ename.compare("bs") == 0)
76 andreas 221
                    bsr.bs = content;
3 andreas 222
                else if (ename.compare("cb") == 0)
76 andreas 223
                    bsr.cb = content;
3 andreas 224
                else if (ename.compare("cf") == 0)
76 andreas 225
                    bsr.cf = content;
3 andreas 226
                else if (ename.compare("ct") == 0)
76 andreas 227
                    bsr.ct = content;
3 andreas 228
                else if (ename.compare("ec") == 0)
76 andreas 229
                    bsr.ec = content;
3 andreas 230
                else if (ename.compare("bm") == 0)
76 andreas 231
                    bsr.bm = content;
65 andreas 232
                else if (ename.compare("mi") == 0)
76 andreas 233
                    bsr.mi = content;
3 andreas 234
                else if (ename.compare("fi") == 0)
76 andreas 235
                    bsr.fi = xml.convertElementToInt(content);
55 andreas 236
                else if (ename.compare("te") == 0)
76 andreas 237
                    bsr.te = content;
55 andreas 238
                else if (ename.compare("tx") == 0)
76 andreas 239
                    bsr.tx = xml.convertElementToInt(content);
55 andreas 240
                else if (ename.compare("ty") == 0)
76 andreas 241
                    bsr.ty = xml.convertElementToInt(content);
55 andreas 242
                else if (ename.compare("et") == 0)
76 andreas 243
                    bsr.et = xml.convertElementToInt(content);
55 andreas 244
                else if (ename.compare("ww") == 0)
76 andreas 245
                    bsr.ww = xml.convertElementToInt(content);
55 andreas 246
                else if (ename.compare("jt") == 0)
76 andreas 247
                    bsr.jt = (Button::TEXT_ORIENTATION)xml.convertElementToInt(content);
65 andreas 248
                else if (ename.compare("jb") == 0)
76 andreas 249
                    bsr.jb = (Button::TEXT_ORIENTATION)xml.convertElementToInt(content);
3 andreas 250
 
76 andreas 251
                oldIndex = index;
3 andreas 252
            }
253
 
254
            sr.push_back(bsr);
76 andreas 255
 
256
            if (index == TExpat::npos)
257
                index = oldIndex + 1;
3 andreas 258
        }
76 andreas 259
    }
3 andreas 260
 
204 andreas 261
    setSR(sr);
262
 
76 andreas 263
    if (TStreamError::checkFilter(HLOG_DEBUG))
264
    {
201 andreas 265
        MSG_DEBUG("PageID: " << mPage.pageID);
266
        MSG_DEBUG("Name  : " << mPage.name);
267
        MSG_DEBUG("Width : " << mPage.width);
268
        MSG_DEBUG("Height: " << mPage.height);
76 andreas 269
 
270
        vector<SR_T>::iterator iter;
271
        size_t pos = 1;
272
 
273
        for (iter = sr.begin(); iter != sr.end(); ++iter)
274
        {
275
            MSG_DEBUG("   " << pos << ": bs: " << iter->bs);
276
            MSG_DEBUG("   " << pos << ": cb: " << iter->cb);
277
            MSG_DEBUG("   " << pos << ": cf: " << iter->cf);
278
            MSG_DEBUG("   " << pos << ": ct: " << iter->ct);
279
            MSG_DEBUG("   " << pos << ": ec: " << iter->ec);
280
            MSG_DEBUG("   " << pos << ": bm: " << iter->bm);
281
            MSG_DEBUG("   " << pos << ": mi: " << iter->mi);
282
            MSG_DEBUG("   " << pos << ": fi: " << iter->fi);
283
            pos++;
284
        }
3 andreas 285
    }
286
 
203 andreas 287
    if (TPageInterface::getButtons())
76 andreas 288
        sortButtons();
3 andreas 289
}
204 andreas 290
/*
199 andreas 291
void TPage::registerListCallback(TButton *button)
292
{
293
    DECL_TRACER("TPage::registerListCallback(TButton *button)");
294
 
204 andreas 295
    TPageInterface::registerListCallback<TPage>(button, this);
199 andreas 296
}
204 andreas 297
*/
43 andreas 298
void TPage::addProgress()
299
{
300
    DECL_TRACER("TPage::addProgress()");
301
 
302
    if (!gPageManager)
303
    {
304
        MSG_WARNING("The page manager is still not initialized!");
305
        return;
306
    }
307
 
308
    Button::SR_T bsr;
201 andreas 309
    mPage.pageID = 300;
310
    mPage.name = "_progress";
217 andreas 311
    mPage.width = gPageManager->getSettings()->getWidth();
201 andreas 312
    mPage.height = gPageManager->getSettings()->getHeight();
313
    double unit = (double)mPage.height / 10.0;
43 andreas 314
    MSG_DEBUG("One unit is " << unit);
315
    // Background of page
316
    bsr.number = 1;
317
    bsr.cf = "#106010ff";
318
    bsr.ct = "#ffffffff";
319
    bsr.cb = "#009000ff";
320
    bsr.ec = "#ffffffff";
321
    bsr.fi = 21;
322
    sr.push_back(bsr);
323
    // Text field 1 to show status messages
324
    Button::EXTBUTTON_t bt;
195 andreas 325
    bt.type = GENERAL;
43 andreas 326
    bt.bi = 1;
327
    bt.na = "Line1";
328
    bt.tp = (int)(unit * 2.0);
201 andreas 329
    bt.lt = (int)(((double)mPage.width - ((double)mPage.width / 100.0 * 80.0)) / 2.0);
330
    bt.wt = (int)((double)mPage.width / 100.0 * 80.0);    // Line take 80% of available width
43 andreas 331
    bt.ht = (int)(unit / 100.0 * 80.0);
332
    MSG_DEBUG("Dimensions button 1: lt: " << bt.lt << ", tp: " << bt.tp << ", wt: " << bt.wt << ", ht: " << bt.ht);
333
    bt.zo = 1;
334
    bt.ap = 0;
335
    bt.ad = 160;
336
    bsr.cf = "#000000ff";
337
    bt.sr.push_back(bsr);
338
    bsr.number = 2;
339
    bt.sr.push_back(bsr);
340
    TButton *button = new TButton();
341
    button->setPalette(mPalette);
201 andreas 342
    button->setFonts(getFonts());
43 andreas 343
    button->registerCallback(_displayButton);
344
    button->regCallPlayVideo(_playVideo);
345
    button->createSoftButton(bt);
201 andreas 346
    button->setParentSize(mPage.width, mPage.height);
43 andreas 347
 
348
    if (TError::isError())
349
    {
350
        MSG_WARNING("Button \"" << button->getButtonName() << "\" deleted because of an error!");
351
        delete button;
352
        return;
353
    }
354
 
201 andreas 355
    button->setHandle(((mPage.pageID << 16) & 0xffff0000) | bt.bi);
43 andreas 356
    button->createButtons();
357
    addButton(button);
358
    // Text field 2 to show status messages
359
    bt.bi = 2;
360
    bt.na = "Line2";
361
    bt.tp = (int)(unit * 7.0);
362
    MSG_DEBUG("Dimensions button 2: lt: " << bt.lt << ", tp: " << bt.tp << ", wt: " << bt.wt << ", ht: " << bt.ht);
363
    bt.zo = 2;
364
    bt.ad = 161;
365
    button = new TButton();
366
    button->setPalette(mPalette);
201 andreas 367
    button->setFonts(getFonts());
43 andreas 368
    button->registerCallback(_displayButton);
369
    button->regCallPlayVideo(_playVideo);
370
    button->createSoftButton(bt);
201 andreas 371
    button->setParentSize(mPage.width, mPage.height);
43 andreas 372
 
373
    if (TError::isError())
374
    {
375
        MSG_WARNING("Button \"" << button->getButtonName() << "\" deleted because of an error!");
376
        delete button;
377
        return;
378
    }
379
 
201 andreas 380
    button->setHandle(((mPage.pageID << 16) & 0xffff0000) | bt.bi);
43 andreas 381
    button->createButtons();
382
    addButton(button);
383
    // Progress bar 1 (overall status)
195 andreas 384
    bt.type = BARGRAPH;
43 andreas 385
    bt.bi = 3;
386
    bt.na = "Bar1";
387
    bt.tp = (int)(unit * 3.0);
201 andreas 388
    bt.lt = (int)(((double)mPage.width - ((double)mPage.width / 100.0 * 80.0)) / 2.0);
389
    bt.wt = (int)((double)mPage.width / 100.0 * 80.0);    // Line take 80% of available width
43 andreas 390
    bt.ht = (int)unit;
391
    MSG_DEBUG("Dimensions bargraph 1: lt: " << bt.lt << ", tp: " << bt.tp << ", wt: " << bt.wt << ", ht: " << bt.ht);
392
    bt.zo = 3;
393
    bt.ap = 0;
394
    bt.ad = 162;
395
    bt.lp = 0;
396
    bt.lv = 162;
397
    bt.rl = 1;
398
    bt.rh = 100;
399
    bt.sc = "#ffffffff";
400
    bt.dr = "horizontal";
401
    bsr.number = 1;
402
    bsr.cf = "#0e0e0eff";
403
    bsr.ct = "#ffffffff";
404
    bsr.cb = "#009000ff";
405
    bt.sr.clear();
406
    bt.sr.push_back(bsr);
407
    bsr.number = 2;
408
    bsr.cf = "#ffffffff";
409
    bt.sr.push_back(bsr);
410
    button = new TButton();
411
    button->setPalette(mPalette);
201 andreas 412
    button->setFonts(getFonts());
43 andreas 413
    button->registerCallback(_displayButton);
414
    button->regCallPlayVideo(_playVideo);
415
    button->createSoftButton(bt);
201 andreas 416
    button->setParentSize(mPage.width, mPage.height);
43 andreas 417
 
418
    if (TError::isError())
419
    {
420
        MSG_WARNING("Button \"" << button->getButtonName() << "\" deleted because of an error!");
421
        delete button;
422
        return;
423
    }
424
 
203 andreas 425
    button->setHandle(((mPage.pageID << 16) & 0xffff0000) | bt.bi);
43 andreas 426
    button->createButtons();
427
    addButton(button);
428
    // Progress bar 2 (details)
429
    bt.bi = 4;
430
    bt.na = "Bar2";
431
    bt.tp = (int)(unit * 5.0);
432
    MSG_DEBUG("Dimensions bargraph 2: lt: " << bt.lt << ", tp: " << bt.tp << ", wt: " << bt.wt << ", ht: " << bt.ht);
433
    bt.zo = 4;
434
    bt.ad = 163;
435
    bt.lv = 163;
436
    button = new TButton();
437
    button->setPalette(mPalette);
201 andreas 438
    button->setFonts(getFonts());
43 andreas 439
    button->registerCallback(_displayButton);
440
    button->regCallPlayVideo(_playVideo);
441
    button->createSoftButton(bt);
201 andreas 442
    button->setParentSize(mPage.width, mPage.height);
43 andreas 443
 
444
    if (TError::isError())
445
    {
446
        MSG_WARNING("Button \"" << button->getButtonName() << "\" deleted because of an error!");
447
        delete button;
448
        return;
449
    }
450
 
201 andreas 451
    button->setHandle(((mPage.pageID << 16) & 0xffff0000) | bt.bi);
43 andreas 452
    button->createButtons();
453
    addButton(button);
454
}
455
 
5 andreas 456
void TPage::show()
457
{
458
    DECL_TRACER("TPage::show()");
459
 
460
    if (!_setBackground)
461
    {
31 andreas 462
        if (gPageManager && gPageManager->getCallbackBG())
463
            _setBackground = gPageManager->getCallbackBG();
464
        else
465
        {
466
            MSG_WARNING("No callback \"setBackground\" was set!");
467
            return;
468
        }
5 andreas 469
    }
470
 
217 andreas 471
    bool haveImage = false;
201 andreas 472
    ulong handle = (mPage.pageID << 16) & 0xffff0000;
473
    MSG_DEBUG("Processing page " << mPage.pageID);
66 andreas 474
    SkBitmap target;
201 andreas 475
    target.allocN32Pixels(mPage.width, mPage.height);
66 andreas 476
    target.eraseColor(TColor::getSkiaColor(sr[0].cf));
477
    // Draw the background, if any
478
    if (sr.size() > 0 && (!sr[0].bm.empty() || !sr[0].mi.empty()))
5 andreas 479
    {
66 andreas 480
        TDrawImage dImage;
201 andreas 481
        dImage.setWidth(mPage.width);
482
        dImage.setHeight(mPage.height);
5 andreas 483
 
66 andreas 484
        if (!sr[0].bm.empty())
5 andreas 485
        {
66 andreas 486
            MSG_DEBUG("Loading image " << sr[0].bm);
487
            sk_sp<SkData> rawImage = readImage(sr[0].bm);
5 andreas 488
            SkBitmap bm;
28 andreas 489
 
66 andreas 490
            if (rawImage)
491
            {
492
                MSG_DEBUG("Decoding image BM ...");
55 andreas 493
 
66 andreas 494
                if (!DecodeDataToBitmap(rawImage, &bm))
495
                {
496
                    MSG_WARNING("Problem while decoding image " << sr[0].bm);
497
                }
498
                else if (!bm.empty())
499
                {
500
                    dImage.setImageBm(bm);
501
                    SkImageInfo info = bm.info();
502
                    sr[0].bm_width = info.width();
503
                    sr[0].bm_height = info.height();
504
                    haveImage = true;
505
                }
506
                else
507
                {
508
                    MSG_WARNING("BM image " << sr[0].bm << " seems to be empty!");
509
                }
510
            }
511
        }
512
 
513
        if (!sr[0].mi.empty())
514
        {
515
            MSG_DEBUG("Loading image " << sr[0].mi);
516
            sk_sp<SkData> rawImage = readImage(sr[0].mi);
517
            SkBitmap mi;
518
 
519
            if (rawImage)
520
            {
521
                MSG_DEBUG("Decoding image MI ...");
522
 
523
                if (!DecodeDataToBitmap(rawImage, &mi))
524
                {
525
                    MSG_WARNING("Problem while decoding image " << sr[0].mi);
526
                }
527
                else if (!mi.empty())
528
                {
529
                    dImage.setImageMi(mi);
530
                    SkImageInfo info = mi.info();
531
                    sr[0].mi_width = info.width();
532
                    sr[0].mi_height = info.height();
533
                    haveImage = true;
534
                }
535
                else
536
                {
537
                    MSG_WARNING("MI image " << sr[0].mi << " seems to be empty!");
538
                }
539
            }
540
        }
541
 
542
        if (haveImage)
543
        {
544
            dImage.setSr(sr);
545
 
546
            if (!dImage.drawImage(&target))
547
                return;
548
 
55 andreas 549
            if (!sr[0].te.empty())
550
            {
201 andreas 551
                if (!drawText(mPage, &target))
55 andreas 552
                    return;
553
            }
66 andreas 554
 
555
            SkImageInfo info = target.info();
556
            size_t rowBytes = info.minRowBytes();
557
            size_t size = info.computeByteSize(rowBytes);
558
 
43 andreas 559
#ifdef _SCALE_SKIA_
26 andreas 560
            if (gPageManager && gPageManager->getScaleFactor() != 1.0)
561
            {
66 andreas 562
                SkPaint paint;
563
                int left, top;
564
 
565
                paint.setBlendMode(SkBlendMode::kSrc);
26 andreas 566
                paint.setFilterQuality(kHigh_SkFilterQuality);
28 andreas 567
                // Calculate new dimension
31 andreas 568
                double scaleFactor = gPageManager->getScaleFactor();
569
                MSG_DEBUG("Using scale factor " << scaleFactor);
570
                int lwidth = (int)((double)info.width() * scaleFactor);
571
                int lheight = (int)((double)info.height() * scaleFactor);
572
                int twidth = (int)((double)width * scaleFactor);
573
                int theight = (int)((double)height * scaleFactor);
66 andreas 574
                calcPosition(lwidth, lheight, &left, &top);
28 andreas 575
                // Create a canvas and draw new image
66 andreas 576
                sk_sp<SkImage> im = SkImage::MakeFromBitmap(target);
577
                target.allocN32Pixels(twidth, theight);
578
                target.eraseColor(TColor::getSkiaColor(sr[0].cf));
579
                SkCanvas can(target, SkSurfaceProps(1, kUnknown_SkPixelGeometry));
580
                SkRect rect = SkRect::MakeXYWH(left, top, lwidth, lheight);
581
                can.drawImageRect(im, rect, &paint);
582
                rowBytes = target.info().minRowBytes();
583
                size = target.info().computeByteSize(rowBytes);
584
                MSG_DEBUG("Scaled size of background image: " << left << ", " << top << ", " << lwidth << ", " << lheight);
26 andreas 585
            }
43 andreas 586
#endif
66 andreas 587
            if (sr[0].te.empty())
588
                _setBackground(handle, (unsigned char *)target.getPixels(), size, rowBytes, target.info().width(), target.info().height(), TColor::getColor(sr[0].cf));
5 andreas 589
        }
590
    }
66 andreas 591
 
592
    if (sr.size() > 0 && !sr[0].te.empty())
55 andreas 593
    {
66 andreas 594
        MSG_DEBUG("Drawing text on background image ...");
55 andreas 595
 
201 andreas 596
        if (!drawText(mPage, &target))
55 andreas 597
            return;
598
 
66 andreas 599
        SkImageInfo info = target.info();
55 andreas 600
        size_t rowBytes = info.minRowBytes();
601
        size_t size = info.computeByteSize(rowBytes);
66 andreas 602
        _setBackground(handle, (unsigned char *)target.getPixels(), size, rowBytes, target.info().width(), target.info().height(), TColor::getColor(sr[0].cf));
603
        haveImage = true;
55 andreas 604
    }
66 andreas 605
 
606
    if (sr.size() > 0 && !haveImage)
5 andreas 607
    {
26 andreas 608
        MSG_DEBUG("Calling \"setBackground\" with no image ...");
38 andreas 609
        _setBackground(handle, nullptr, 0, 0, 0, 0, TColor::getColor(sr[0].cf));
5 andreas 610
    }
611
 
26 andreas 612
    // Draw the buttons
201 andreas 613
    BUTTONS_T *button = TPageInterface::getButtons();
26 andreas 614
 
615
    while (button)
616
    {
617
        if (button->button)
618
        {
619
            MSG_DEBUG("Drawing button " << button->button->getButtonIndex() << ": " << button->button->getButtonName());
620
            button->button->registerCallback(_displayButton);
621
            button->button->regCallPlayVideo(_playVideo);
204 andreas 622
            TPageInterface::registerListCallback<TPage>(button->button, this);
201 andreas 623
            button->button->setFonts(getFonts());
26 andreas 624
            button->button->setPalette(mPalette);
625
            button->button->createButtons();
626
 
627
            if (sr.size() > 0)
628
                button->button->setGlobalOpacity(sr[0].oo);
629
 
630
            button->button->show();
631
        }
632
 
633
        button = button->next;
634
    }
635
 
66 andreas 636
    // Mark page as visible
14 andreas 637
    mVisible = true;
5 andreas 638
}
639
 
3 andreas 640
PAGECHAIN_T *TPage::addSubPage(TSubPage* pg)
641
{
14 andreas 642
    DECL_TRACER("TPage::addSubPage(TSubPage* pg)");
3 andreas 643
 
644
    if (!pg)
645
    {
646
        MSG_ERROR("Parameter is NULL!");
647
        TError::setError();
648
        return nullptr;
649
    }
650
 
651
    PAGECHAIN_T *chain = new PAGECHAIN_T;
652
    chain->subpage = pg;
14 andreas 653
    chain->next = nullptr;
154 andreas 654
    chain->prev = nullptr;
14 andreas 655
    PAGECHAIN_T *spg = mSubPages;
3 andreas 656
 
14 andreas 657
    if (spg)
3 andreas 658
    {
14 andreas 659
        // First make sure that the new page is not already in the chain.
660
        PAGECHAIN_T *p = spg;
3 andreas 661
 
14 andreas 662
        while (p)
13 andreas 663
        {
664
            if (p->subpage->getNumber() == pg->getNumber())
665
            {
14 andreas 666
                MSG_TRACE("Page " << pg->getNumber() << " is already in chain. Don't add it again.");
13 andreas 667
                delete chain;
668
                return p;
669
            }
670
 
3 andreas 671
            p = p->next;
13 andreas 672
        }
3 andreas 673
 
14 andreas 674
        // The subpage is not in chain. So we add it now.
675
        p = spg;
676
        // Find the last element in chain
40 andreas 677
        while (p && p->next)
14 andreas 678
            p = p->next;
679
 
3 andreas 680
        p->next = chain;
154 andreas 681
        chain->prev = p;
3 andreas 682
    }
683
    else
14 andreas 684
    {
685
        mZOrder = 0;
3 andreas 686
        mSubPages = chain;
14 andreas 687
    }
3 andreas 688
 
5 andreas 689
    mLastSubPage = 0;
3 andreas 690
    return chain;
691
}
692
 
693
bool TPage::removeSubPage(int ID)
694
{
695
    DECL_TRACER("TPage::removeSubPage(int ID)");
696
 
697
    PAGECHAIN_T *p = mSubPages;
698
    PAGECHAIN_T *prev = nullptr;
699
 
700
    while (p)
701
    {
702
        if (p->subpage->getNumber() == ID)
703
        {
704
            PAGECHAIN_T *next = p->next;
705
 
706
            if (prev)
154 andreas 707
            {
3 andreas 708
                prev->next = next;
154 andreas 709
                next->prev = prev;
710
            }
3 andreas 711
            else
154 andreas 712
            {
3 andreas 713
                mSubPages = next;
154 andreas 714
                mSubPages->prev = nullptr;
715
            }
3 andreas 716
 
717
            delete p;
5 andreas 718
            mLastSubPage = 0;
3 andreas 719
            return true;
720
        }
721
 
722
        prev = p;
723
        p = p->next;
724
    }
725
 
726
    return false;
727
}
728
 
729
bool TPage::removeSubPage(const std::string& nm)
730
{
731
    DECL_TRACER("TPage::removeSubPage(const std::string& nm)");
732
 
733
    PAGECHAIN_T *p = mSubPages;
734
    PAGECHAIN_T *prev = nullptr;
735
 
736
    while (p)
737
    {
738
        if (p->subpage->getName().compare(nm) == 0)
739
        {
740
            PAGECHAIN_T *next = p->next;
741
 
742
            if (prev)
154 andreas 743
            {
3 andreas 744
                prev->next = next;
154 andreas 745
                next->prev = prev;
746
            }
3 andreas 747
            else
154 andreas 748
            {
3 andreas 749
                mSubPages = next;
154 andreas 750
                mSubPages->prev = nullptr;
751
            }
3 andreas 752
 
753
            delete p;
5 andreas 754
            mLastSubPage = 0;
3 andreas 755
            return true;
756
        }
757
 
758
        prev = p;
759
        p = p->next;
760
    }
761
 
762
    return false;
763
}
764
 
4 andreas 765
TSubPage *TPage::getSubPage(int pageID)
766
{
767
    DECL_TRACER("TPage::getSubPage(int pageID)");
768
 
769
    PAGECHAIN_T *pg = mSubPages;
770
 
771
    while (pg)
772
    {
773
        if (pg->subpage->getNumber() == pageID)
774
        {
775
            mLastSubPage = pageID;
776
            return pg->subpage;
777
        }
778
 
779
        pg = pg->next;
780
    }
781
 
5 andreas 782
    mLastSubPage = 0;
4 andreas 783
    return nullptr;
784
}
785
 
786
TSubPage *TPage::getSubPage(const std::string& name)
787
{
788
    DECL_TRACER("TPage::getSubPage(const std::string& name)");
789
 
790
    PAGECHAIN_T *pg = mSubPages;
791
 
792
    while (pg)
793
    {
794
        if (pg->subpage->getName().compare(name) == 0)
795
        {
14 andreas 796
            mLastSubPage = pg->subpage->getNumber();
4 andreas 797
            return pg->subpage;
798
        }
799
 
800
        pg = pg->next;
801
    }
802
 
5 andreas 803
    mLastSubPage = 0;
4 andreas 804
    return nullptr;
805
}
806
 
807
TSubPage *TPage::getFirstSubPage()
808
{
809
    DECL_TRACER("TPage::getFirstSubPage()");
810
 
14 andreas 811
    PAGECHAIN_T *pg = mSubPages;
812
 
154 andreas 813
    if (pg && pg->subpage)
4 andreas 814
    {
154 andreas 815
        mLastSubPage = pg->subpage->getNumber();
816
        MSG_DEBUG("Subpage (Z: " << pg->subpage->getZOrder() << "): " << pg->subpage->getNumber() << ". " << pg->subpage->getName());
817
        return pg->subpage;
4 andreas 818
    }
819
 
14 andreas 820
    MSG_DEBUG("No subpages in chain.");
5 andreas 821
    mLastSubPage = 0;
4 andreas 822
    return nullptr;
823
}
824
 
825
TSubPage *TPage::getNextSubPage()
826
{
827
    DECL_TRACER("TPage::getNextSubPage()");
828
 
154 andreas 829
    if (mLastSubPage > 0 && mSubPages)
4 andreas 830
    {
831
        PAGECHAIN_T *p = mSubPages;
832
 
833
        while (p)
834
        {
835
            if (p->subpage->getNumber() == mLastSubPage)
836
            {
14 andreas 837
                if (p->next && p->next->subpage)
4 andreas 838
                {
14 andreas 839
                    TSubPage *page = p->next->subpage;
840
                    mLastSubPage = page->getNumber();
151 andreas 841
                    MSG_DEBUG("Subpage (Z: " << page->getZOrder() << "): " << page->getNumber() << ". " << page->getName());
14 andreas 842
                    return page;
4 andreas 843
                }
844
            }
845
 
846
            p = p->next;
847
        }
848
    }
849
 
14 andreas 850
    MSG_DEBUG("No more subpages in chain.");
5 andreas 851
    mLastSubPage = 0;
4 andreas 852
    return nullptr;
853
}
854
 
154 andreas 855
TSubPage *TPage::getPrevSubPage()
856
{
857
    DECL_TRACER("TPage::getPrevSubPage()");
858
 
859
    if (mLastSubPage < MAX_PAGE_ID || !mSubPages)
860
        return nullptr;
861
 
862
    PAGECHAIN_T *pg = mSubPages;
863
 
864
    while (pg)
865
    {
866
        if (pg->subpage->getNumber() == mLastSubPage)
867
        {
868
            if (!pg->prev)
869
            {
870
                mLastSubPage = 0;
871
                MSG_DEBUG("No more subpages in chain.");
872
                return nullptr;
873
            }
874
 
875
            mLastSubPage = pg->prev->subpage->getNumber();
876
            return pg->prev->subpage;
877
        }
878
 
879
        pg = pg->next;
880
    }
881
 
882
    MSG_DEBUG("No more subpages in chain.");
883
    mLastSubPage = 0;
884
    return nullptr;
885
}
886
 
887
TSubPage *TPage::getLastSubPage()
888
{
889
    DECL_TRACER("TPage::getLastSubPage()");
890
 
891
    if (!mSubPages)
892
    {
893
        mLastSubPage = 0;
894
        MSG_DEBUG("No subpages in cache!");
895
        return nullptr;
896
    }
897
 
898
    PAGECHAIN_T *pg = mSubPages;
899
 
900
    while (pg && pg->next)
901
        pg = pg->next;
902
 
903
    mLastSubPage = pg->subpage->getNumber();
904
    return pg->subpage;
905
}
906
 
12 andreas 907
void TPage::drop()
908
{
909
    DECL_TRACER("TPage::drop()");
910
 
911
    PAGECHAIN_T *pc = mSubPages;
14 andreas 912
 
147 andreas 913
    // remove all subpages, if there are any
12 andreas 914
    while (pc)
915
    {
147 andreas 916
        MSG_DEBUG("Dropping popup " << pc->subpage->getNumber() << ": " << pc->subpage->getName());
13 andreas 917
        pc->subpage->drop();
12 andreas 918
        pc = pc->next;
919
    }
14 andreas 920
 
147 andreas 921
    // remove all buttons, if there are any
201 andreas 922
    BUTTONS_T *bt = TPageInterface::getButtons();
147 andreas 923
 
924
    while (bt)
925
    {
926
        MSG_DEBUG("Dropping button " << TObject::handleToString(bt->button->getHandle()));
927
        bt->button->hide(true);
928
        bt = bt->next;
929
    }
930
 
14 andreas 931
    mZOrder = ZORDER_INVALID;
932
    mVisible = false;
12 andreas 933
}
43 andreas 934
#ifdef _SCALE_SKIA_
31 andreas 935
void TPage::calcPosition(int im_width, int im_height, int *left, int *top, bool scale)
43 andreas 936
#else
937
void TPage::calcPosition(int im_width, int im_height, int *left, int *top)
938
#endif
28 andreas 939
{
940
    DECL_TRACER("TPage::calcPosition(int im_width, int im_height, int *left, int *top)");
941
 
201 andreas 942
    int nw = mPage.width;
943
    int nh = mPage.height;
43 andreas 944
#ifdef _SCALE_SKIA_
31 andreas 945
    if (scale && gPageManager && gPageManager->getScaleFactor() != 1.0)
28 andreas 946
    {
947
        nw = (int)((double)width * gPageManager->getScaleFactor());
948
        nh = (int)((double)height * gPageManager->getScaleFactor());
949
    }
43 andreas 950
#endif
28 andreas 951
    switch (sr[0].jb)
952
    {
953
        case 0: // absolute position
954
            *left = sr[0].bx;
955
            *top = sr[0].by;
43 andreas 956
#ifdef _SCALE_SKIA_
31 andreas 957
            if (scale && gPageManager && gPageManager->getScaleFactor() != 1.0)
28 andreas 958
            {
959
                *left = (int)((double)sr[0].bx * gPageManager->getScaleFactor());
960
                *left = (int)((double)sr[0].by * gPageManager->getScaleFactor());
961
            }
43 andreas 962
#endif
28 andreas 963
        break;
964
 
965
        case 1: // top, left
966
            *left = 0;
967
            *top = 0;
968
        break;
969
 
970
        case 2: // center, top
971
            *left = (nw - im_width) / 2;
972
            *top = 0;
973
        break;
974
 
975
        case 3: // right, top
976
            *left = nw - im_width;
977
            *top = 0;
978
        break;
979
 
980
        case 4: // left, middle
981
            *left = 0;
982
            *top = (nh - im_height) / 2;
983
        break;
984
 
985
        case 6: // right, middle
986
            *left = nw - im_width;
987
            *top = (nh - im_height) / 2;
988
        break;
989
 
990
        case 7: // left, bottom
991
            *left = 0;
992
            *top = nh - im_height;
993
        break;
994
 
995
        case 8: // center, bottom
996
            *left = (nw - im_width) / 2;
997
            *top = nh - im_height;
998
        break;
999
 
1000
        case 9: // right, bottom
1001
            *left = nw - im_width;
1002
            *top = nh - im_height;
1003
        break;
31 andreas 1004
 
1005
        default:    // center middle
1006
            *left = (nw - im_width) / 2;
1007
            *top = (nh - im_height) / 2;
28 andreas 1008
    }
1009
 
1010
    if (*left < 0)
1011
        *left = 0;
1012
 
1013
    if (*top < 0)
1014
        *top = 0;
1015
}
1016
 
151 andreas 1017
void TPage::sortSubpages()
1018
{
1019
    DECL_TRACER("TPage::sortSubpage()");
1020
 
154 andreas 1021
    PAGECHAIN_T *pages = nullptr;
1022
    bool turned = false;
151 andreas 1023
 
154 andreas 1024
    // Here we do a simple bubble sort to bring the subpages in ascending Z-order
1025
    do
151 andreas 1026
    {
154 andreas 1027
        turned = false;
1028
        pages = mSubPages;
151 andreas 1029
 
154 andreas 1030
        while (pages && pages->next)
1031
        {
1032
            int actZ = 0;
1033
            int nextZ = 0;
151 andreas 1034
 
154 andreas 1035
            if (pages->next->subpage && pages->subpage)
1036
            {
1037
                nextZ = pages->next->subpage->getZOrder();
1038
                actZ = pages->subpage->getZOrder();
1039
            }
151 andreas 1040
 
154 andreas 1041
            if (actZ > nextZ)   // Turn?
1042
            {                   // Yes, then change only pointers to subpages
1043
                TSubPage *sp = pages->next->subpage;
151 andreas 1044
 
154 andreas 1045
                pages->next->subpage = pages->subpage;
1046
                pages->subpage = sp;
1047
                turned = true;
1048
            }
1049
 
1050
            pages = pages->next;
1051
        }
1052
    }
1053
    while (turned);
151 andreas 1054
}
1055
 
152 andreas 1056
int TPage::getNextZOrder()
1057
{
1058
    DECL_TRACER("TPage::getNextZOrder()");
1059
 
1060
    // Find highest z-order number
1061
    PAGECHAIN_T *pages = mSubPages;
154 andreas 1062
    int cnt = 0;
152 andreas 1063
 
1064
    while(pages)
1065
    {
154 andreas 1066
        if (pages->subpage->getZOrder() != ZORDER_INVALID)
1067
        {
1068
            cnt++;
1069
            pages->subpage->setZOrder(cnt);
1070
        }
152 andreas 1071
 
1072
        pages = pages->next;
1073
    }
1074
 
154 andreas 1075
    mZOrder = cnt + 1;
152 andreas 1076
    MSG_DEBUG("New Z-order: " << mZOrder);
1077
    return mZOrder;
1078
}
1079
 
151 andreas 1080
int TPage::decZOrder()
1081
{
1082
    DECL_TRACER("TPage::decZOrder()");
1083
 
1084
    // Find highest z-order number
1085
    PAGECHAIN_T *pages = mSubPages;
1086
    int z = 0;
1087
 
1088
    while(pages)
1089
    {
154 andreas 1090
        if (pages->subpage->getZOrder() != ZORDER_INVALID)
1091
        {
1092
            z++;
1093
            pages->subpage->setZOrder(z);
1094
        }
151 andreas 1095
 
1096
        pages = pages->next;
1097
    }
1098
 
1099
    mZOrder = z;
1100
    return mZOrder;
1101
}