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>
5 andreas 22
#include "tresources.h"
26 andreas 23
#include "tpagemanager.h"
2 andreas 24
#include "tpage.h"
25
 
3 andreas 26
using std::string;
27
using namespace Button;
28
 
26 andreas 29
extern TPageManager *gPageManager;
30
 
3 andreas 31
TPage::TPage(const string& name)
2 andreas 32
{
3 andreas 33
    DECL_TRACER("TPage::TPage(const string& name)");
14 andreas 34
    TError::clear();
3 andreas 35
    initialize(name);
36
}
2 andreas 37
 
3 andreas 38
TPage::~TPage()
39
{
5 andreas 40
    DECL_TRACER("TPage::~TPage()");
41
 
42
    MSG_DEBUG("Destroing page " << pageID << ": " << name);
3 andreas 43
    BUTTONS_T *p = mButtons;
44
    BUTTONS_T *next = nullptr;
2 andreas 45
 
3 andreas 46
    while (p)
47
    {
48
        next = p->next;
49
        delete p->button;
50
        delete p;
51
        p = next;
52
    }
2 andreas 53
 
3 andreas 54
    mButtons = nullptr;
55
 
56
    PAGECHAIN_T *pc = mSubPages;
57
    PAGECHAIN_T *pc_next = nullptr;
58
 
59
    // We're not allowd to delete the subpages here, because they're managed
60
    // by the TPageManager.
61
    while (pc)
62
    {
63
        pc_next = pc->next;
64
        delete pc;
65
        pc = pc_next;
66
    }
67
 
68
    mSubPages = nullptr;
69
}
70
 
71
void TPage::initialize(const string& nm)
72
{
73
    DECL_TRACER("TPage::initialize(const string& name)");
74
    makeFileName(TConfig::getProjectPath(), nm);
75
 
76
    if (isValidFile())
77
        mPath = getFileName();
78
 
79
    TReadXML reader(mPath);
80
 
81
    if (TError::isError())
82
        return;
83
 
84
    reader.findElement("page", "type");
85
 
86
    if (!reader.success())
87
    {
88
        MSG_ERROR("Element \"page\" with attribute \"type\" was not found!");
89
        TError::setError();
90
        return;
91
    }
92
 
93
    string type = reader.getAttribute("type");
94
 
95
    if (type.compare("page") != 0)
96
    {
97
        MSG_ERROR("Invalid page type \"" << type << "\"!");
98
        TError::setError();
99
        return;
100
    }
101
 
102
    mxml_node_t *node = reader.getFirstChild();
103
 
104
    while (node)
105
    {
106
        string e = reader.getElementName(node);
107
 
108
        if (e.compare("pageID") == 0)
109
            pageID = reader.getIntFromNode(node);
110
        else if (e.compare("name") == 0)
111
            name = reader.getTextFromNode(node);
112
        else if (e.compare("width") == 0)
113
            width = reader.getIntFromNode(node);
114
        else if (e.compare("height") == 0)
115
            height = reader.getIntFromNode(node);
116
        else if (e.compare("button") == 0)
117
        {
118
            TButton *button = new TButton();
4 andreas 119
            button->setPalette(mPalette);
7 andreas 120
            button->setFonts(mFonts);
121
            button->registerCallback(_displayButton);
122
            button->registerCallbackFT(_setText);
21 andreas 123
            button->regCallPlayVideo(_playVideo);
3 andreas 124
            button->initialize(&reader, node);
125
 
126
            if (TError::isError())
127
            {
23 andreas 128
                MSG_WARNING("Button \"" << button->getButtonName() << "\" deleted because of an error!");
3 andreas 129
                delete button;
130
                return;
131
            }
132
 
5 andreas 133
            button->setHandle(((pageID << 16) & 0xffff0000) | button->getButtonIndex());
14 andreas 134
            button->createButtons();
3 andreas 135
            addButton(button);
136
        }
137
        else if (e.compare("sr") == 0)
138
        {
139
            SR_T bsr;
140
            bsr.number = atoi(reader.getAttributeFromNode(node, "number").c_str());
141
            mxml_node_t *n = reader.getFirstChild(node);
142
 
143
            while (n)
144
            {
145
                string ename = reader.getElementName(n);
146
 
147
                if (ename.compare("bs") == 0)
148
                    bsr.bs = reader.getTextFromNode(n);
149
                else if (ename.compare("cb") == 0)
150
                    bsr.cb = reader.getTextFromNode(n);
151
                else if (ename.compare("cf") == 0)
152
                    bsr.cf = reader.getTextFromNode(n);
153
                else if (ename.compare("ct") == 0)
154
                    bsr.ct = reader.getTextFromNode(n);
155
                else if (ename.compare("ec") == 0)
156
                    bsr.ec = reader.getTextFromNode(n);
157
                else if (ename.compare("bm") == 0)
158
                    bsr.bm = reader.getTextFromNode(n);
159
                else if (ename.compare("fi") == 0)
160
                    bsr.fi = reader.getIntFromNode(n);
161
 
5 andreas 162
                n = reader.getNextChild(n);
3 andreas 163
            }
164
 
165
            sr.push_back(bsr);
166
        }
167
 
168
        node = reader.getNextChild();
169
    }
170
 
171
    sortButtons();
172
}
173
 
