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