Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 andreas 1
/*
21 andreas 2
 * Copyright (C) 2020, 2021 by Andreas Theofilu <andreas@theosys.at>
2 andreas 3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
 
19
#include <sys/types.h>
20
#include <sys/stat.h>
21
#include <unistd.h>
55 andreas 22
 
23
#include <include/core/SkFont.h>
24
#include <include/core/SkFontMetrics.h>
25
#include <include/core/SkTextBlob.h>
26
 
5 andreas 27
#include "tresources.h"
26 andreas 28
#include "tpagemanager.h"
2 andreas 29
#include "tpage.h"
66 andreas 30
#include "tdrawimage.h"
76 andreas 31
#include "texpat++.h"
147 andreas 32
#include "tobject.h"
2 andreas 33
 
3 andreas 34
using std::string;
55 andreas 35
using std::vector;
151 andreas 36
using std::map;
37
using std::pair;
3 andreas 38
using namespace Button;
76 andreas 39
using namespace Expat;
3 andreas 40
 
26 andreas 41
extern TPageManager *gPageManager;
42
 
3 andreas 43
TPage::TPage(const string& name)
2 andreas 44
{
3 andreas 45
    DECL_TRACER("TPage::TPage(const string& name)");
14 andreas 46
    TError::clear();
38 andreas 47
 
48
    if (gPageManager)
49
    {
50
        if (!_setBackground)
51
            _setBackground = gPageManager->getCallbackBG();
52
 
53
        if (!_displayButton)
54
            _displayButton = gPageManager->getCallbackDB();
55
 
56
        if (!_callDropPage)
57
            _callDropPage = gPageManager->getCallDropPage();
58
 
59
        if (!_callDropSubPage)
60
            _callDropSubPage = gPageManager->getCallDropSubPage();
61
 
62
        if (!_playVideo)
63
            _playVideo = gPageManager->getCallbackPV();
64
    }
65
 
43 andreas 66
    if (name.compare("_progress") == 0)
67
    {
68
        addProgress();
69
        return ;
70
    }
71
 
3 andreas 72
    initialize(name);
73
}
2 andreas 74
 
3 andreas 75
TPage::~TPage()
76
{
5 andreas 77
    DECL_TRACER("TPage::~TPage()");
78
 
79
    MSG_DEBUG("Destroing page " << pageID << ": " << name);
3 andreas 80
    BUTTONS_T *p = mButtons;
81
    BUTTONS_T *next = nullptr;
2 andreas 82
 
3 andreas 83
    while (p)
84
    {
85
        next = p->next;
86
        delete p->button;
87
        delete p;
88
        p = next;
89
    }
2 andreas 90
 
3 andreas 91
    mButtons = nullptr;
92
 
93
    PAGECHAIN_T *pc = mSubPages;
94
    PAGECHAIN_T *pc_next = nullptr;
95
 
96
    // We're not allowd to delete the subpages here, because they're managed
97
    // by the TPageManager.
98
    while (pc)
99
    {
100
        pc_next = pc->next;
101
        delete pc;
102
        pc = pc_next;
103
    }
104
 
105
    mSubPages = nullptr;
106
}
107
 
108
void TPage::initialize(const string& nm)
109
{
110
    DECL_TRACER("TPage::initialize(const string& name)");
111
    makeFileName(TConfig::getProjectPath(), nm);
112
 
113
    if (isValidFile())
114
        mPath = getFileName();
115
 
76 andreas 116
    TExpat xml(mPath);
117
    xml.setEncoding(ENC_CP1250);
3 andreas 118
 
76 andreas 119
    if (!xml.parse())
3 andreas 120
        return;
121
 
76 andreas 122
    int depth = 0;
123
    size_t index = 0;
124
    size_t oldIndex = 0;
125
    vector<ATTRIBUTE_t> attrs;
3 andreas 126
 
76 andreas 127
    if ((index = xml.getElementIndex("page", &depth)) == TExpat::npos)
3 andreas 128
    {
129
        MSG_ERROR("Element \"page\" with attribute \"type\" was not found!");
130
        TError::setError();
131
        return;
132
    }
133
 
76 andreas 134
    attrs = xml.getAttributes();
135
    string type = xml.getAttribute("type", attrs);
3 andreas 136
 
137
    if (type.compare("page") != 0)
138
    {
139
        MSG_ERROR("Invalid page type \"" << type << "\"!");
140
        TError::setError();
141
        return;
142
    }
143
 
76 andreas 144
    depth++;
145
    string ename, content;
3 andreas 146
 
76 andreas 147
    while ((index = xml.getNextElementFromIndex(index, &ename, &content, &attrs)) != TExpat::npos)
3 andreas 148
    {
76 andreas 149
        string e = ename;
3 andreas 150
 
151
        if (e.compare("pageID") == 0)
76 andreas 152
            pageID = xml.convertElementToInt(content);
3 andreas 153
        else if (e.compare("name") == 0)
76 andreas 154
            name = content;
3 andreas 155
        else if (e.compare("width") == 0)
76 andreas 156
            width = xml.convertElementToInt(content);
3 andreas 157
        else if (e.compare("height") == 0)
76 andreas 158
            height = xml.convertElementToInt(content);
3 andreas 159
        else if (e.compare("button") == 0)
160
        {
161
            TButton *button = new TButton();
4 andreas 162
            button->setPalette(mPalette);
7 andreas 163
            button->setFonts(mFonts);
164
            button->registerCallback(_displayButton);
21 andreas 165
            button->regCallPlayVideo(_playVideo);
76 andreas 166
            index = button->initialize(&xml, index);
40 andreas 167
            button->setParentSize(width, height);
3 andreas 168
 
169
            if (TError::isError())
170
            {
23 andreas 171
                MSG_WARNING("Button \"" << button->getButtonName() << "\" deleted because of an error!");
3 andreas 172
                delete button;
173
                return;
174
            }
175
 
5 andreas 176
            button->setHandle(((pageID << 16) & 0xffff0000) | button->getButtonIndex());
14 andreas 177
            button->createButtons();
3 andreas 178
            addButton(button);
76 andreas 179
            index++;        // Jump over the end tag of the button.
3 andreas 180
        }
181
        else if (e.compare("sr") == 0)
182
        {
183
            SR_T bsr;
76 andreas 184
            bsr.number = xml.getAttributeInt("number", attrs);
185
            index++;
3 andreas 186
 
76 andreas 187
            while ((index = xml.getNextElementFromIndex(index, &ename, &content, &attrs)) != TExpat::npos)
3 andreas 188
            {
189
                if (ename.compare("bs") == 0)
76 andreas 190
                    bsr.bs = content;
3 andreas 191
                else if (ename.compare("cb") == 0)
76 andreas 192
                    bsr.cb = content;
3 andreas 193
                else if (ename.compare("cf") == 0)
76 andreas 194
                    bsr.cf = content;
3 andreas 195
                else if (ename.compare("ct") == 0)
76 andreas 196
                    bsr.ct = content;
3 andreas 197
                else if (ename.compare("ec") == 0)
76 andreas 198
                    bsr.ec = content;
3 andreas 199
                else if (ename.compare("bm") == 0)
76 andreas 200
                    bsr.bm = content;
65 andreas 201
                else if (ename.compare("mi") == 0)
76 andreas 202
                    bsr.mi = content;
3 andreas 203
                else if (ename.compare("fi") == 0)
76 andreas 204
                    bsr.fi = xml.convertElementToInt(content);
55 andreas 205
                else if (ename.compare("te") == 0)
76 andreas 206
                    bsr.te = content;
55 andreas 207
                else if (ename.compare("tx") == 0)
76 andreas 208
                    bsr.tx = xml.convertElementToInt(content);
55 andreas 209
                else if (ename.compare("ty") == 0)
76 andreas 210
                    bsr.ty = xml.convertElementToInt(content);
55 andreas 211
                else if (ename.compare("et") == 0)
76 andreas 212
                    bsr.et = xml.convertElementToInt(content);
55 andreas 213
                else if (ename.compare("ww") == 0)
76 andreas 214
                    bsr.ww = xml.convertElementToInt(content);
55 andreas 215
                else if (ename.compare("jt") == 0)
76 andreas 216
                    bsr.jt = (Button::TEXT_ORIENTATION)xml.convertElementToInt(content);
65 andreas 217
                else if (ename.compare("jb") == 0)
76 andreas 218
                    bsr.jb = (Button::TEXT_ORIENTATION)xml.convertElementToInt(content);
3 andreas 219
 
76 andreas 220
                oldIndex = index;
3 andreas 221
            }
222
 
223
            sr.push_back(bsr);
76 andreas 224
 
225
            if (index == TExpat::npos)
226
                index = oldIndex + 1;
3 andreas 227
        }
76 andreas 228
    }
3 andreas 229
 
76 andreas 230
    if (TStreamError::checkFilter(HLOG_DEBUG))
231
    {
232
        MSG_DEBUG("PageID: " << pageID);
233
        MSG_DEBUG("Name  : " << name);
234
        MSG_DEBUG("Width : " << width);
235
        MSG_DEBUG("Height: " << height);
236
 
237
        vector<SR_T>::iterator iter;
238
        size_t pos = 1;
239
 
240
        for (iter = sr.begin(); iter != sr.end(); ++iter)
241
        {
242
            MSG_DEBUG("   " << pos << ": bs: " << iter->bs);
243
            MSG_DEBUG("   " << pos << ": cb: " << iter->cb);
244
            MSG_DEBUG("   " << pos << ": cf: " << iter->cf);
245
            MSG_DEBUG("   " << pos << ": ct: " << iter->ct);
246
            MSG_DEBUG("   " << pos << ": ec: " << iter->ec);
247
            MSG_DEBUG("   " << pos << ": bm: " << iter->bm);
248
            MSG_DEBUG("   " << pos << ": mi: " << iter->mi);
249
            MSG_DEBUG("   " << pos << ": fi: " << iter->fi);
250
            pos++;
251
        }
3 andreas 252
    }
253
 
76 andreas 254
    if (mButtons)
255
        sortButtons();
3 andreas 256
}
257
 
43 andreas 258
void TPage::addProgress()
259
{
260
    DECL_TRACER("TPage::addProgress()");
261
 
262
    if (!gPageManager)
263
    {
264
        MSG_WARNING("The page manager is still not initialized!");
265
        return;
266
    }
267
 
268
    Button::SR_T bsr;
269
    pageID = 300;
270
    name = "_progress";
271
    width = gPageManager->getSettings()->getWith();
272
    height = gPageManager->getSettings()->getHeight();
273
    double unit = (double)height / 10.0;
274
    MSG_DEBUG("One unit is " << unit);
275
    // Background of page
276
    bsr.number = 1;
277
    bsr.cf = "#106010ff";
278
    bsr.ct = "#ffffffff";
279
    bsr.cb = "#009000ff";
280
    bsr.ec = "#ffffffff";
281
    bsr.fi = 21;
282
    sr.push_back(bsr);
283
    // Text field 1 to show status messages
284
    Button::EXTBUTTON_t bt;
285
    bt.type = Button::GENERAL;
286
    bt.bi = 1;
287
    bt.na = "Line1";
288
    bt.tp = (int)(unit * 2.0);
289
    bt.lt = (int)(((double)width - ((double)width / 100.0 * 80.0)) / 2.0);
290
    bt.wt = (int)((double)width / 100.0 * 80.0);    // Line take 80% of available width
291
    bt.ht = (int)(unit / 100.0 * 80.0);
292
    MSG_DEBUG("Dimensions button 1: lt: " << bt.lt << ", tp: " << bt.tp << ", wt: " << bt.wt << ", ht: " << bt.ht);
293
    bt.zo = 1;
294
    bt.ap = 0;
295
    bt.ad = 160;
296
    bsr.cf = "#000000ff";
297
    bt.sr.push_back(bsr);
298
    bsr.number = 2;
299
    bt.sr.push_back(bsr);
300
    TButton *button = new TButton();
301
    button->setPalette(mPalette);
302
    button->setFonts(mFonts);
303
    button->registerCallback(_displayButton);
304
    button->regCallPlayVideo(_playVideo);
305
    button->createSoftButton(bt);
306
    button->setParentSize(width, height);
307
 
308
    if (TError::isError())
309
    {
310
        MSG_WARNING("Button \"" << button->getButtonName() << "\" deleted because of an error!");
311
        delete button;
312
        return;
313
    }
314
 
315
    button->setHandle(((pageID << 16) & 0xffff0000) | bt.bi);
316
    button->createButtons();
317
    addButton(button);
318
    // Text field 2 to show status messages
319
    bt.bi = 2;
320
    bt.na = "Line2";
321
    bt.tp = (int)(unit * 7.0);
322
    MSG_DEBUG("Dimensions button 2: lt: " << bt.lt << ", tp: " << bt.tp << ", wt: " << bt.wt << ", ht: " << bt.ht);
323
    bt.zo = 2;
324
    bt.ad = 161;
325
    button = new TButton();
326
    button->setPalette(mPalette);
327
    button->setFonts(mFonts);
328
    button->registerCallback(_displayButton);
329
    button->regCallPlayVideo(_playVideo);
330
    button->createSoftButton(bt);
331
    button->setParentSize(width, height);
332
 
333
    if (TError::isError())
334
    {
335
        MSG_WARNING("Button \"" << button->getButtonName() << "\" deleted because of an error!");
336
        delete button;
337
        return;
338
    }
339
 
340
    button->setHandle(((pageID << 16) & 0xffff0000) | bt.bi);
341
    button->createButtons();
342
    addButton(button);
343
    // Progress bar 1 (overall status)
344
    bt.type = Button::BARGRAPH;
345
    bt.bi = 3;
346
    bt.na = "Bar1";
347
    bt.tp = (int)(unit * 3.0);
348
    bt.lt = (int)(((double)width - ((double)width / 100.0 * 80.0)) / 2.0);
349
    bt.wt = (int)((double)width / 100.0 * 80.0);    // Line take 80% of available width
350
    bt.ht = (int)unit;
351
    MSG_DEBUG("Dimensions bargraph 1: lt: " << bt.lt << ", tp: " << bt.tp << ", wt: " << bt.wt << ", ht: " << bt.ht);
352
    bt.zo = 3;
353
    bt.ap = 0;
354
    bt.ad = 162;
355
    bt.lp = 0;
356
    bt.lv = 162;
357
    bt.rl = 1;
358
    bt.rh = 100;
359
    bt.sc = "#ffffffff";
360
    bt.dr = "horizontal";
361
    bsr.number = 1;
362
    bsr.cf = "#0e0e0eff";
363
    bsr.ct = "#ffffffff";
364
    bsr.cb = "#009000ff";
365
    bt.sr.clear();
366
    bt.sr.push_back(bsr);
367
    bsr.number = 2;
368
    bsr.cf = "#ffffffff";
369
    bt.sr.push_back(bsr);
370
    button = new TButton();
371
    button->setPalette(mPalette);
372
    button->setFonts(mFonts);
373
    button->registerCallback(_displayButton);
374
    button->regCallPlayVideo(_playVideo);
375
    button->createSoftButton(bt);
376
    button->setParentSize(width, height);
377
 
378
    if (TError::isError())
379
    {
380
        MSG_WARNING("Button \"" << button->getButtonName() << "\" deleted because of an error!");
381
        delete button;
382
        return;
383
    }
384
 
385
    button->setHandle(((pageID << 16) & 0xffff0000) | bt.bi);
386
    button->createButtons();
387
    addButton(button);
388
    // Progress bar 2 (details)
389
    bt.bi = 4;
390
    bt.na = "Bar2";
391
    bt.tp = (int)(unit * 5.0);
392
    MSG_DEBUG("Dimensions bargraph 2: lt: " << bt.lt << ", tp: " << bt.tp << ", wt: " << bt.wt << ", ht: " << bt.ht);
393
    bt.zo = 4;
394
    bt.ad = 163;
395
    bt.lv = 163;
396
    button = new TButton();
397
    button->setPalette(mPalette);
398
    button->setFonts(mFonts);
399
    button->registerCallback(_displayButton);
400
    button->regCallPlayVideo(_playVideo);
401
    button->createSoftButton(bt);
402
    button->setParentSize(width, height);
403
 
404
    if (TError::isError())
405
    {
406
        MSG_WARNING("Button \"" << button->getButtonName() << "\" deleted because of an error!");
407
        delete button;
408
        return;
409
    }
410
 
411
    button->setHandle(((pageID << 16) & 0xffff0000) | bt.bi);
412
    button->createButtons();
413
    addButton(button);
414
}
415
 
5 andreas 416
void TPage::show()
417
{
418
    DECL_TRACER("TPage::show()");
419
 
420
    if (!_setBackground)
421
    {
31 andreas 422
        if (gPageManager && gPageManager->getCallbackBG())
423
            _setBackground = gPageManager->getCallbackBG();
424
        else
425
        {
426
            MSG_WARNING("No callback \"setBackground\" was set!");
427
            return;
428
        }
5 andreas 429
    }
430
 
66 andreas 431
    bool haveImage;
5 andreas 432
    ulong handle = (pageID << 16) & 0xffff0000;
433
    MSG_DEBUG("Processing page " << pageID);
66 andreas 434
    SkBitmap target;
435
    target.allocN32Pixels(width, height);
436
    target.eraseColor(TColor::getSkiaColor(sr[0].cf));
437
    // Draw the background, if any
438
    if (sr.size() > 0 && (!sr[0].bm.empty() || !sr[0].mi.empty()))
5 andreas 439
    {
66 andreas 440
        TDrawImage dImage;
441
        dImage.setWidth(width);
442
        dImage.setHeight(height);
5 andreas 443
 
66 andreas 444
        if (!sr[0].bm.empty())
5 andreas 445
        {
66 andreas 446
            MSG_DEBUG("Loading image " << sr[0].bm);
447
            sk_sp<SkData> rawImage = readImage(sr[0].bm);
5 andreas 448
            SkBitmap bm;
28 andreas 449
 
66 andreas 450
            if (rawImage)
451
            {
452
                MSG_DEBUG("Decoding image BM ...");
55 andreas 453
 
66 andreas 454
                if (!DecodeDataToBitmap(rawImage, &bm))
455
                {
456
                    MSG_WARNING("Problem while decoding image " << sr[0].bm);
457
                }
458
                else if (!bm.empty())
459
                {
460
                    dImage.setImageBm(bm);
461
                    SkImageInfo info = bm.info();
462
                    sr[0].bm_width = info.width();
463
                    sr[0].bm_height = info.height();
464
                    haveImage = true;
465
                }
466
                else
467
                {
468
                    MSG_WARNING("BM image " << sr[0].bm << " seems to be empty!");
469
                }
470
            }
471
        }
472
 
473
        if (!sr[0].mi.empty())
474
        {
475
            MSG_DEBUG("Loading image " << sr[0].mi);
476
            sk_sp<SkData> rawImage = readImage(sr[0].mi);
477
            SkBitmap mi;
478
 
479
            if (rawImage)
480
            {
481
                MSG_DEBUG("Decoding image MI ...");
482
 
483
                if (!DecodeDataToBitmap(rawImage, &mi))
484
                {
485
                    MSG_WARNING("Problem while decoding image " << sr[0].mi);
486
                }
487
                else if (!mi.empty())
488
                {
489
                    dImage.setImageMi(mi);
490
                    SkImageInfo info = mi.info();
491
                    sr[0].mi_width = info.width();
492
                    sr[0].mi_height = info.height();
493
                    haveImage = true;
494
                }
495
                else
496
                {
497
                    MSG_WARNING("MI image " << sr[0].mi << " seems to be empty!");
498
                }
499
            }
500
        }
501
 
502
        if (haveImage)
503
        {
504
            dImage.setSr(sr);
505
 
506
            if (!dImage.drawImage(&target))
507
                return;
508
 
55 andreas 509
            if (!sr[0].te.empty())
510
            {
66 andreas 511
                if (!drawText(&target))
55 andreas 512
                    return;
513
            }
66 andreas 514
 
515
            SkImageInfo info = target.info();
516
            size_t rowBytes = info.minRowBytes();
517
            size_t size = info.computeByteSize(rowBytes);
518
 
43 andreas 519
#ifdef _SCALE_SKIA_
26 andreas 520
            if (gPageManager && gPageManager->getScaleFactor() != 1.0)
521
            {
66 andreas 522
                SkPaint paint;
523
                int left, top;
524
 
525
                paint.setBlendMode(SkBlendMode::kSrc);
26 andreas 526
                paint.setFilterQuality(kHigh_SkFilterQuality);
28 andreas 527
                // Calculate new dimension
31 andreas 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)width * scaleFactor);
533
                int theight = (int)((double)height * scaleFactor);
66 andreas 534
                calcPosition(lwidth, lheight, &left, &top);
28 andreas 535
                // Create a canvas and draw new image
66 andreas 536
                sk_sp<SkImage> im = SkImage::MakeFromBitmap(target);
537
                target.allocN32Pixels(twidth, theight);
538
                target.eraseColor(TColor::getSkiaColor(sr[0].cf));
539
                SkCanvas can(target, SkSurfaceProps(1, kUnknown_SkPixelGeometry));
540
                SkRect rect = SkRect::MakeXYWH(left, top, lwidth, lheight);
541
                can.drawImageRect(im, rect, &paint);
542
                rowBytes = target.info().minRowBytes();
543
                size = target.info().computeByteSize(rowBytes);
544
                MSG_DEBUG("Scaled size of background image: " << left << ", " << top << ", " << lwidth << ", " << lheight);
26 andreas 545
            }
43 andreas 546
#endif
66 andreas 547
            if (sr[0].te.empty())
548
                _setBackground(handle, (unsigned char *)target.getPixels(), size, rowBytes, target.info().width(), target.info().height(), TColor::getColor(sr[0].cf));
5 andreas 549
        }
550
    }
66 andreas 551
 
552
    if (sr.size() > 0 && !sr[0].te.empty())
55 andreas 553
    {
66 andreas 554
        MSG_DEBUG("Drawing text on background image ...");
55 andreas 555
 
66 andreas 556
        if (!drawText(&target))
55 andreas 557
            return;
558
 
66 andreas 559
        SkImageInfo info = target.info();
55 andreas 560
        size_t rowBytes = info.minRowBytes();
561
        size_t size = info.computeByteSize(rowBytes);
66 andreas 562
        rowBytes = target.info().minRowBytes();
563
        size = target.info().computeByteSize(rowBytes);
564
        _setBackground(handle, (unsigned char *)target.getPixels(), size, rowBytes, target.info().width(), target.info().height(), TColor::getColor(sr[0].cf));
565
        haveImage = true;
55 andreas 566
    }
66 andreas 567
 
568
    if (sr.size() > 0 && !haveImage)
5 andreas 569
    {
26 andreas 570
        MSG_DEBUG("Calling \"setBackground\" with no image ...");
38 andreas 571
        _setBackground(handle, nullptr, 0, 0, 0, 0, TColor::getColor(sr[0].cf));
5 andreas 572
    }
573
 
26 andreas 574
    // Draw the buttons
575
    BUTTONS_T *button = mButtons;
576
 
577
    while (button)
578
    {
579
        if (button->button)
580
        {
581
            MSG_DEBUG("Drawing button " << button->button->getButtonIndex() << ": " << button->button->getButtonName());
582
            button->button->registerCallback(_displayButton);
583
            button->button->regCallPlayVideo(_playVideo);
584
            button->button->setFonts(mFonts);
585
            button->button->setPalette(mPalette);
586
            button->button->createButtons();
587
 
588
            if (sr.size() > 0)
589
                button->button->setGlobalOpacity(sr[0].oo);
590
 
591
            button->button->show();
592
        }
593
 
594
        button = button->next;
595
    }
596
 
66 andreas 597
    // Mark page as visible
14 andreas 598
    mVisible = true;
5 andreas 599
}
600
 
55 andreas 601
int TPage::numberLines(const string& str)
602
{
603
    DECL_TRACER("TPage::numberLines(const string& str)");
604
 
605
    int lines = 1;
606
 
607
    for (size_t i = 0; i < str.length(); i++)
608
    {
609
        if (str.at(i) == '\n')
610
            lines++;
611
    }
612
 
613
    return lines;
614
}
615
 
118 andreas 616
int TPage::calcLineHeight(const string& text, SkFont& font)
55 andreas 617
{
118 andreas 618
    DECL_TRACER("TButton::calcLineHeight(const string& text, SkFont& font)");
55 andreas 619
 
620
    sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromString(text.c_str(), font);
621
    SkRect rect = blob.get()->bounds();
622
    return rect.height();
623
}
624
 
625
Button::POSITION_t TPage::calcImagePosition(int width, int height, Button::CENTER_CODE cc, int line)
626
{
627
    DECL_TRACER("TButton::calcImagePosition(int with, int height, CENTER_CODE code, int number)");
628
 
629
    SR_T act_sr;
630
    POSITION_t position;
631
    int ix, iy;
632
 
633
    if (sr.size() == 0)
634
        return position;
635
 
636
    act_sr = sr.at(0);
637
    //    int border_size = getBorderSize(act_sr.bs);
638
    int border_size = 0;
639
    int code, border = border_size;
640
    string dbgCC;
641
    int rwt = 0, rht = 0;
642
 
643
    switch (cc)
644
    {
645
        case SC_ICON:
646
            code = act_sr.ji;
647
            ix = act_sr.ix;
648
            iy = act_sr.iy;
649
            border = border_size = 0;
650
            dbgCC = "ICON";
651
            rwt = width;
652
            rht = height;
653
            break;
654
 
655
        case SC_BITMAP:
656
            code = act_sr.jb;
657
            ix = act_sr.bx;
658
            iy = act_sr.by;
659
            dbgCC = "BITMAP";
660
            rwt = std::min(this->width - border * 2, width);
661
            rht = std::min(this->height - border_size * 2, height);
662
            break;
663
 
664
        case SC_TEXT:
665
            code = act_sr.jt;
666
            ix = act_sr.tx;
667
            iy = act_sr.ty;
668
            dbgCC = "TEXT";
669
            border += 4;
670
            rwt = std::min(this->width - border * 2, width);
671
            rht = std::min(this->height - border_size * 2, height);
672
            break;
673
    }
674
 
675
    if (width > rwt || height > rht)
676
        position.overflow = true;
677
 
678
    switch (code)
679
    {
680
        case 0: // absolute position
681
            position.left = ix;
682
 
683
            if (cc == SC_TEXT)
684
                position.top = iy + height * line;
685
            else
686
                position.top = iy;
687
 
688
            if (cc == SC_BITMAP && ix < 0 && rwt < width)
689
                position.left *= -1;
690
 
691
            if (cc == SC_BITMAP && iy < 0 && rht < height)
692
                position.top += -1;
693
 
694
            position.width = rwt;
695
            position.height = rht;
696
            break;
697
 
698
        case 1: // top, left
699
            if (cc == SC_TEXT)
700
            {
701
                position.left = border;
702
                position.top = height * line;
703
            }
704
 
705
            position.width = rwt;
706
            position.height = rht;
707
            break;
708
 
709
        case 2: // center, top
710
            if (cc == SC_TEXT)
711
                position.top = height * line;
712
 
713
            position.left = (this->width - rwt) / 2;
714
            position.height = rht;
715
            position.width = rwt;
716
            break;
717
 
718
        case 3: // right, top
719
            position.left = this->width - rwt;
720
 
721
            if (cc == SC_TEXT)
722
            {
723
                position.left = (((position.left - border) < 0) ? 0 : position.left - border);
724
                position.top = height * line;
725
            }
726
 
727
            position.width = rwt;
728
            position.height = rht;
729
            break;
730
 
731
        case 4: // left, middle
732
            if (cc == SC_TEXT)
733
            {
734
                position.left = border;
735
                position.top = ((this->height - rht) / 2) + (height / 2 * line);
736
            }
737
            else
738
                position.top = (this->height - rht) / 2;
739
 
740
            position.width = rwt;
741
            position.height = rht;
742
            break;
743
 
744
        case 6: // right, middle
745
            position.left = this->width - rwt;
746
 
747
            if (cc == SC_TEXT)
748
            {
749
                position.left = (((position.left - border) < 0) ? 0 : position.left - border);
750
                position.top = ((this->height - rht) / 2) + (height / 2 * line);
751
            }
752
            else
753
                position.top = (this->height - rht) / 2;
754
 
755
            position.width = rwt;
756
            position.height = rht;
757
            break;
758
 
759
        case 7: // left, bottom
760
            if (cc == SC_TEXT)
761
            {
762
                position.left = border_size;
763
                position.top = (this->height - rht) - height * line;
764
            }
765
            else
766
                position.top = this->height - rht;
767
 
768
            position.width = rwt;
769
            position.height = rht;
770
            break;
771
 
772
        case 8: // center, bottom
773
            position.left = (this->width - rwt) / 2;
774
 
775
            if (cc == SC_TEXT)
776
                position.top = (this->height - rht) - height * line;
777
            else
778
                position.top = this->height - rht;
779
 
780
            position.width = rwt;
781
            position.height = rht;
782
            break;
783
 
784
        case 9: // right, bottom
785
            position.left = this->width - rwt;
786
 
787
            if (cc == SC_TEXT)
788
            {
789
                position.left = (((position.left - border) < 0) ? 0 : position.left - border);
790
                position.top = (this->height - rht) - height * line;
791
            }
792
            else
793
                position.top = this->height - rht;
794
            break;
795
 
796
        default: // center, middle
797
            position.left = (this->width - rwt) / 2;
798
 
799
            if (cc == SC_TEXT)
800
                position.top = ((this->height - rht) / 2) + (height / 2 * line);
801
            else
802
                position.top = (this->height - rht) / 2;
803
 
804
            position.width = rwt;
805
            position.height = rht;
806
    }
807
 
808
    MSG_DEBUG("Type: " << dbgCC << ", PosType=" << code << ", Position: x=" << position.left << ", y=" << position.top << ", w=" << position.width << ", h=" << position.height << ", Overflow: " << (position.overflow ? "YES" : "NO"));
809
    position.valid = true;
810
    return position;
811
}
812
 
813
bool TPage::drawText(SkBitmap *img)
814
{
815
    MSG_TRACE("TSubPage::drawText(SkImage& img)");
816
 
817
    if (sr[0].te.empty())
818
        return true;
819
 
820
    MSG_DEBUG("Searching for font number " << sr[0].fi << " with text " << sr[0].te);
821
    FONT_T font = mFonts->getFont(sr[0].fi);
822
 
823
    if (!font.file.empty())
824
    {
825
        SkCanvas canvas(*img, SkSurfaceProps(1, kUnknown_SkPixelGeometry));
826
        sk_sp<SkTypeface> typeFace = mFonts->getTypeFace(sr[0].fi);
827
 
828
        if (!typeFace)
829
        {
830
            MSG_ERROR("Error creating type face " << font.fullName);
831
            TError::setError();
832
            return false;
833
        }
834
 
835
        SkScalar fontSizePt = ((SkScalar)font.size * 1.322);
836
        SkFont skFont(typeFace, fontSizePt);
837
 
838
        SkPaint paint;
839
        paint.setAntiAlias(true);
840
        SkColor color = TColor::getSkiaColor(sr[0].ct);
841
        paint.setColor(color);
842
        paint.setStyle(SkPaint::kFill_Style);
843
 
844
        SkFontMetrics metrics;
845
        skFont.getMetrics(&metrics);
846
        int lines = numberLines(sr[0].te);
847
 
848
        if (lines > 1 || sr[0].ww)
849
        {
850
            vector<string> textLines;
851
 
852
            if (!sr[0].ww)
853
                textLines = ::splitLine(sr[0].te);
854
            else
855
            {
856
                textLines = splitLine(sr[0].te, width, height, skFont, paint);
857
                lines = textLines.size();
858
            }
859
 
860
            int lineHeight = calcLineHeight(sr[0].te, skFont);
861
            int totalHeight = lineHeight * lines;
862
 
863
            if (totalHeight > height)
864
            {
865
                lines = height / lineHeight;
866
                totalHeight = lineHeight * lines;
867
            }
868
 
869
            MSG_DEBUG("Line height: " << lineHeight);
870
            POSITION_t position = calcImagePosition(width, totalHeight, SC_TEXT, 1);
871
            MSG_DEBUG("Position frame: l: " << position.left << ", t: " << position.top << ", w: " << position.width << ", h: " << position.height);
872
 
873
            if (!position.valid)
874
            {
875
                MSG_ERROR("Error calculating the text position!");
876
                TError::setError();
877
                return false;
878
            }
879
 
880
            vector<string>::iterator iter;
881
            int line = 0;
882
 
118 andreas 883
            for (iter = textLines.begin(); iter != textLines.end(); ++iter)
55 andreas 884
            {
885
                sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromString(iter->c_str(), skFont);
886
                SkRect rect;
887
                skFont.measureText(iter->c_str(), iter->length(), SkTextEncoding::kUTF8, &rect, &paint);
888
                POSITION_t pos = calcImagePosition(rect.width(), lineHeight, SC_TEXT, 1);
889
 
890
                if (!pos.valid)
891
                {
892
                    MSG_ERROR("Error calculating the text position!");
893
                    TError::setError();
894
                    return false;
895
                }
896
                MSG_DEBUG("Triing to print line: " << *iter);
897
 
898
                SkScalar startX = (SkScalar)pos.left;
899
                SkScalar startY = (SkScalar)position.top + lineHeight * line;
900
                MSG_DEBUG("x=" << startX << ", y=" << startY);
901
                canvas.drawTextBlob(blob, startX, startY + lineHeight / 2 + 4, paint);
902
                line++;
903
 
904
                if (line > lines)
905
                    break;
906
            }
907
        }
908
        else    // single line
909
        {
910
            sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromString(sr[0].te.c_str(), skFont);
911
            SkRect rect;
912
            skFont.measureText(sr[0].te.c_str(), sr[0].te.length(), SkTextEncoding::kUTF8, &rect, &paint);
913
            POSITION_t position = calcImagePosition(rect.width(), (rect.height() * (float)lines), SC_TEXT, 0);
914
 
915
            if (!position.valid)
916
            {
917
                MSG_ERROR("Error calculating the text position!");
918
                TError::setError();
919
                return false;
920
            }
921
 
922
            MSG_DEBUG("Printing line " << sr[0].te);
923
            SkScalar startX = (SkScalar)position.left;
924
            SkScalar startY = (SkScalar)position.top + metrics.fCapHeight; // + metrics.fLeading; // (metrics.fAscent * -1.0);
925
            canvas.drawTextBlob(blob, startX, startY, paint);
926
        }
927
    }
928
    else
929
    {
930
        MSG_WARNING("No font file name found for font " << sr[0].fi);
931
    }
932
 
933
    return true;
934
}
935
 
3 andreas 936
PAGECHAIN_T *TPage::addSubPage(TSubPage* pg)
937
{
14 andreas 938
    DECL_TRACER("TPage::addSubPage(TSubPage* pg)");
3 andreas 939
 
940
    if (!pg)
941
    {
942
        MSG_ERROR("Parameter is NULL!");
943
        TError::setError();
944
        return nullptr;
945
    }
946
 
947
    PAGECHAIN_T *chain = new PAGECHAIN_T;
948
    chain->subpage = pg;
14 andreas 949
    chain->next = nullptr;
154 andreas 950
    chain->prev = nullptr;
14 andreas 951
    PAGECHAIN_T *spg = mSubPages;
3 andreas 952
 
14 andreas 953
    if (spg)
3 andreas 954
    {
14 andreas 955
        // First make sure that the new page is not already in the chain.
956
        PAGECHAIN_T *p = spg;
3 andreas 957
 
14 andreas 958
        while (p)
13 andreas 959
        {
960
            if (p->subpage->getNumber() == pg->getNumber())
961
            {
14 andreas 962
                MSG_TRACE("Page " << pg->getNumber() << " is already in chain. Don't add it again.");
13 andreas 963
                delete chain;
964
                return p;
965
            }
966
 
3 andreas 967
            p = p->next;
13 andreas 968
        }
3 andreas 969
 
14 andreas 970
        // The subpage is not in chain. So we add it now.
971
        p = spg;
972
        // Find the last element in chain
40 andreas 973
        while (p && p->next)
14 andreas 974
            p = p->next;
975
 
3 andreas 976
        p->next = chain;
154 andreas 977
        chain->prev = p;
3 andreas 978
    }
979
    else
14 andreas 980
    {
981
        mZOrder = 0;
3 andreas 982
        mSubPages = chain;
14 andreas 983
    }
3 andreas 984
 
5 andreas 985
    mLastSubPage = 0;
3 andreas 986
    return chain;
987
}
988
 
989
bool TPage::removeSubPage(int ID)
990
{
991
    DECL_TRACER("TPage::removeSubPage(int ID)");
992
 
993
    PAGECHAIN_T *p = mSubPages;
994
    PAGECHAIN_T *prev = nullptr;
995
 
996
    while (p)
997
    {
998
        if (p->subpage->getNumber() == ID)
999
        {
1000
            PAGECHAIN_T *next = p->next;
1001
 
1002
            if (prev)
154 andreas 1003
            {
3 andreas 1004
                prev->next = next;
154 andreas 1005
                next->prev = prev;
1006
            }
3 andreas 1007
            else
154 andreas 1008
            {
3 andreas 1009
                mSubPages = next;
154 andreas 1010
                mSubPages->prev = nullptr;
1011
            }
3 andreas 1012
 
1013
            delete p;
5 andreas 1014
            mLastSubPage = 0;
3 andreas 1015
            return true;
1016
        }
1017
 
1018
        prev = p;
1019
        p = p->next;
1020
    }
1021
 
1022
    return false;
1023
}
1024
 
1025
bool TPage::removeSubPage(const std::string& nm)
1026
{
1027
    DECL_TRACER("TPage::removeSubPage(const std::string& nm)");
1028
 
1029
    PAGECHAIN_T *p = mSubPages;
1030
    PAGECHAIN_T *prev = nullptr;
1031
 
1032
    while (p)
1033
    {
1034
        if (p->subpage->getName().compare(nm) == 0)
1035
        {
1036
            PAGECHAIN_T *next = p->next;
1037
 
1038
            if (prev)
154 andreas 1039
            {
3 andreas 1040
                prev->next = next;
154 andreas 1041
                next->prev = prev;
1042
            }
3 andreas 1043
            else
154 andreas 1044
            {
3 andreas 1045
                mSubPages = next;
154 andreas 1046
                mSubPages->prev = nullptr;
1047
            }
3 andreas 1048
 
1049
            delete p;
5 andreas 1050
            mLastSubPage = 0;
3 andreas 1051
            return true;
1052
        }
1053
 
1054
        prev = p;
1055
        p = p->next;
1056
    }
1057
 
1058
    return false;
1059
}
1060
 
4 andreas 1061
TSubPage *TPage::getSubPage(int pageID)
1062
{
1063
    DECL_TRACER("TPage::getSubPage(int pageID)");
1064
 
1065
    PAGECHAIN_T *pg = mSubPages;
1066
 
1067
    while (pg)
1068
    {
1069
        if (pg->subpage->getNumber() == pageID)
1070
        {
1071
            mLastSubPage = pageID;
1072
            return pg->subpage;
1073
        }
1074
 
1075
        pg = pg->next;
1076
    }
1077
 
5 andreas 1078
    mLastSubPage = 0;
4 andreas 1079
    return nullptr;
1080
}
1081
 
1082
TSubPage *TPage::getSubPage(const std::string& name)
1083
{
1084
    DECL_TRACER("TPage::getSubPage(const std::string& name)");
1085
 
1086
    PAGECHAIN_T *pg = mSubPages;
1087
 
1088
    while (pg)
1089
    {
1090
        if (pg->subpage->getName().compare(name) == 0)
1091
        {
14 andreas 1092
            mLastSubPage = pg->subpage->getNumber();
4 andreas 1093
            return pg->subpage;
1094
        }
1095
 
1096
        pg = pg->next;
1097
    }
1098
 
5 andreas 1099
    mLastSubPage = 0;
4 andreas 1100
    return nullptr;
1101
}
1102
 
1103
TSubPage *TPage::getFirstSubPage()
1104
{
1105
    DECL_TRACER("TPage::getFirstSubPage()");
1106
 
14 andreas 1107
    PAGECHAIN_T *pg = mSubPages;
1108
 
154 andreas 1109
    if (pg && pg->subpage)
4 andreas 1110
    {
154 andreas 1111
        mLastSubPage = pg->subpage->getNumber();
1112
        MSG_DEBUG("Subpage (Z: " << pg->subpage->getZOrder() << "): " << pg->subpage->getNumber() << ". " << pg->subpage->getName());
1113
        return pg->subpage;
4 andreas 1114
    }
1115
 
14 andreas 1116
    MSG_DEBUG("No subpages in chain.");
5 andreas 1117
    mLastSubPage = 0;
4 andreas 1118
    return nullptr;
1119
}
1120
 
1121
TSubPage *TPage::getNextSubPage()
1122
{
1123
    DECL_TRACER("TPage::getNextSubPage()");
1124
 
154 andreas 1125
    if (mLastSubPage > 0 && mSubPages)
4 andreas 1126
    {
1127
        PAGECHAIN_T *p = mSubPages;
1128
 
1129
        while (p)
1130
        {
1131
            if (p->subpage->getNumber() == mLastSubPage)
1132
            {
14 andreas 1133
                if (p->next && p->next->subpage)
4 andreas 1134
                {
14 andreas 1135
                    TSubPage *page = p->next->subpage;
1136
                    mLastSubPage = page->getNumber();
151 andreas 1137
                    MSG_DEBUG("Subpage (Z: " << page->getZOrder() << "): " << page->getNumber() << ". " << page->getName());
14 andreas 1138
                    return page;
4 andreas 1139
                }
1140
            }
1141
 
1142
            p = p->next;
1143
        }
1144
    }
1145
 
14 andreas 1146
    MSG_DEBUG("No more subpages in chain.");
5 andreas 1147
    mLastSubPage = 0;
4 andreas 1148
    return nullptr;
1149
}
1150
 
154 andreas 1151
TSubPage *TPage::getPrevSubPage()
1152
{
1153
    DECL_TRACER("TPage::getPrevSubPage()");
1154
 
1155
    if (mLastSubPage < MAX_PAGE_ID || !mSubPages)
1156
        return nullptr;
1157
 
1158
    PAGECHAIN_T *pg = mSubPages;
1159
 
1160
    while (pg)
1161
    {
1162
        if (pg->subpage->getNumber() == mLastSubPage)
1163
        {
1164
            if (!pg->prev)
1165
            {
1166
                mLastSubPage = 0;
1167
                MSG_DEBUG("No more subpages in chain.");
1168
                return nullptr;
1169
            }
1170
 
1171
            mLastSubPage = pg->prev->subpage->getNumber();
1172
            return pg->prev->subpage;
1173
        }
1174
 
1175
        pg = pg->next;
1176
    }
1177
 
1178
    MSG_DEBUG("No more subpages in chain.");
1179
    mLastSubPage = 0;
1180
    return nullptr;
1181
}
1182
 
1183
TSubPage *TPage::getLastSubPage()
1184
{
1185
    DECL_TRACER("TPage::getLastSubPage()");
1186
 
1187
    if (!mSubPages)
1188
    {
1189
        mLastSubPage = 0;
1190
        MSG_DEBUG("No subpages in cache!");
1191
        return nullptr;
1192
    }
1193
 
1194
    PAGECHAIN_T *pg = mSubPages;
1195
 
1196
    while (pg && pg->next)
1197
        pg = pg->next;
1198
 
1199
    mLastSubPage = pg->subpage->getNumber();
1200
    return pg->subpage;
1201
}
1202
 
3 andreas 1203
BUTTONS_T *TPage::addButton(TButton* button)
1204
{
1205
    DECL_TRACER("*TPage::addButton(TButton* button)");
1206
 
1207
    if (!button)
1208
    {
1209
        MSG_ERROR("Parameter is NULL!");
1210
        TError::setError();
1211
        return nullptr;
1212
    }
1213
 
1214
    BUTTONS_T *chain = new BUTTONS_T;
14 andreas 1215
    BUTTONS_T *bts = mButtons;
3 andreas 1216
    chain->button = button;
40 andreas 1217
    chain->next = nullptr;
1218
    chain->previous = nullptr;
3 andreas 1219
 
14 andreas 1220
    if (bts)
3 andreas 1221
    {
14 andreas 1222
        BUTTONS_T *p = bts;
3 andreas 1223
 
40 andreas 1224
        while (p && p->next)
3 andreas 1225
            p = p->next;
1226
 
1227
        p->next = chain;
1228
        chain->previous = p;
1229
    }
1230
    else
1231
        mButtons = chain;
1232
 
1233
    return chain;
1234
}
1235
 
14 andreas 1236
bool TPage::hasButton(int id)
1237
{
1238
    DECL_TRACER("TPage::hasButton(int id)");
1239
 
1240
    BUTTONS_T *bt = mButtons;
1241
 
1242
    while (bt)
1243
    {
1244
        if (bt->button && bt->button->getButtonIndex() == id)
1245
            return true;
1246
 
1247
        bt = bt->next;
1248
    }
1249
 
1250
    return false;
1251
}
1252
 
1253
TButton *TPage::getButton(int id)
1254
{
1255
    DECL_TRACER("TPage::getButton(int id)");
1256
 
1257
    BUTTONS_T *bt = mButtons;
1258
 
1259
    while (bt)
1260
    {
1261
        if (bt->button && bt->button->getButtonIndex() == id)
1262
            return bt->button;
1263
 
1264
        bt = bt->next;
1265
    }
1266
 
1267
    return nullptr;
1268
}
1269
 
16 andreas 1270
std::vector<TButton *> TPage::getButtons(int ap, int ad)
1271
{
1272
    DECL_TRACER("TSubPage::getButtons(int ap, int ad)");
1273
 
1274
    std::vector<TButton *> list;
1275
    BUTTONS_T *bt = mButtons;
1276
 
1277
    while (bt)
1278
    {
1279
        if (bt->button->getAddressPort() == ap && bt->button->getAddressChannel() == ad)
1280
            list.push_back(bt->button);
1281
 
1282
        bt = bt->next;
1283
    }
1284
 
1285
    return list;
1286
}
1287
 
51 andreas 1288
std::vector<TButton *> TPage::getAllButtons()
1289
{
1290
    DECL_TRACER("TPage::getAllButtons()");
40 andreas 1291
 
51 andreas 1292
    std::vector<TButton *> list;
1293
    BUTTONS_T *bt = mButtons;
1294
 
1295
    while (bt)
1296
    {
1297
        list.push_back(bt->button);
1298
        bt = bt->next;
1299
    }
1300
 
1301
    return list;
1302
}
1303
 
40 andreas 1304
TButton *TPage::getFirstButton()
1305
{
1306
    DECL_TRACER("TButton::getFirstButton()");
1307
 
1308
    mLastButton = 0;
1309
 
1310
    if (mButtons)
1311
        return mButtons->button;
1312
 
1313
    return nullptr;
1314
}
1315
 
1316
TButton *TPage::getNextButton()
1317
{
1318
    DECL_TRACER("TPage::getNextButton()");
1319
 
1320
    BUTTONS_T *but = mButtons;
1321
    int count = 0;
1322
    mLastButton++;
1323
 
1324
    while (but)
1325
    {
1326
        if (but->button && count == mLastButton)
1327
            return but->button;
1328
 
1329
        but = but->next;
1330
        count++;
1331
    }
1332
 
1333
    return nullptr;
1334
}
1335
 
150 andreas 1336
TButton *TPage::getLastButton()
1337
{
1338
    DECL_TRACER("TPage::getLastButton()");
1339
 
1340
    BUTTONS_T *but = mButtons;
1341
    mLastButton = 0;
1342
 
1343
    while (but && but->next)
1344
    {
1345
        mLastButton++;
1346
        but = but->next;
1347
    }
1348
 
154 andreas 1349
    if (!but)
1350
        return nullptr;
1351
 
150 andreas 1352
    return but->button;
1353
}
1354
 
1355
TButton *TPage::getPreviousButton()
1356
{
1357
    DECL_TRACER("TPage::getPreviousButton()");
1358
 
1359
    BUTTONS_T *but = mButtons;
1360
    int count = 0;
1361
 
1362
    if (mLastButton)
1363
        mLastButton--;
1364
    else
1365
        return nullptr;
1366
 
1367
    while (but)
1368
    {
1369
        if (but->button && count == mLastButton)
1370
            return but->button;
1371
 
1372
        but = but->next;
1373
        count++;
1374
    }
1375
 
1376
    return nullptr;
1377
}
1378
 
12 andreas 1379
void TPage::drop()
1380
{
1381
    DECL_TRACER("TPage::drop()");
1382
 
1383
    PAGECHAIN_T *pc = mSubPages;
14 andreas 1384
 
147 andreas 1385
    // remove all subpages, if there are any
12 andreas 1386
    while (pc)
1387
    {
147 andreas 1388
        MSG_DEBUG("Dropping popup " << pc->subpage->getNumber() << ": " << pc->subpage->getName());
13 andreas 1389
        pc->subpage->drop();
12 andreas 1390
        pc = pc->next;
1391
    }
14 andreas 1392
 
147 andreas 1393
    // remove all buttons, if there are any
1394
    BUTTONS_T *bt = mButtons;
1395
 
1396
    while (bt)
1397
    {
1398
        MSG_DEBUG("Dropping button " << TObject::handleToString(bt->button->getHandle()));
1399
        bt->button->hide(true);
1400
        bt = bt->next;
1401
    }
1402
 
14 andreas 1403
    mZOrder = ZORDER_INVALID;
1404
    mVisible = false;
12 andreas 1405
}
43 andreas 1406
#ifdef _SCALE_SKIA_
31 andreas 1407
void TPage::calcPosition(int im_width, int im_height, int *left, int *top, bool scale)
43 andreas 1408
#else
1409
void TPage::calcPosition(int im_width, int im_height, int *left, int *top)
1410
#endif
28 andreas 1411
{
1412
    DECL_TRACER("TPage::calcPosition(int im_width, int im_height, int *left, int *top)");
1413
 
1414
    int nw = width;
1415
    int nh = height;
43 andreas 1416
#ifdef _SCALE_SKIA_
31 andreas 1417
    if (scale && gPageManager && gPageManager->getScaleFactor() != 1.0)
28 andreas 1418
    {
1419
        nw = (int)((double)width * gPageManager->getScaleFactor());
1420
        nh = (int)((double)height * gPageManager->getScaleFactor());
1421
    }
43 andreas 1422
#endif
28 andreas 1423
    switch (sr[0].jb)
1424
    {
1425
        case 0: // absolute position
1426
            *left = sr[0].bx;
1427
            *top = sr[0].by;
43 andreas 1428
#ifdef _SCALE_SKIA_
31 andreas 1429
            if (scale && gPageManager && gPageManager->getScaleFactor() != 1.0)
28 andreas 1430
            {
1431
                *left = (int)((double)sr[0].bx * gPageManager->getScaleFactor());
1432
                *left = (int)((double)sr[0].by * gPageManager->getScaleFactor());
1433
            }
43 andreas 1434
#endif
28 andreas 1435
        break;
1436
 
1437
        case 1: // top, left
1438
            *left = 0;
1439
            *top = 0;
1440
        break;
1441
 
1442
        case 2: // center, top
1443
            *left = (nw - im_width) / 2;
1444
            *top = 0;
1445
        break;
1446
 
1447
        case 3: // right, top
1448
            *left = nw - im_width;
1449
            *top = 0;
1450
        break;
1451
 
1452
        case 4: // left, middle
1453
            *left = 0;
1454
            *top = (nh - im_height) / 2;
1455
        break;
1456
 
1457
        case 6: // right, middle
1458
            *left = nw - im_width;
1459
            *top = (nh - im_height) / 2;
1460
        break;
1461
 
1462
        case 7: // left, bottom
1463
            *left = 0;
1464
            *top = nh - im_height;
1465
        break;
1466
 
1467
        case 8: // center, bottom
1468
            *left = (nw - im_width) / 2;
1469
            *top = nh - im_height;
1470
        break;
1471
 
1472
        case 9: // right, bottom
1473
            *left = nw - im_width;
1474
            *top = nh - im_height;
1475
        break;
31 andreas 1476
 
1477
        default:    // center middle
1478
            *left = (nw - im_width) / 2;
1479
            *top = (nh - im_height) / 2;
28 andreas 1480
    }
1481
 
1482
    if (*left < 0)
1483
        *left = 0;
1484
 
1485
    if (*top < 0)
1486
        *top = 0;
1487
}
1488
 
151 andreas 1489
void TPage::sortSubpages()
1490
{
1491
    DECL_TRACER("TPage::sortSubpage()");
1492
 
154 andreas 1493
    PAGECHAIN_T *pages = nullptr;
1494
    bool turned = false;
151 andreas 1495
 
154 andreas 1496
    // Here we do a simple bubble sort to bring the subpages in ascending Z-order
1497
    do
151 andreas 1498
    {
154 andreas 1499
        turned = false;
1500
        pages = mSubPages;
151 andreas 1501
 
154 andreas 1502
        while (pages && pages->next)
1503
        {
1504
            int actZ = 0;
1505
            int nextZ = 0;
151 andreas 1506
 
154 andreas 1507
            if (pages->next->subpage && pages->subpage)
1508
            {
1509
                nextZ = pages->next->subpage->getZOrder();
1510
                actZ = pages->subpage->getZOrder();
1511
            }
151 andreas 1512
 
154 andreas 1513
            if (actZ > nextZ)   // Turn?
1514
            {                   // Yes, then change only pointers to subpages
1515
                TSubPage *sp = pages->next->subpage;
151 andreas 1516
 
154 andreas 1517
                pages->next->subpage = pages->subpage;
1518
                pages->subpage = sp;
1519
                turned = true;
1520
            }
1521
 
1522
            pages = pages->next;
1523
        }
1524
    }
1525
    while (turned);
151 andreas 1526
}
1527
 
3 andreas 1528
/*
1529
 * Sort the button according to their Z-order.
1530
 * The button with the highest Z-order will be the last button in the chain.
1531
 * The algorithm is a bubble sort algorithm.
1532
 */
