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