Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 andreas 1
/*
258 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
 */
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"
211 andreas 32
#include "tconfig.h"
303 andreas 33
#include "terror.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
}
199 andreas 290
 
43 andreas 291
void TPage::addProgress()
292
{
293
    DECL_TRACER("TPage::addProgress()");
294
 
295
    if (!gPageManager)
296
    {
297
        MSG_WARNING("The page manager is still not initialized!");
298
        return;
299
    }
300
 
301
    Button::SR_T bsr;
201 andreas 302
    mPage.pageID = 300;
303
    mPage.name = "_progress";
217 andreas 304
    mPage.width = gPageManager->getSettings()->getWidth();
201 andreas 305
    mPage.height = gPageManager->getSettings()->getHeight();
306
    double unit = (double)mPage.height / 10.0;
43 andreas 307
    MSG_DEBUG("One unit is " << unit);
308
    // Background of page
309
    bsr.number = 1;
310
    bsr.cf = "#106010ff";
311
    bsr.ct = "#ffffffff";
312
    bsr.cb = "#009000ff";
313
    bsr.ec = "#ffffffff";
314
    bsr.fi = 21;
315
    sr.push_back(bsr);
316
    // Text field 1 to show status messages
317
    Button::EXTBUTTON_t bt;
195 andreas 318
    bt.type = GENERAL;
43 andreas 319
    bt.bi = 1;
320
    bt.na = "Line1";
321
    bt.tp = (int)(unit * 2.0);
201 andreas 322
    bt.lt = (int)(((double)mPage.width - ((double)mPage.width / 100.0 * 80.0)) / 2.0);
323
    bt.wt = (int)((double)mPage.width / 100.0 * 80.0);    // Line take 80% of available width
43 andreas 324
    bt.ht = (int)(unit / 100.0 * 80.0);
325
    MSG_DEBUG("Dimensions button 1: lt: " << bt.lt << ", tp: " << bt.tp << ", wt: " << bt.wt << ", ht: " << bt.ht);
326
    bt.zo = 1;
327
    bt.ap = 0;
328
    bt.ad = 160;
329
    bsr.cf = "#000000ff";
330
    bt.sr.push_back(bsr);
331
    bsr.number = 2;
332
    bt.sr.push_back(bsr);
333
    TButton *button = new TButton();
334
    button->setPalette(mPalette);
201 andreas 335
    button->setFonts(getFonts());
43 andreas 336
    button->registerCallback(_displayButton);
337
    button->regCallPlayVideo(_playVideo);
338
    button->createSoftButton(bt);
201 andreas 339
    button->setParentSize(mPage.width, mPage.height);
43 andreas 340
 
341
    if (TError::isError())
342
    {
343
        MSG_WARNING("Button \"" << button->getButtonName() << "\" deleted because of an error!");
344
        delete button;
345
        return;
346
    }
347
 
201 andreas 348
    button->setHandle(((mPage.pageID << 16) & 0xffff0000) | bt.bi);
43 andreas 349
    button->createButtons();
350
    addButton(button);
351
    // Text field 2 to show status messages
352
    bt.bi = 2;
353
    bt.na = "Line2";
354
    bt.tp = (int)(unit * 7.0);
355
    MSG_DEBUG("Dimensions button 2: lt: " << bt.lt << ", tp: " << bt.tp << ", wt: " << bt.wt << ", ht: " << bt.ht);
356
    bt.zo = 2;
357
    bt.ad = 161;
358
    button = new TButton();
359
    button->setPalette(mPalette);
201 andreas 360
    button->setFonts(getFonts());
43 andreas 361
    button->registerCallback(_displayButton);
362
    button->regCallPlayVideo(_playVideo);
363
    button->createSoftButton(bt);
201 andreas 364
    button->setParentSize(mPage.width, mPage.height);
43 andreas 365
 
366
    if (TError::isError())
367
    {
368
        MSG_WARNING("Button \"" << button->getButtonName() << "\" deleted because of an error!");
369
        delete button;
370
        return;
371
    }
372
 
201 andreas 373
    button->setHandle(((mPage.pageID << 16) & 0xffff0000) | bt.bi);
43 andreas 374
    button->createButtons();
375
    addButton(button);
376
    // Progress bar 1 (overall status)
195 andreas 377
    bt.type = BARGRAPH;
43 andreas 378
    bt.bi = 3;
379
    bt.na = "Bar1";
380
    bt.tp = (int)(unit * 3.0);
201 andreas 381
    bt.lt = (int)(((double)mPage.width - ((double)mPage.width / 100.0 * 80.0)) / 2.0);
382
    bt.wt = (int)((double)mPage.width / 100.0 * 80.0);    // Line take 80% of available width
43 andreas 383
    bt.ht = (int)unit;
384
    MSG_DEBUG("Dimensions bargraph 1: lt: " << bt.lt << ", tp: " << bt.tp << ", wt: " << bt.wt << ", ht: " << bt.ht);
385
    bt.zo = 3;
386
    bt.ap = 0;
387
    bt.ad = 162;
388
    bt.lp = 0;
389
    bt.lv = 162;
390
    bt.rl = 1;
391
    bt.rh = 100;
392
    bt.sc = "#ffffffff";
393
    bt.dr = "horizontal";
394
    bsr.number = 1;
395
    bsr.cf = "#0e0e0eff";
396
    bsr.ct = "#ffffffff";
397
    bsr.cb = "#009000ff";
398
    bt.sr.clear();
399
    bt.sr.push_back(bsr);
400
    bsr.number = 2;
401
    bsr.cf = "#ffffffff";
402
    bt.sr.push_back(bsr);
403
    button = new TButton();
404
    button->setPalette(mPalette);
201 andreas 405
    button->setFonts(getFonts());
43 andreas 406
    button->registerCallback(_displayButton);
407
    button->regCallPlayVideo(_playVideo);
408
    button->createSoftButton(bt);
201 andreas 409
    button->setParentSize(mPage.width, mPage.height);
43 andreas 410
 
411
    if (TError::isError())
412
    {
413
        MSG_WARNING("Button \"" << button->getButtonName() << "\" deleted because of an error!");
414
        delete button;
415
        return;
416
    }
417
 
203 andreas 418
    button->setHandle(((mPage.pageID << 16) & 0xffff0000) | bt.bi);
43 andreas 419
    button->createButtons();
420
    addButton(button);
421
    // Progress bar 2 (details)
422
    bt.bi = 4;
423
    bt.na = "Bar2";
424
    bt.tp = (int)(unit * 5.0);
425
    MSG_DEBUG("Dimensions bargraph 2: lt: " << bt.lt << ", tp: " << bt.tp << ", wt: " << bt.wt << ", ht: " << bt.ht);
426
    bt.zo = 4;
427
    bt.ad = 163;
428
    bt.lv = 163;
429
    button = new TButton();
430
    button->setPalette(mPalette);
201 andreas 431
    button->setFonts(getFonts());
43 andreas 432
    button->registerCallback(_displayButton);
433
    button->regCallPlayVideo(_playVideo);
434
    button->createSoftButton(bt);
201 andreas 435
    button->setParentSize(mPage.width, mPage.height);
43 andreas 436
 
437
    if (TError::isError())
438
    {
439
        MSG_WARNING("Button \"" << button->getButtonName() << "\" deleted because of an error!");
440
        delete button;
441
        return;
442
    }
443
 
201 andreas 444
    button->setHandle(((mPage.pageID << 16) & 0xffff0000) | bt.bi);
43 andreas 445
    button->createButtons();
446
    addButton(button);
447
}
448
 