1533
bool TPage::sortButtons()
1534
{
1535
    DECL_TRACER("TPage::sortButtons()");
1536
 
1537
    bool turned = true;
1538
 
1539
    while (turned)
1540
    {
1541
        BUTTONS_T *button = mButtons;
1542
        turned = false;
1543
 
1544
        while (button)
1545
        {
1546
            int zo = button->button->getZOrder();
1547
 
1548
            if (button->previous)
1549
            {
1550
                if (zo < button->previous->button->getZOrder())
1551
                {
1552
                    BUTTONS_T *pprev = button->previous->previous;
1553
                    BUTTONS_T *prev = button->previous;
1554
                    BUTTONS_T *next = button->next;
1555
 
1556
                    if (pprev)
1557
                        pprev->next = button;
1558
 
1559
                    prev->next = next;
1560
                    prev->previous = button;
1561
                    button->next = prev;
1562
                    button->previous = pprev;
14 andreas 1563
 
1564
                    if (!pprev)
1565
                        mButtons = button;
1566
 
3 andreas 1567
                    button = next;
14 andreas 1568
 
1569
                    if (next)
1570
                        next->previous = prev;
1571
 
3 andreas 1572
                    turned = true;
1573
                    continue;
1574
                }
1575
            }
1576
 
1577
            button = button->next;
1578
        }
1579
    }
1580
 
1581
    return true;
1582
}
151 andreas 1583
 
