Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 andreas 1
/*
21 andreas 2
 * Copyright (C) 2020, 2021 by Andreas Theofilu <andreas@theosys.at>
3 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
 
5 andreas 19
#include <exception>
20
 
6 andreas 21
#include "tresources.h"
3 andreas 22
#include "treadxml.h"
23
#include "tsubpage.h"
24
#include "tconfig.h"
25
#include "terror.h"
26
 
27
using std::string;
6 andreas 28
using std::vector;
3 andreas 29
using namespace Button;
30
 
31
TSubPage::TSubPage(const string& name)
32
    : mFile(name)
33
{
34
    DECL_TRACER("TSubPage::TSubPage(const string& path)");
14 andreas 35
    TError::clear();
3 andreas 36
    string path = makeFileName(TConfig::getProjectPath(), name);
37
 
38
    if (isValidFile())
39
        mFName = getFileName();
40
    else
41
    {
42
        MSG_ERROR("Either the path \"" << TConfig::getProjectPath() << "\" or the file name \"" << name << "\" is invalid!");
43
        TError::setError();
44
        return;
45
    }
46
 
47
    initialize();
48
}
49
 
50
TSubPage::~TSubPage()
51
{
52
    DECL_TRACER("TSubPage::~TSubPage()");
53
 
5 andreas 54
    if (mSubpage.name.empty())
55
    {
56
        MSG_WARNING("Invalid page found!");
57
        return;
58
    }
59
 
60
    MSG_DEBUG("Destroing subpage " << mSubpage.pageID << ": " << mSubpage.name);
61
 
3 andreas 62
    BUTTONS_T *b = mButtons;
63
    BUTTONS_T *next = nullptr;
64
 
65
    while (b)
66
    {
67
        next = b->next;
5 andreas 68
 
69
        if (b->button)
70
            delete b->button;
71
 
3 andreas 72
        delete b;
73
        b = next;
74
    }
75
 
76
    mButtons = nullptr;
77
}
78
 
79
void TSubPage::initialize()
80
{
81
    DECL_TRACER("TSubPage::initialize()");
82
 
83
    if (mFName.empty())
84
        return;
85
 
86
    TError::clear();
87
    TReadXML reader(mFName);
88
 
89
    if (TError::isError())
90
    {
91
        MSG_DEBUG("Stopped scanning the subpage " << mFile << " due to previous errors!");
92
        return;
93
    }
94
 
95
    reader.findElement("page", "type");
96
 
97
    if (!reader.success())
98
    {
99
        MSG_ERROR("Element \"page\" with attribute \"type\" was not found! Invalid XML file!");
100
        TError::setError();
101
        return;
102
    }
103
 
104
    if (reader.getAttribute("type").compare("subpage") != 0)
105
    {
106
        MSG_ERROR("The type " << reader.getAttribute("type") << " is invalid for a subpage!");
107
        TError::setError();
108
        return;
109
    }
110
 
111
    mSubpage.popupType = reader.getAttribute("popupType");
112
    mxml_node_t *node = reader.getFirstChild();
113
 
114
    while (node)
115
    {
116
        string ename = reader.getElementName(node);
117
 
118
        if (ename.compare("pageID") == 0)
119
            mSubpage.pageID = reader.getIntFromNode(node);
120
        else if (ename.compare("name") == 0)
121
            mSubpage.name = reader.getTextFromNode(node);
7 andreas 122
        else if (ename.compare("left") == 0)
123
            mSubpage.left = reader.getIntFromNode(node);
124
        else if (ename.compare("top") == 0)
125
            mSubpage.top = reader.getIntFromNode(node);
3 andreas 126
        else if (ename.compare("width") == 0)
127
            mSubpage.width = reader.getIntFromNode(node);
128
        else if (ename.compare("height") == 0)
129
            mSubpage.height = reader.getIntFromNode(node);
130
        else if (ename.compare("group") == 0)
131
            mSubpage.group = reader.getTextFromNode(node);
7 andreas 132
        else if (ename.compare("showEffect") == 0)
133
            mSubpage.showEffect = (SHOWEFFECT)reader.getIntFromNode(node);
3 andreas 134
        else if (ename.compare("showTime") == 0)
135
            mSubpage.showTime = reader.getIntFromNode(node);
136
        else if (ename.compare("hideTime") == 0)
137
            mSubpage.hideTime = reader.getIntFromNode(node);
7 andreas 138
        else if (ename.compare("hideEffect") == 0)
139
            mSubpage.hideEffect = (SHOWEFFECT)reader.getIntFromNode(node);
3 andreas 140
        else if (ename.compare("timeout") == 0)
141
            mSubpage.timeout = reader.getIntFromNode(node);
142
        else if (ename.compare("button") == 0)      // Read a button
143
        {
144
            try
145
            {
146
                TButton *button = new TButton();
4 andreas 147
                button->setPalette(mPalette);
7 andreas 148
                button->setFonts(mFonts);
3 andreas 149
                button->initialize(&reader, node);
6 andreas 150
                button->setParentSize(mSubpage.width, mSubpage.height);
7 andreas 151
                button->registerCallback(_displayButton);
152
                button->registerCallbackFT(_setText);
21 andreas 153
                button->regCallPlayVideo(_playVideo);
3 andreas 154
 
155
                if (TError::isError())
156
                {
16 andreas 157
                    MSG_ERROR("Dropping button because of previous errors!");
3 andreas 158
                    delete button;
159
                    return;
160
                }
161
 
5 andreas 162
                button->setHandle(((mSubpage.pageID << 16) & 0xffff0000) | button->getButtonIndex());
14 andreas 163
                button->createButtons();
3 andreas 164
                addButton(button);
165
            }
166
            catch (std::exception& e)
167
            {
168
                MSG_ERROR("Memory exception: " << e.what());
169
                TError::setError();
170
                return;
171
            }
172
        }
6 andreas 173
        else if (ename.compare("sr") == 0)
174
        {
175
            SR_T sr;
176
            sr.number = atoi(reader.getAttributeFromNode(node, "number").c_str());
177
            mxml_node_t *n = reader.getFirstChild(node);
3 andreas 178
 
6 andreas 179
            while (n)
180
            {
181
                string ename = reader.getElementName(n);
182
 
183
                if (ename.compare("bs") == 0)
184
                    sr.bs = reader.getTextFromNode(n);
185
                else if (ename.compare("cb") == 0)
186
                    sr.cb = reader.getTextFromNode(n);
187
                else if (ename.compare("cf") == 0)
188
                    sr.cf = reader.getTextFromNode(n);
189
                else if (ename.compare("ct") == 0)
190
                    sr.ct = reader.getTextFromNode(n);
191
                else if (ename.compare("ec") == 0)
192
                    sr.ec = reader.getTextFromNode(n);
193
                else if (ename.compare("bm") == 0)
194
                    sr.bm = reader.getTextFromNode(n);
10 andreas 195
                else if (ename.compare("ji") == 0)
196
                    sr.ji = reader.getIntFromNode(n);
197
                else if (ename.compare("jb") == 0)
198
                    sr.jb = reader.getIntFromNode(n);
6 andreas 199
                else if (ename.compare("fi") == 0)
200
                    sr.fi = reader.getIntFromNode(n);
10 andreas 201
                else if (ename.compare("ii") == 0)
202
                    sr.ii = reader.getIntFromNode(n);
203
                else if (ename.compare("ix") == 0)
204
                    sr.ix = reader.getIntFromNode(n);
205
                else if (ename.compare("iy") == 0)
206
                    sr.iy = reader.getIntFromNode(n);
207
                else if (ename.compare("oo") == 0)
208
                    sr.oo = reader.getIntFromNode(n);
6 andreas 209
 
210
                n = reader.getNextChild(n);
211
            }
212
 
213
            mSubpage.sr.push_back(sr);
214
        }
215
 
3 andreas 216
        node = reader.getNextChild();
217
    }
8 andreas 218
 
219
    // Here the sort function could be called. But it's not necessary because
220
    // the buttons are stored in ascending Z order. Therefor the following
221
    // method call is commented out.
222
    // sortButtons();
6 andreas 223
}
3 andreas 224
 
6 andreas 225
void TSubPage::show()
226
{
227
    DECL_TRACER("TSubPage::show()");
3 andreas 228
 
6 andreas 229
    if (!_setBackground)
3 andreas 230
    {
6 andreas 231
        MSG_WARNING("No callback \"setBackground\" was set!");
3 andreas 232
        return;
233
    }
234
 
6 andreas 235
    ulong handle = (mSubpage.pageID << 16) & 0xffff0000;
236
    MSG_DEBUG("Processing page " << mSubpage.pageID << ": " << mSubpage.name);
237
    // Draw the background, if any
238
    if (mSubpage.sr.size() > 0 && !mSubpage.sr[0].bm.empty())
3 andreas 239
    {
6 andreas 240
        MSG_DEBUG("Loading image " << mSubpage.sr[0].bm);
241
        sk_sp<SkData> rawImage = readImage(mSubpage.sr[0].bm);
3 andreas 242
 
6 andreas 243
        if (rawImage)
3 andreas 244
        {
6 andreas 245
            SkBitmap bm;
246
            MSG_DEBUG("Decoding image ...");
19 andreas 247
 
248
            if (!DecodeDataToBitmap(rawImage, &bm))
249
                MSG_WARNING("Problem while decoding image " << mSubpage.sr[0].bm);
250
 
6 andreas 251
            SkImageInfo info = bm.info();
252
            size_t rowBytes = info.minRowBytes();
253
            size_t size = info.computeByteSize(rowBytes);
3 andreas 254
 
19 andreas 255
            MSG_DEBUG("Setting background with image of size " << size);
256
            _setBackground(handle, (unsigned char *)bm.getPixels(), size, rowBytes, TColor::getColor(mSubpage.sr[0].cf));
6 andreas 257
        }
258
        else
259
        {
260
            MSG_WARNING("Couldn't read image " << mSubpage.sr[0].bm);
3 andreas 261
 
19 andreas 262
            if (mSubpage.sr.size() > 0)
6 andreas 263
                _setBackground(handle, nullptr, 0, 0, TColor::getColor(mSubpage.sr[0].cf));
3 andreas 264
        }
6 andreas 265
    }
19 andreas 266
    else if (mSubpage.sr.size() > 0)
6 andreas 267
    {
268
        MSG_DEBUG("Calling \"setBackground\" with no image ...");
269
        _setBackground(handle, nullptr, 0, 0, TColor::getColor(mSubpage.sr[0].cf));
270
    }
3 andreas 271
 
6 andreas 272
    // Draw the buttons
273
    BUTTONS_T *button = mButtons;
274
 
275
    while (button)
276
    {
277
        if (button->button)
278
        {
279
            MSG_DEBUG("Drawing button " << button->button->getButtonIndex() << ": " << button->button->getButtonName());
280
            button->button->registerCallback(_displayButton);
7 andreas 281
            button->button->registerCallbackFT(_setText);
21 andreas 282
            button->button->regCallPlayVideo(_playVideo);
7 andreas 283
            button->button->setFonts(mFonts);
284
            button->button->setPalette(mPalette);
6 andreas 285
            button->button->createButtons();
10 andreas 286
 
287
            if (mSubpage.sr.size() > 0)
288
                button->button->setGlobalOpacity(mSubpage.sr[0].oo);
289
 
6 andreas 290
            button->button->show();
291
        }
292
 
293
        button = button->next;
3 andreas 294
    }
11 andreas 295
 
296
    // Mark page as visible
297
    mVisible = true;
3 andreas 298
}
299
 
11 andreas 300
void TSubPage::drop()
301
{
302
    DECL_TRACER("TSubPage::drop()");
303
 
14 andreas 304
    if (mVisible && _callDropSubPage)
11 andreas 305
        _callDropSubPage((mSubpage.pageID << 16) & 0xffff0000);
306
 
15 andreas 307
    // Set all elements of subpage invisible
308
    BUTTONS_T *bt = mButtons;
309
 
310
    while (bt)
311
    {
312
        bt->button->hide();
313
        bt = bt->next;
314
    }
315
 
14 andreas 316
    mZOrder = -1;
11 andreas 317
    mVisible = false;
318
}
319
 
3 andreas 320
BUTTONS_T *TSubPage::addButton(TButton* button)
321
{
322
    DECL_TRACER("*TSubPage::addButton(TButton* button)");
323
 
324
    if (!button)
325
    {
326
        MSG_ERROR("Parameter is NULL!");
327
        TError::setError();
328
        return nullptr;
329
    }
330
 
331
    try
332
    {
333
        BUTTONS_T *chain = new BUTTONS_T;
334
        chain->button = button;
14 andreas 335
        chain->next = nullptr;
336
        chain->previous = nullptr;
337
        BUTTONS_T *bts = mButtons;
3 andreas 338
 
14 andreas 339
        if (bts)
3 andreas 340
        {
14 andreas 341
            BUTTONS_T *p = bts;
3 andreas 342
 
343
            while (p->next)
344
                p = p->next;
345
 
346
            p->next = chain;
347
            chain->previous = p;
348
        }
349
        else
350
            mButtons = chain;
351
 
352
        return chain;
353
    }
354
    catch (std::exception& e)
355
    {
356
        MSG_ERROR("Memory error: " << e.what());
357
        TError::setError();
358
    }
359
 
360
    return nullptr;
361
}
362
 
14 andreas 363
bool TSubPage::hasButton(int id)
364
{
365
    DECL_TRACER("TSubPage::hasButton(int id)");
366
 
367
    BUTTONS_T *bt = mButtons;
368
 
369
    while (bt)
370
    {
371
        if (bt->button && bt->button->getButtonIndex() == id)
372
            return true;
373
 
374
        bt = bt->next;
375
    }
376
 
377
    return false;
378
}
379
 
380
TButton *TSubPage::getButton(int id)
381
{
382
    DECL_TRACER("TSubPage::getButton(int id)");
383
 
384
    BUTTONS_T *bt = mButtons;
385
 
386
    while (bt)
387
    {
388
        if (bt->button && bt->button->getButtonIndex() == id)
389
            return bt->button;
390
 
391
        bt = bt->next;
392
    }
393
 
394
    return nullptr;
395
}
396
 
16 andreas 397
vector<TButton *> TSubPage::getButtons(int ap, int ad)
398
{
399
    DECL_TRACER("TSubPage::getButtons(int ap, int ad)");
400
 
401
    vector<TButton *> list;
402
    BUTTONS_T *bt = mButtons;
403
 
404
    while (bt)
405
    {
406
        if (bt->button->getAddressPort() == ap && bt->button->getAddressChannel() == ad)
407
            list.push_back(bt->button);
408
 
409
        bt = bt->next;
410
    }
411
 
412
    return list;
413
}
414
 
3 andreas 415
/*
416
 * Sort the button according to their Z-order.
417
 * The button with the highest Z-order will be the last button in the chain.
418
 * The algorithm is a bubble sort algorithm.
419
 */
