Subversion Repositories tpanel

Rev

Rev 479 | Details | Compare with Previous | Last modification | View Log | RSS feed

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