152 andreas 1584
int TPage::getNextZOrder()
1585
{
1586
    DECL_TRACER("TPage::getNextZOrder()");
1587
 
1588
    // Find highest z-order number
1589
    PAGECHAIN_T *pages = mSubPages;
154 andreas 1590
    int cnt = 0;
152 andreas 1591
 
1592
    while(pages)
1593
    {
154 andreas 1594
        if (pages->subpage->getZOrder() != ZORDER_INVALID)
1595
        {
1596
            cnt++;
1597
            pages->subpage->setZOrder(cnt);
1598
        }
152 andreas 1599
 
1600
        pages = pages->next;
1601
    }
1602
 
154 andreas 1603
    mZOrder = cnt + 1;
152 andreas 1604
    MSG_DEBUG("New Z-order: " << mZOrder);
1605
    return mZOrder;
1606
}
1607
 
151 andreas 1608
int TPage::decZOrder()
1609
{
1610
    DECL_TRACER("TPage::decZOrder()");
1611
 
1612
    // Find highest z-order number
1613
    PAGECHAIN_T *pages = mSubPages;
1614
    int z = 0;
1615
 
1616
    while(pages)
1617
    {
154 andreas 1618
        if (pages->subpage->getZOrder() != ZORDER_INVALID)
1619
        {
1620
            z++;
1621
            pages->subpage->setZOrder(z);
1622
        }
151 andreas 1623
 
1624
        pages = pages->next;
1625
    }
1626
 
1627
    mZOrder = z;
1628
    return mZOrder;
1629
}