300 andreas 449
SkBitmap& TPage::getBgImage()
450
{
451
    DECL_TRACER("TPage::getBgImage()");
452
 
453
    if (!mBgImage.empty())
454
        return mBgImage;
455
 
456
    bool haveImage = false;
457
    MSG_DEBUG("Creating image for page " << mPage.pageID << ": " << mPage.name);
458
    SkBitmap target;
459
 
460
    if (!allocPixels(mPage.width, mPage.height, &target))
461
        return mBgImage;
462
 
463
    target.eraseColor(TColor::getSkiaColor(mPage.sr[0].cf));
464
    // Draw the background, if any
465
    if (mPage.sr.size() > 0 && (!mPage.sr[0].bm.empty() || !mPage.sr[0].mi.empty()))
466
    {
467
        TDrawImage dImage;
468
        dImage.setWidth(mPage.width);
469
        dImage.setHeight(mPage.height);
470
 
471
        if (!mPage.sr[0].bm.empty())
472
        {
473
            MSG_DEBUG("Loading image " << mPage.sr[0].bm);
474
            sk_sp<SkData> rawImage = readImage(mPage.sr[0].bm);
475
            SkBitmap bm;
476
 
477
            if (rawImage)
478
            {
479
                MSG_DEBUG("Decoding image BM ...");
480
 
481
                if (!DecodeDataToBitmap(rawImage, &bm))
482
                {
483
                    MSG_WARNING("Problem while decoding image " << mPage.sr[0].bm);
484
                }
485
                else if (!bm.empty())
486
                {
487
                    dImage.setImageBm(bm);
488
                    SkImageInfo info = bm.info();
489
                    mPage.sr[0].bm_width = info.width();
490
                    mPage.sr[0].bm_height = info.height();
491
                    haveImage = true;
492
                }
493
                else
494
                {
495
                    MSG_WARNING("BM image " << mPage.sr[0].bm << " seems to be empty!");
496
                }
497
            }
498
        }
499
 
500
        if (!mPage.sr[0].mi.empty())
501
        {
502
            MSG_DEBUG("Loading image " << mPage.sr[0].mi);
503
            sk_sp<SkData> rawImage = readImage(mPage.sr[0].mi);
504
            SkBitmap mi;
505
 
506
            if (rawImage)
507
            {
508
                MSG_DEBUG("Decoding image MI ...");
509
 
510
                if (!DecodeDataToBitmap(rawImage, &mi))
511
                {
512
                    MSG_WARNING("Problem while decoding image " << mPage.sr[0].mi);
513
                }
514
                else if (!mi.empty())
515
                {
516
                    dImage.setImageMi(mi);
517
                    SkImageInfo info = mi.info();
518
                    mPage.sr[0].mi_width = info.width();
519
                    mPage.sr[0].mi_height = info.height();
520
                    haveImage = true;
521
                }
522
                else
523
                {
524
                    MSG_WARNING("MI image " << mPage.sr[0].mi << " seems to be empty!");
525
                }
526
            }
527
        }
528
 
529
        if (haveImage)
530
        {
531
            dImage.setSr(mPage.sr);
532
 
533
            if (!dImage.drawImage(&target))
534
                return mBgImage;
535
 
536
            if (!mPage.sr[0].te.empty())
537
            {
538
                if (!drawText(mPage, &target))
539
                    return mBgImage;
540
            }
541
 
542
            if (mPage.sr[0].oo < 255 && mPage.sr[0].te.empty() && mPage.sr[0].bs.empty())
543
                setOpacity(&target, mPage.sr[0].oo);
544
 
545
#ifdef _SCALE_SKIA_
546
            size_t rowBytes = info.minRowBytes();
547
            size_t size = info.computeByteSize(rowBytes);
548
            SkImageInfo info = target.info();
549
 
550
            if (gPageManager && gPageManager->getScaleFactor() != 1.0)
551
            {
552
                SkPaint paint;
553
                int left, top;
554
 
555
                paint.setBlendMode(SkBlendMode::kSrc);
556
                paint.setFilterQuality(kHigh_SkFilterQuality);
557
                // Calculate new dimension
558
                double scaleFactor = gPageManager->getScaleFactor();
559
                MSG_DEBUG("Using scale factor " << scaleFactor);
560
                int lwidth = (int)((double)info.width() * scaleFactor);
561
                int lheight = (int)((double)info.height() * scaleFactor);
562
                int twidth = (int)((double)mPage.width * scaleFactor);
563
                int theight = (int)((double)mPage.height * scaleFactor);
564
                calcPosition(lwidth, lheight, &left, &top);
565
                // Create a canvas and draw new image
566
                sk_sp<SkImage> im = SkImage::MakeFromBitmap(target);
567
 
568
                if (!allocPixels(twidth, theight, &target))
569
                    return;
570
 
571
                target.eraseColor(TColor::getSkiaColor(mPage.sr[0].cf));
572
                SkCanvas can(target, SkSurfaceProps());
573
                SkRect rect = SkRect::MakeXYWH(left, top, lwidth, lheight);
574
                can.drawImageRect(im, rect, &paint);
575
                MSG_DEBUG("Scaled size of background image: " << left << ", " << top << ", " << lwidth << ", " << lheight);
576
            }
577
#endif
578
        }
579
    }
580
 
581
    if (mPage.sr.size() > 0 && !mPage.sr[0].te.empty())
582
    {
583
        MSG_DEBUG("Drawing a text only on background image ...");
584
 
585
        if (drawText(mPage, &target))
586
            haveImage = true;
587
    }
588
 
589
    // Check for a frame and draw it if there is one.
590
    if (!mPage.sr[0].bs.empty())
591
    {
592
        if (drawFrame(mPage, &target))
593
            haveImage = true;
594
    }
595
 
596
    if (haveImage)
597
    {
598
        if (mPage.sr[0].oo < 255)
599
            setOpacity(&target, mPage.sr[0].oo);
600
 
601
        mBgImage = target;
602
    }
603
 
604
    return mBgImage;
605
}
606
 