5 andreas 174
void TPage::show()
175
{
176
    DECL_TRACER("TPage::show()");
177
 
178
    if (!_setBackground)
179
    {
31 andreas 180
        if (gPageManager && gPageManager->getCallbackBG())
181
            _setBackground = gPageManager->getCallbackBG();
182
        else
183
        {
184
            MSG_WARNING("No callback \"setBackground\" was set!");
185
            return;
186
        }
5 andreas 187
    }
188
 
189
    ulong handle = (pageID << 16) & 0xffff0000;
190
    MSG_DEBUG("Processing page " << pageID);
191
 
192
    if (!sr[0].bm.empty())
193
    {
194
        sk_sp<SkData> rawImage = readImage(sr[0].bm);
195
 
196
        if (rawImage)
197
        {
198
            SkBitmap bm;
28 andreas 199
            int l, t;
200
 
5 andreas 201
            DecodeDataToBitmap(rawImage, &bm);
202
            SkImageInfo info = bm.info();
203
            size_t rowBytes = info.minRowBytes();
204
            size_t size = info.computeByteSize(rowBytes);
28 andreas 205
            calcPosition(info.width(), info.height(), &l, &t);
31 andreas 206
            MSG_DEBUG("Background image size: l=" << l << ", t=" << t << ", w=" << info.width() << ", h=" << info.height());
28 andreas 207
            sk_sp<SkImage> im = SkImage::MakeFromBitmap(bm);
208
            bm.allocN32Pixels(width, height);
209
            bm.eraseColor(TColor::getSkiaColor(sr[0].cf));
210
            SkCanvas can(bm, SkSurfaceProps(1, kUnknown_SkPixelGeometry));
31 andreas 211
            SkRect rect = SkRect::MakeXYWH(l, t, info.width(), info.height());
28 andreas 212
            SkPaint paint;
213
            paint.setBlendMode(SkBlendMode::kSrc);
214
            can.drawImageRect(im, rect, &paint);
215
            rowBytes = bm.info().minRowBytes();
216
            size = bm.info().computeByteSize(rowBytes);
26 andreas 217
 
218
            if (gPageManager && gPageManager->getScaleFactor() != 1.0)
219
            {
220
                paint.setFilterQuality(kHigh_SkFilterQuality);
28 andreas 221
                // Calculate new dimension
31 andreas 222
                double scaleFactor = gPageManager->getScaleFactor();
223
                MSG_DEBUG("Using scale factor " << scaleFactor);
224
                int lwidth = (int)((double)info.width() * scaleFactor);
225
                int lheight = (int)((double)info.height() * scaleFactor);
226
                int twidth = (int)((double)width * scaleFactor);
227
                int theight = (int)((double)height * scaleFactor);
228
                calcPosition(lwidth, lheight, &l, &t, true);
229
                MSG_DEBUG("Scaled background image: l=" << l << ", t=" << t << ", w=" << lwidth << ", h=" << lheight << ", total w=" << twidth << ", total h=" << theight);
28 andreas 230
                // Create a canvas and draw new image
26 andreas 231
                sk_sp<SkImage> im = SkImage::MakeFromBitmap(bm);
28 andreas 232
                bm.allocN32Pixels(twidth, theight);
26 andreas 233
                bm.eraseColor(TColor::getSkiaColor(sr[0].cf));
31 andreas 234
                SkCanvas can1(bm, SkSurfaceProps(1, kUnknown_SkPixelGeometry));
235
                SkRect rect = SkRect::MakeXYWH(l, t, lwidth, lheight);
236
                can1.drawImageRect(im, rect, &paint);
28 andreas 237
                rowBytes = bm.info().minRowBytes();
238
                size = bm.info().computeByteSize(rowBytes);
26 andreas 239
            }
240
 
5 andreas 241
            _setBackground(handle, (unsigned char *)bm.getPixels(), size, rowBytes, TColor::getColor(sr[0].cf));
242
        }
243
        else
244
        {
245
            MSG_WARNING("Couldn't read image " << sr[0].bm);
26 andreas 246
            _setBackground(handle, nullptr, 0, 0, TColor::getColor(sr[0].cf));
5 andreas 247
        }
248
    }
249
    else
250
    {
26 andreas 251
        MSG_DEBUG("Calling \"setBackground\" with no image ...");
252
        _setBackground(handle, nullptr, 0, 0, TColor::getColor(sr[0].cf));
5 andreas 253
    }
254
 
26 andreas 255
    // Draw the buttons
256
    BUTTONS_T *button = mButtons;
257
 
258
    while (button)
259
    {
260
        if (button->button)
261
        {
262
            MSG_DEBUG("Drawing button " << button->button->getButtonIndex() << ": " << button->button->getButtonName());
263
            button->button->registerCallback(_displayButton);
264
            button->button->registerCallbackFT(_setText);
265
            button->button->regCallPlayVideo(_playVideo);
266
            button->button->setFonts(mFonts);
267
            button->button->setPalette(mPalette);
268
            button->button->createButtons();
269
 
270
            if (sr.size() > 0)
271
                button->button->setGlobalOpacity(sr[0].oo);
272
 
273
            button->button->show();
274
        }
275
 
276
        button = button->next;
277
    }
278
 
14 andreas 279
    mVisible = true;
5 andreas 280
}
281
 