420
bool TSubPage::sortButtons()
421
{
422
    DECL_TRACER("TSubPage::sortButtons()");
423
 
424
    bool turned = true;
425
 
426
    while (turned)
427
    {
428
        BUTTONS_T *button = mButtons;
429
        turned = false;
430
 
431
        while (button)
432
        {
433
            int zo = button->button->getZOrder();
434
 
435
            if (button->previous)
436
            {
437
                if (zo < button->previous->button->getZOrder())
438
                {
439
                    BUTTONS_T *pprev = button->previous->previous;
440
                    BUTTONS_T *prev = button->previous;
441
                    BUTTONS_T *next = button->next;
442
 
443
                    if (pprev)
444
                        pprev->next = button;
445
 
446
                    prev->next = next;
447
                    prev->previous = button;
448
                    button->next = prev;
449
                    button->previous = pprev;
450
 
451
                    if (!pprev)
452
                        mButtons = button;
453
 
454
                    button = next;
455
 
456
                    if (next)
457
                        next->previous = prev;
458
 
459
                    turned = true;
460
                    continue;
461
                }
462
            }
463
 
464
            button = button->next;
465
        }
466
    }
467
 
468
    return true;
469
}
11 andreas 470
 
471
RECT_T TSubPage::getRegion()
472
{
473
    DECL_TRACER("TSubPage::getRegion()");
474
    return {mSubpage.left, mSubpage.top, mSubpage.width, mSubpage.height};
475
}
476
 