5 andreas 607
void TPage::show()
608
{
609
    DECL_TRACER("TPage::show()");
610
 
611
    if (!_setBackground)
612
    {
31 andreas 613
        if (gPageManager && gPageManager->getCallbackBG())
614
            _setBackground = gPageManager->getCallbackBG();
615
        else
616
        {
617
            MSG_WARNING("No callback \"setBackground\" was set!");
618
            return;
619
        }
5 andreas 620
    }
621
 
217 andreas 622
    bool haveImage = false;
201 andreas 623
    ulong handle = (mPage.pageID << 16) & 0xffff0000;
624
    MSG_DEBUG("Processing page " << mPage.pageID);
66 andreas 625
    SkBitmap target;
254 andreas 626
 
627
    if (!allocPixels(mPage.width, mPage.height, &target))
628
        return;
629
 
66 andreas 630
    target.eraseColor(TColor::getSkiaColor(sr[0].cf));
631
    // Draw the background, if any
632
    if (sr.size() > 0 && (!sr[0].bm.empty() || !sr[0].mi.empty()))
5 andreas 633
    {
66 andreas 634
        TDrawImage dImage;
201 andreas 635
        dImage.setWidth(mPage.width);
636
        dImage.setHeight(mPage.height);
5 andreas 637
 
66 andreas 638
        if (!sr[0].bm.empty())
5 andreas 639
        {
66 andreas 640
            MSG_DEBUG("Loading image " << sr[0].bm);
641
            sk_sp<SkData> rawImage = readImage(sr[0].bm);
5 andreas 642
            SkBitmap bm;
28 andreas 643
 
66 andreas 644
            if (rawImage)
645
            {
646
                MSG_DEBUG("Decoding image BM ...");
55 andreas 647
 
66 andreas 648
                if (!DecodeDataToBitmap(rawImage, &bm))
649
                {
650
                    MSG_WARNING("Problem while decoding image " << sr[0].bm);
651
                }
652
                else if (!bm.empty())
653
                {
654
                    dImage.setImageBm(bm);
655
                    SkImageInfo info = bm.info();
656
                    sr[0].bm_width = info.width();
657
                    sr[0].bm_height = info.height();
658
                    haveImage = true;
659
                }
660
                else
661
                {
662
                    MSG_WARNING("BM image " << sr[0].bm << " seems to be empty!");
663
                }
664
            }
665
        }
666
 
667
        if (!sr[0].mi.empty())
668
        {
669
            MSG_DEBUG("Loading image " << sr[0].mi);
670
            sk_sp<SkData> rawImage = readImage(sr[0].mi);
671
            SkBitmap mi;
672
 
673
            if (rawImage)
674
            {
675
                MSG_DEBUG("Decoding image MI ...");
676
 
677
                if (!DecodeDataToBitmap(rawImage, &mi))
678
                {
679
                    MSG_WARNING("Problem while decoding image " << sr[0].mi);
680
                }
681
                else if (!mi.empty())
682
                {
683
                    dImage.setImageMi(mi);
684
                    SkImageInfo info = mi.info();
685
                    sr[0].mi_width = info.width();
686
                    sr[0].mi_height = info.height();
687
                    haveImage = true;
688
                }
689
                else
690
                {
691
                    MSG_WARNING("MI image " << sr[0].mi << " seems to be empty!");
692
                }
693
            }
694
        }
695
 
696
        if (haveImage)
697
        {
698
            dImage.setSr(sr);
699
 
700
            if (!dImage.drawImage(&target))
701
                return;
702
 
55 andreas 703
            if (!sr[0].te.empty())
704
            {
201 andreas 705
                if (!drawText(mPage, &target))
55 andreas 706
                    return;
707
            }
66 andreas 708
 
43 andreas 709
#ifdef _SCALE_SKIA_
26 andreas 710
            if (gPageManager && gPageManager->getScaleFactor() != 1.0)
711
            {
66 andreas 712
                SkPaint paint;
713
                int left, top;
289 andreas 714
                SkImageInfo info = target.info();
66 andreas 715
 
716
                paint.setBlendMode(SkBlendMode::kSrc);
26 andreas 717
                paint.setFilterQuality(kHigh_SkFilterQuality);
28 andreas 718
                // Calculate new dimension
31 andreas 719
                double scaleFactor = gPageManager->getScaleFactor();
720
                MSG_DEBUG("Using scale factor " << scaleFactor);
721
                int lwidth = (int)((double)info.width() * scaleFactor);
722
                int lheight = (int)((double)info.height() * scaleFactor);
723
                int twidth = (int)((double)width * scaleFactor);
724
                int theight = (int)((double)height * scaleFactor);
66 andreas 725
                calcPosition(lwidth, lheight, &left, &top);
28 andreas 726
                // Create a canvas and draw new image
66 andreas 727
                sk_sp<SkImage> im = SkImage::MakeFromBitmap(target);
254 andreas 728
 
729
                if (!allocPixels(twidth, theight, &target))
730
                    return;
731
 
66 andreas 732
                target.eraseColor(TColor::getSkiaColor(sr[0].cf));
254 andreas 733
                SkCanvas can(target, SkSurfaceProps());
66 andreas 734
                SkRect rect = SkRect::MakeXYWH(left, top, lwidth, lheight);
735
                can.drawImageRect(im, rect, &paint);
736
                MSG_DEBUG("Scaled size of background image: " << left << ", " << top << ", " << lwidth << ", " << lheight);
26 andreas 737
            }
43 andreas 738
#endif
277 andreas 739
/*
289 andreas 740
            TBitmap image((unsigned char *)target.getPixels(), target.info().width(), target.info().height());
262 andreas 741
#ifdef _OPAQUE_SKIA_
258 andreas 742
            if (sr[0].te.empty() && sr[0].bs.empty())
289 andreas 743
                _setBackground(handle, image, target.info().width(), target.info().height(), TColor::getColor(sr[0].cf));
262 andreas 744
#else
745
            if (sr[0].te.empty() && sr[0].bs.empty())
289 andreas 746
                _setBackground(handle, image, target.info().width(), target.info().height(), TColor::getColor(sr[0].cf), sr[0].oo);
262 andreas 747
#endif
277 andreas 748
*/
5 andreas 749
        }
750
    }
66 andreas 751
 
752
    if (sr.size() > 0 && !sr[0].te.empty())
55 andreas 753
    {
66 andreas 754
        MSG_DEBUG("Drawing text on background image ...");
55 andreas 755
 
258 andreas 756
        if (drawText(mPage, &target))
757
            haveImage = true;
758
    }
55 andreas 759
 
258 andreas 760
    // Check for a frame and draw it if there is one.
761
    if (!sr[0].bs.empty())
762
    {
763
        if (drawFrame(mPage, &target))
764
            haveImage = true;
765
    }
766
 
767
    if (haveImage)
768
    {
66 andreas 769
        SkImageInfo info = target.info();
289 andreas 770
        TBitmap image((unsigned char *)target.getPixels(), info.width(), info.height());
262 andreas 771
#ifdef _OPAQUE_SKIA_
289 andreas 772
        _setBackground(handle, image, target.info().width(), target.info().height(), TColor::getColor(sr[0].cf));
262 andreas 773
#else
289 andreas 774
        _setBackground(handle, image, target.info().width(), target.info().height(), TColor::getColor(sr[0].cf), sr[0].oo);
262 andreas 775
#endif
55 andreas 776
    }
258 andreas 777
    else if (sr.size() > 0 && !haveImage)
5 andreas 778
    {
26 andreas 779
        MSG_DEBUG("Calling \"setBackground\" with no image ...");
262 andreas 780
#ifdef _OPAQUE_SKIA_
289 andreas 781
        _setBackground(handle, TBitmap(), 0, 0, TColor::getColor(sr[0].cf));
262 andreas 782
#else
289 andreas 783
        _setBackground(handle, TBitmap(), 0, 0, TColor::getColor(sr[0].cf), sr[0].oo);
262 andreas 784
#endif
5 andreas 785
    }
786
 
26 andreas 787
    // Draw the buttons
201 andreas 788
    BUTTONS_T *button = TPageInterface::getButtons();
26 andreas 789
 
790
    while (button)
791
    {
792
        if (button->button)
793
        {
794
            MSG_DEBUG("Drawing button " << button->button->getButtonIndex() << ": " << button->button->getButtonName());
795
            button->button->registerCallback(_displayButton);
796
            button->button->regCallPlayVideo(_playVideo);
204 andreas 797
            TPageInterface::registerListCallback<TPage>(button->button, this);
201 andreas 798
            button->button->setFonts(getFonts());
26 andreas 799
            button->button->setPalette(mPalette);
800
            button->button->createButtons();
801
 
802
            if (sr.size() > 0)
803
                button->button->setGlobalOpacity(sr[0].oo);
804
 
805
            button->button->show();
806
        }
807
 
808
        button = button->next;
809
    }
810
 
66 andreas 811
    // Mark page as visible
14 andreas 812
    mVisible = true;
271 andreas 813
 
814
    if (gPageManager && gPageManager->getPageFinished())
815
        gPageManager->getPageFinished()(handle);
5 andreas 816
}
817
 