3 andreas 282
PAGECHAIN_T *TPage::addSubPage(TSubPage* pg)
283
{
14 andreas 284
    DECL_TRACER("TPage::addSubPage(TSubPage* pg)");
3 andreas 285
 
286
    if (!pg)
287
    {
288
        MSG_ERROR("Parameter is NULL!");
289
        TError::setError();
290
        return nullptr;
291
    }
292
 
293
    PAGECHAIN_T *chain = new PAGECHAIN_T;
294
    chain->subpage = pg;
14 andreas 295
    chain->next = nullptr;
296
    PAGECHAIN_T *spg = mSubPages;
3 andreas 297
 
14 andreas 298
    if (spg)
3 andreas 299
    {
14 andreas 300
        // First make sure that the new page is not already in the chain.
301
        PAGECHAIN_T *p = spg;
3 andreas 302
 
14 andreas 303
        while (p)
13 andreas 304
        {
305
            if (p->subpage->getNumber() == pg->getNumber())
306
            {
14 andreas 307
                MSG_TRACE("Page " << pg->getNumber() << " is already in chain. Don't add it again.");
13 andreas 308
                delete chain;
309
                return p;
310
            }
311
 
3 andreas 312
            p = p->next;
13 andreas 313
        }
3 andreas 314
 
14 andreas 315
        // The subpage is not in chain. So we add it now.
316
        p = spg;
317
        // Find the last element in chain
318
        while (p->next)
319
            p = p->next;
320
 
3 andreas 321
        p->next = chain;
322
    }
323
    else
14 andreas 324
    {
325
        mZOrder = 0;
3 andreas 326
        mSubPages = chain;
14 andreas 327
    }
3 andreas 328
 
5 andreas 329
    mLastSubPage = 0;
3 andreas 330
    return chain;
331
}
332
 