15 andreas 477
/**
478
 * This method is called indirectly from the GUI after a mouse click. If This
479
 * subpage matches the clicked coordinates, than the elements are tested. If
480
 * an element is found that matches the coordinates it gets the click. It
481
 * depends on the kind of element what happens.
482
 */
11 andreas 483
void TSubPage::doClick(int x, int y, bool pressed)
484
{
485
    DECL_TRACER("TSubPage::doClick(int x, int y)");
486
 
487
    MSG_DEBUG("X=" << x << ", Y=" << y);
488
    BUTTONS_T *button = mButtons;
489
    // Find last button
490
    while (button->next)
491
        button = button->next;
492
 
493
    // Scan in reverse order
494
    while (button)
495
    {
496
        TButton *but = button->button;
497
        MSG_DEBUG("Button " << but->getButtonIndex() << ": lx=" << but->getLeftPosition() << ", ly=" << but->getTopPosition() << ", rx=" << (but->getLeftPosition() + but->getWidth()) << ", ry=" << (but->getTopPosition() + but->getHeight()));
498
 
499
        if (x >= but->getLeftPosition() && x <= (but->getLeftPosition() + but->getWidth()) &&
500
            y >= but->getTopPosition() && y <= (but->getTopPosition() + but->getHeight()))
501
        {
502
            MSG_DEBUG("Clicking button " << but->getButtonIndex() << ": " << but->getButtonName() << " to state " << (pressed ? "PRESS" : "RELEASE"));
15 andreas 503
            int btX = x - but->getLeftPosition();
504
            int btY = y - but->getTopPosition();
505
 
506
            if (but->doClick(btX, btY, pressed))
507
                break;
11 andreas 508
        }
509
 
510
        button = button->previous;
511
    }
512
}