3 andreas 818
PAGECHAIN_T *TPage::addSubPage(TSubPage* pg)
819
{
14 andreas 820
    DECL_TRACER("TPage::addSubPage(TSubPage* pg)");
3 andreas 821
 
822
    if (!pg)
823
    {
824
        MSG_ERROR("Parameter is NULL!");
825
        TError::setError();
826
        return nullptr;
827
    }
828
 
829
    PAGECHAIN_T *chain = new PAGECHAIN_T;
830
    chain->subpage = pg;
14 andreas 831
    chain->next = nullptr;
154 andreas 832
    chain->prev = nullptr;
14 andreas 833
    PAGECHAIN_T *spg = mSubPages;
3 andreas 834
 
14 andreas 835
    if (spg)
3 andreas 836
    {
14 andreas 837
        // First make sure that the new page is not already in the chain.
838
        PAGECHAIN_T *p = spg;
3 andreas 839
 
14 andreas 840
        while (p)
13 andreas 841
        {
842
            if (p->subpage->getNumber() == pg->getNumber())
843
            {
14 andreas 844
                MSG_TRACE("Page " << pg->getNumber() << " is already in chain. Don't add it again.");
13 andreas 845
                delete chain;
846
                return p;
847
            }
848
 
3 andreas 849
            p = p->next;
13 andreas 850
        }
3 andreas 851
 
14 andreas 852
        // The subpage is not in chain. So we add it now.
853
        p = spg;
854
        // Find the last element in chain
40 andreas 855
        while (p && p->next)
14 andreas 856
            p = p->next;
857
 
3 andreas 858
        p->next = chain;
154 andreas 859
        chain->prev = p;
3 andreas 860
    }
861
    else
14 andreas 862
    {
863
        mZOrder = 0;
3 andreas 864
        mSubPages = chain;
14 andreas 865
    }
3 andreas 866
 
5 andreas 867
    mLastSubPage = 0;
3 andreas 868
    return chain;
869
}
870
 