333
bool TPage::removeSubPage(int ID)
334
{
335
    DECL_TRACER("TPage::removeSubPage(int ID)");
336
 
337
    PAGECHAIN_T *p = mSubPages;
338
    PAGECHAIN_T *prev = nullptr;
339
 
340
    while (p)
341
    {
342
        if (p->subpage->getNumber() == ID)
343
        {
344
            PAGECHAIN_T *next = p->next;
345
 
346
            if (prev)
347
                prev->next = next;
348
            else
349
                mSubPages = next;
350
 
351
            delete p;
5 andreas 352
            mLastSubPage = 0;
3 andreas 353
            return true;
354
        }
355
 
356
        prev = p;
357
        p = p->next;
358
    }
359
 
360
    return false;
361
}
362
 
363
bool TPage::removeSubPage(const std::string& nm)
364
{
365
    DECL_TRACER("TPage::removeSubPage(const std::string& nm)");
366
 
367
    PAGECHAIN_T *p = mSubPages;
368
    PAGECHAIN_T *prev = nullptr;
369
 
370
    while (p)
371
    {
372
        if (p->subpage->getName().compare(nm) == 0)
373
        {
374
            PAGECHAIN_T *next = p->next;
375
 
376
            if (prev)
377
                prev->next = next;
378
            else
379
                mSubPages = next;
380
 
381
            delete p;
5 andreas 382
            mLastSubPage = 0;
3 andreas 383
            return true;
384
        }
385
 
386
        prev = p;
387
        p = p->next;
388
    }
389
 
390
    return false;
391
}
392
 
4 andreas 393
TSubPage *TPage::getSubPage(int pageID)
394
{
395
    DECL_TRACER("TPage::getSubPage(int pageID)");
396
 
397
    PAGECHAIN_T *pg = mSubPages;
398
 
399
    while (pg)
400
    {
401
        if (pg->subpage->getNumber() == pageID)
402
        {
403
            mLastSubPage = pageID;
404
            return pg->subpage;
405
        }
406
 
407
        pg = pg->next;
408
    }
409
 
5 andreas 410
    mLastSubPage = 0;
4 andreas 411
    return nullptr;
412
}
413
 
414
TSubPage *TPage::getSubPage(const std::string& name)
415
{
416
    DECL_TRACER("TPage::getSubPage(const std::string& name)");
417
 
418
    PAGECHAIN_T *pg = mSubPages;
419
 
420
    while (pg)
421
    {
422
        if (pg->subpage->getName().compare(name) == 0)
423
        {
14 andreas 424
            mLastSubPage = pg->subpage->getNumber();
4 andreas 425
            return pg->subpage;
426
        }
427
 
428
        pg = pg->next;
429
    }
430
 
5 andreas 431
    mLastSubPage = 0;
4 andreas 432
    return nullptr;
433
}
434
 
435
TSubPage *TPage::getFirstSubPage()
436
{
437
    DECL_TRACER("TPage::getFirstSubPage()");
438
 
14 andreas 439
    PAGECHAIN_T *pg = mSubPages;
440
 
441
    if (pg)
4 andreas 442
    {
14 andreas 443
        if (pg->subpage)
4 andreas 444
        {
14 andreas 445
            mLastSubPage = pg->subpage->getNumber();
446
            MSG_DEBUG("Subpage " << pg->subpage->getNumber() << ". " << pg->subpage->getName());
447
            return pg->subpage;
4 andreas 448
        }
449
    }
450
 
14 andreas 451
    MSG_DEBUG("No subpages in chain.");
5 andreas 452
    mLastSubPage = 0;
4 andreas 453
    return nullptr;
454
}
455
 