871
bool TPage::removeSubPage(int ID)
872
{
873
    DECL_TRACER("TPage::removeSubPage(int ID)");
874
 
875
    PAGECHAIN_T *p = mSubPages;
876
    PAGECHAIN_T *prev = nullptr;
877
 
878
    while (p)
879
    {
880
        if (p->subpage->getNumber() == ID)
881
        {
882
            PAGECHAIN_T *next = p->next;
883
 
884
            if (prev)
154 andreas 885
            {
3 andreas 886
                prev->next = next;
154 andreas 887
                next->prev = prev;
888
            }
3 andreas 889
            else
154 andreas 890
            {
3 andreas 891
                mSubPages = next;
154 andreas 892
                mSubPages->prev = nullptr;
893
            }
3 andreas 894
 
895
            delete p;
5 andreas 896
            mLastSubPage = 0;
3 andreas 897
            return true;
898
        }
899
 
900
        prev = p;
901
        p = p->next;
902
    }
903
 
904
    return false;
905
}
906
 
907
bool TPage::removeSubPage(const std::string& nm)
908
{
909
    DECL_TRACER("TPage::removeSubPage(const std::string& nm)");
910
 
911
    PAGECHAIN_T *p = mSubPages;
912
    PAGECHAIN_T *prev = nullptr;
913
 
914
    while (p)
915
    {
916
        if (p->subpage->getName().compare(nm) == 0)
917
        {
918
            PAGECHAIN_T *next = p->next;
919
 
920
            if (prev)
154 andreas 921
            {
3 andreas 922
                prev->next = next;
154 andreas 923
                next->prev = prev;
924
            }
3 andreas 925
            else
154 andreas 926
            {
3 andreas 927
                mSubPages = next;
154 andreas 928
                mSubPages->prev = nullptr;
929
            }
3 andreas 930
 
931
            delete p;
5 andreas 932
            mLastSubPage = 0;
3 andreas 933
            return true;
934
        }
935
 
936
        prev = p;
937
        p = p->next;
938
    }
939
 
940
    return false;
941
}
942
 