456
TSubPage *TPage::getNextSubPage()
457
{
458
    DECL_TRACER("TPage::getNextSubPage()");
459
 
460
    if (mLastSubPage > 0)
461
    {
462
        PAGECHAIN_T *p = mSubPages;
463
 
464
        while (p)
465
        {
466
            if (p->subpage->getNumber() == mLastSubPage)
467
            {
14 andreas 468
                if (p->next && p->next->subpage)
4 andreas 469
                {
14 andreas 470
                    TSubPage *page = p->next->subpage;
471
                    mLastSubPage = page->getNumber();
15 andreas 472
                    MSG_DEBUG("Subpage " << page->getNumber() << ". " << page->getName());
14 andreas 473
                    return page;
4 andreas 474
                }
475
            }
476
 
477
            p = p->next;
478
        }
479
    }
480
 
14 andreas 481
    MSG_DEBUG("No more subpages in chain.");
5 andreas 482
    mLastSubPage = 0;
4 andreas 483
    return nullptr;
484
}
485
 
3 andreas 486
BUTTONS_T *TPage::addButton(TButton* button)
487
{
488
    DECL_TRACER("*TPage::addButton(TButton* button)");
489
 
490
    if (!button)
491
    {
492
        MSG_ERROR("Parameter is NULL!");
493
        TError::setError();
494
        return nullptr;
495
    }
496
 
497
    BUTTONS_T *chain = new BUTTONS_T;
14 andreas 498
    BUTTONS_T *bts = mButtons;
3 andreas 499
    chain->button = button;
500
 
14 andreas 501
    if (bts)
3 andreas 502
    {
14 andreas 503
        BUTTONS_T *p = bts;
3 andreas 504
 
505
        while (p->next)
506
            p = p->next;
507
 
508
        p->next = chain;
509
        chain->previous = p;
510
    }
511
    else
512
        mButtons = chain;
513
 
514
    return chain;
515
}
516
 
14 andreas 517
bool TPage::hasButton(int id)
518
{
519
    DECL_TRACER("TPage::hasButton(int id)");
520
 
521
    BUTTONS_T *bt = mButtons;
522
 
523
    while (bt)
524
    {
525
        if (bt->button && bt->button->getButtonIndex() == id)
526
            return true;
527
 
528
        bt = bt->next;
529
    }
530
 
531
    return false;
532
}
533
 
534
TButton *TPage::getButton(int id)
535
{
536
    DECL_TRACER("TPage::getButton(int id)");
537
 
538
    BUTTONS_T *bt = mButtons;
539
 
540
    while (bt)
541
    {
542
        if (bt->button && bt->button->getButtonIndex() == id)
543
            return bt->button;
544
 
545
        bt = bt->next;
546
    }
547
 
548
    return nullptr;
549
}
550
 
16 andreas 551
std::vector<TButton *> TPage::getButtons(int ap, int ad)
552
{
553
    DECL_TRACER("TSubPage::getButtons(int ap, int ad)");
554
 
555
    std::vector<TButton *> list;
556
    BUTTONS_T *bt = mButtons;
557
 
558
    while (bt)
559
    {
560
        if (bt->button->getAddressPort() == ap && bt->button->getAddressChannel() == ad)
561
            list.push_back(bt->button);
562
 
563
        bt = bt->next;
564
    }
565
 
566
    return list;
567
}
568
 
12 andreas 569
void TPage::drop()
570
{
571
    DECL_TRACER("TPage::drop()");
572
 
573
    PAGECHAIN_T *pc = mSubPages;
14 andreas 574
 
12 andreas 575
    while (pc)
576
    {
13 andreas 577
        pc->subpage->drop();
12 andreas 578
        pc = pc->next;
579
    }
14 andreas 580
 
581
    mZOrder = ZORDER_INVALID;
582
    mVisible = false;
12 andreas 583
}
584
 