4 andreas 943
TSubPage *TPage::getSubPage(int pageID)
944
{
945
    DECL_TRACER("TPage::getSubPage(int pageID)");
946
 
947
    PAGECHAIN_T *pg = mSubPages;
948
 
949
    while (pg)
950
    {
951
        if (pg->subpage->getNumber() == pageID)
952
        {
953
            mLastSubPage = pageID;
954
            return pg->subpage;
955
        }
956
 
957
        pg = pg->next;
958
    }
959
 
5 andreas 960
    mLastSubPage = 0;
4 andreas 961
    return nullptr;
962
}
963
 
964
TSubPage *TPage::getSubPage(const std::string& name)
965
{
966
    DECL_TRACER("TPage::getSubPage(const std::string& name)");
967
 
968
    PAGECHAIN_T *pg = mSubPages;
969
 
970
    while (pg)
971
    {
972
        if (pg->subpage->getName().compare(name) == 0)
973
        {
14 andreas 974
            mLastSubPage = pg->subpage->getNumber();
4 andreas 975
            return pg->subpage;
976
        }
977
 
978
        pg = pg->next;
979
    }
980
 
5 andreas 981
    mLastSubPage = 0;
4 andreas 982
    return nullptr;
983
}
984
 
985
TSubPage *TPage::getFirstSubPage()
986
{
987
    DECL_TRACER("TPage::getFirstSubPage()");
988
 
14 andreas 989
    PAGECHAIN_T *pg = mSubPages;
990
 
154 andreas 991
    if (pg && pg->subpage)
4 andreas 992
    {
154 andreas 993
        mLastSubPage = pg->subpage->getNumber();
994
        MSG_DEBUG("Subpage (Z: " << pg->subpage->getZOrder() << "): " << pg->subpage->getNumber() << ". " << pg->subpage->getName());
995
        return pg->subpage;
4 andreas 996
    }
997
 
14 andreas 998
    MSG_DEBUG("No subpages in chain.");
5 andreas 999
    mLastSubPage = 0;
4 andreas 1000
    return nullptr;
1001
}
1002
 
1003
TSubPage *TPage::getNextSubPage()
1004
{
1005
    DECL_TRACER("TPage::getNextSubPage()");
1006
 
154 andreas 1007
    if (mLastSubPage > 0 && mSubPages)
4 andreas 1008
    {
1009
        PAGECHAIN_T *p = mSubPages;
1010
 
1011
        while (p)
1012
        {
289 andreas 1013
            if (p->subpage && p->subpage->getNumber() == mLastSubPage)
4 andreas 1014
            {
14 andreas 1015
                if (p->next && p->next->subpage)
4 andreas 1016
                {
14 andreas 1017
                    TSubPage *page = p->next->subpage;
1018
                    mLastSubPage = page->getNumber();
151 andreas 1019
                    MSG_DEBUG("Subpage (Z: " << page->getZOrder() << "): " << page->getNumber() << ". " << page->getName());
14 andreas 1020
                    return page;
4 andreas 1021
                }
1022
            }
1023
 
1024
            p = p->next;
1025
        }
1026
    }
1027
 
14 andreas 1028
    MSG_DEBUG("No more subpages in chain.");
5 andreas 1029
    mLastSubPage = 0;
4 andreas 1030
    return nullptr;
1031
}
1032
 
154 andreas 1033
TSubPage *TPage::getPrevSubPage()
1034
{
1035
    DECL_TRACER("TPage::getPrevSubPage()");
1036
 
1037
    if (mLastSubPage < MAX_PAGE_ID || !mSubPages)
1038
        return nullptr;
1039
 
1040
    PAGECHAIN_T *pg = mSubPages;
1041
 
1042
    while (pg)
1043
    {
1044
        if (pg->subpage->getNumber() == mLastSubPage)
1045
        {
1046
            if (!pg->prev)
1047
            {
1048
                mLastSubPage = 0;
1049
                MSG_DEBUG("No more subpages in chain.");
1050
                return nullptr;
1051
            }
1052
 
1053
            mLastSubPage = pg->prev->subpage->getNumber();
1054
            return pg->prev->subpage;
1055
        }
1056
 
1057
        pg = pg->next;
1058
    }
1059
 
1060
    MSG_DEBUG("No more subpages in chain.");
1061
    mLastSubPage = 0;
1062
    return nullptr;
1063
}
1064
 
1065
TSubPage *TPage::getLastSubPage()
1066
{
1067
    DECL_TRACER("TPage::getLastSubPage()");
1068
 
1069
    if (!mSubPages)
1070
    {
1071
        mLastSubPage = 0;
1072
        MSG_DEBUG("No subpages in cache!");
1073
        return nullptr;
1074
    }
1075
 
1076
    PAGECHAIN_T *pg = mSubPages;
1077
 
1078
    while (pg && pg->next)
1079
        pg = pg->next;
1080
 
1081
    mLastSubPage = pg->subpage->getNumber();
1082
    return pg->subpage;
1083
}
1084
 
12 andreas 1085
void TPage::drop()
1086
{
1087
    DECL_TRACER("TPage::drop()");
1088
 
1089
    PAGECHAIN_T *pc = mSubPages;
14 andreas 1090
 
147 andreas 1091
    // remove all subpages, if there are any
12 andreas 1092
    while (pc)
1093
    {
295 andreas 1094
        if (pc->subpage)
1095
        {
1096
            MSG_DEBUG("Dropping popup " << pc->subpage->getNumber() << ": " << pc->subpage->getName());
1097
            pc->subpage->drop();
1098
        }
1099
 
12 andreas 1100
        pc = pc->next;
1101
    }
14 andreas 1102
 
147 andreas 1103
    // remove all buttons, if there are any
201 andreas 1104
    BUTTONS_T *bt = TPageInterface::getButtons();
147 andreas 1105
 
1106
    while (bt)
1107
    {
271 andreas 1108
        MSG_DEBUG("Dropping button " << handleToString(bt->button->getHandle()));
1109
//        bt->button->hide(true);
1110
        bt->button->invalidate();
147 andreas 1111
        bt = bt->next;
1112
    }
1113
 
271 andreas 1114
    if (gPageManager && gPageManager->getCallDropPage())
1115
    {
1116
        ulong handle = (mPage.pageID << 16) & 0xffff0000;
1117
        gPageManager->getCallDropPage()(handle);
1118
    }
1119
 
14 andreas 1120
    mZOrder = ZORDER_INVALID;
1121
    mVisible = false;
12 andreas 1122
}
43 andreas 1123
#ifdef _SCALE_SKIA_
31 andreas 1124
void TPage::calcPosition(int im_width, int im_height, int *left, int *top, bool scale)
43 andreas 1125
#else
1126
void TPage::calcPosition(int im_width, int im_height, int *left, int *top)
1127
#endif
28 andreas 1128
{
1129
    DECL_TRACER("TPage::calcPosition(int im_width, int im_height, int *left, int *top)");
1130
 
201 andreas 1131
    int nw = mPage.width;
1132
    int nh = mPage.height;
43 andreas 1133
#ifdef _SCALE_SKIA_
31 andreas 1134
    if (scale && gPageManager && gPageManager->getScaleFactor() != 1.0)
28 andreas 1135
    {
1136
        nw = (int)((double)width * gPageManager->getScaleFactor());
1137
        nh = (int)((double)height * gPageManager->getScaleFactor());
1138
    }
43 andreas 1139
#endif
28 andreas 1140
    switch (sr[0].jb)
1141
    {
1142
        case 0: // absolute position
1143
            *left = sr[0].bx;
1144
            *top = sr[0].by;
43 andreas 1145
#ifdef _SCALE_SKIA_
31 andreas 1146
            if (scale && gPageManager && gPageManager->getScaleFactor() != 1.0)
28 andreas 1147
            {
1148
                *left = (int)((double)sr[0].bx * gPageManager->getScaleFactor());
1149
                *left = (int)((double)sr[0].by * gPageManager->getScaleFactor());
1150
            }
43 andreas 1151
#endif
28 andreas 1152
        break;
1153
 
1154
        case 1: // top, left
1155
            *left = 0;
1156
            *top = 0;
1157
        break;
1158
 
1159
        case 2: // center, top
1160
            *left = (nw - im_width) / 2;
1161
            *top = 0;
1162
        break;
1163
 
1164
        case 3: // right, top
1165
            *left = nw - im_width;
1166
            *top = 0;
1167
        break;
1168
 
1169
        case 4: // left, middle
1170
            *left = 0;
1171
            *top = (nh - im_height) / 2;
1172
        break;
1173
 
1174
        case 6: // right, middle
1175
            *left = nw - im_width;
1176
            *top = (nh - im_height) / 2;
1177
        break;
1178
 
1179
        case 7: // left, bottom
1180
            *left = 0;
1181
            *top = nh - im_height;
1182
        break;
1183
 
1184
        case 8: // center, bottom
1185
            *left = (nw - im_width) / 2;
1186
            *top = nh - im_height;
1187
        break;
1188
 
1189
        case 9: // right, bottom
1190
            *left = nw - im_width;
1191
            *top = nh - im_height;
1192
        break;
31 andreas 1193
 
1194
        default:    // center middle
1195
            *left = (nw - im_width) / 2;
1196
            *top = (nh - im_height) / 2;
28 andreas 1197
    }
1198
 
1199
    if (*left < 0)
1200
        *left = 0;
1201
 
1202
    if (*top < 0)
1203
        *top = 0;
1204
}
1205
 