31 andreas 585
void TPage::calcPosition(int im_width, int im_height, int *left, int *top, bool scale)
28 andreas 586
{
587
    DECL_TRACER("TPage::calcPosition(int im_width, int im_height, int *left, int *top)");
588
 
589
    int nw = width;
590
    int nh = height;
591
 
31 andreas 592
    if (scale && gPageManager && gPageManager->getScaleFactor() != 1.0)
28 andreas 593
    {
594
        nw = (int)((double)width * gPageManager->getScaleFactor());
595
        nh = (int)((double)height * gPageManager->getScaleFactor());
596
    }
597
 
598
    switch (sr[0].jb)
599
    {
600
        case 0: // absolute position
601
            *left = sr[0].bx;
602
            *top = sr[0].by;
603
 
31 andreas 604
            if (scale && gPageManager && gPageManager->getScaleFactor() != 1.0)
28 andreas 605
            {
606
                *left = (int)((double)sr[0].bx * gPageManager->getScaleFactor());
607
                *left = (int)((double)sr[0].by * gPageManager->getScaleFactor());
608
            }
609
        break;
610
 
611
        case 1: // top, left
612
            *left = 0;
613
            *top = 0;
614
        break;
615
 
616
        case 2: // center, top
617
            *left = (nw - im_width) / 2;
618
            *top = 0;
619
        break;
620
 
621
        case 3: // right, top
622
            *left = nw - im_width;
623
            *top = 0;
624
        break;
625
 
626
        case 4: // left, middle
627
            *left = 0;
628
            *top = (nh - im_height) / 2;
629
        break;
630
 
631
        case 6: // right, middle
632
            *left = nw - im_width;
633
            *top = (nh - im_height) / 2;
634
        break;
635
 
636
        case 7: // left, bottom
637
            *left = 0;
638
            *top = nh - im_height;
639
        break;
640
 
641
        case 8: // center, bottom
642
            *left = (nw - im_width) / 2;
643
            *top = nh - im_height;
644
        break;
645
 
646
        case 9: // right, bottom
647
            *left = nw - im_width;
648
            *top = nh - im_height;
649
        break;
31 andreas 650
 
651
        default:    // center middle
652
            *left = (nw - im_width) / 2;
653
            *top = (nh - im_height) / 2;
28 andreas 654
    }
655
 
656
    if (*left < 0)
657
        *left = 0;
658
 
659
    if (*top < 0)
660
        *top = 0;
661
}
662
 
3 andreas 663
/*
664
 * Sort the button according to their Z-order.
665
 * The button with the highest Z-order will be the last button in the chain.
666
 * The algorithm is a bubble sort algorithm.
667
 */
668
bool TPage::sortButtons()
669
{
670
    DECL_TRACER("TPage::sortButtons()");
671
 
672
    bool turned = true;
673
 
674
    while (turned)
675
    {
676
        BUTTONS_T *button = mButtons;
677
        turned = false;
678
 
679
        while (button)
680
        {
681
            int zo = button->button->getZOrder();
682
 
683
            if (button->previous)
684
            {
685
                if (zo < button->previous->button->getZOrder())
686
                {
687
                    BUTTONS_T *pprev = button->previous->previous;
688
                    BUTTONS_T *prev = button->previous;
689
                    BUTTONS_T *next = button->next;
690
 
691
                    if (pprev)
692
                        pprev->next = button;
693
 
694
                    prev->next = next;
695
                    prev->previous = button;
696
                    button->next = prev;
697
                    button->previous = pprev;
14 andreas 698
 
699
                    if (!pprev)
700
                        mButtons = button;
701
 
3 andreas 702
                    button = next;
14 andreas 703
 
704
                    if (next)
705
                        next->previous = prev;
706
 
3 andreas 707
                    turned = true;
708
                    continue;
709
                }
710
            }
711
 
712
            button = button->next;
713
        }
714
    }
715
 
716
    return true;
717
}