151 andreas 1206
void TPage::sortSubpages()
1207
{
1208
    DECL_TRACER("TPage::sortSubpage()");
1209
 
154 andreas 1210
    PAGECHAIN_T *pages = nullptr;
1211
    bool turned = false;
151 andreas 1212
 
154 andreas 1213
    // Here we do a simple bubble sort to bring the subpages in ascending Z-order
1214
    do
151 andreas 1215
    {
154 andreas 1216
        turned = false;
1217
        pages = mSubPages;
151 andreas 1218
 
154 andreas 1219
        while (pages && pages->next)
1220
        {
1221
            int actZ = 0;
1222
            int nextZ = 0;
151 andreas 1223
 
154 andreas 1224
            if (pages->next->subpage && pages->subpage)
1225
            {
1226
                nextZ = pages->next->subpage->getZOrder();
1227
                actZ = pages->subpage->getZOrder();
1228
            }
151 andreas 1229
 
154 andreas 1230
            if (actZ > nextZ)   // Turn?
1231
            {                   // Yes, then change only pointers to subpages
1232
                TSubPage *sp = pages->next->subpage;
151 andreas 1233
 
154 andreas 1234
                pages->next->subpage = pages->subpage;
1235
                pages->subpage = sp;
1236
                turned = true;
1237
            }
1238
 
1239
            pages = pages->next;
1240
        }
1241
    }
1242
    while (turned);
151 andreas 1243
}
1244
 
152 andreas 1245
int TPage::getNextZOrder()
1246
{
1247
    DECL_TRACER("TPage::getNextZOrder()");
1248
 
1249
    // Find highest z-order number
1250
    PAGECHAIN_T *pages = mSubPages;
154 andreas 1251
    int cnt = 0;
152 andreas 1252
 
1253
    while(pages)
1254
    {
154 andreas 1255
        if (pages->subpage->getZOrder() != ZORDER_INVALID)
1256
        {
1257
            cnt++;
1258
            pages->subpage->setZOrder(cnt);
1259
        }
152 andreas 1260
 
1261
        pages = pages->next;
1262
    }
1263
 
154 andreas 1264
    mZOrder = cnt + 1;
152 andreas 1265
    MSG_DEBUG("New Z-order: " << mZOrder);
1266
    return mZOrder;
1267
}
1268
 
151 andreas 1269
int TPage::decZOrder()
1270
{
1271
    DECL_TRACER("TPage::decZOrder()");
1272
 
1273
    // Find highest z-order number
1274
    PAGECHAIN_T *pages = mSubPages;
1275
    int z = 0;
1276
 
1277
    while(pages)
1278
    {
154 andreas 1279
        if (pages->subpage->getZOrder() != ZORDER_INVALID)
1280
        {
1281
            z++;
1282
            pages->subpage->setZOrder(z);
1283
        }
151 andreas 1284
 
1285
        pages = pages->next;
1286
    }
1287
 
1288
    mZOrder = z;
1289
    return mZOrder;
1290
}