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
 
21 andreas 19
/** @file tqtmain.cpp
20
 * @brief Implements the surface of the application.
21
 *
22
 * This file implements the callback functions of the suface. While the most
23
 * classes are drawing the elements, the methods here take the ready elements
24
 * and display them. This file makes the surface completely independent of
25
 * the rest of the application which makes it easy to change the surface by
26
 * any other technology.
27
 */
2 andreas 28
#include <QApplication>
23 andreas 29
#include <QGuiApplication>
14 andreas 30
#include <QByteArray>
2 andreas 31
#include <QCommandLineParser>
32
#include <QCommandLineOption>
9 andreas 33
#include <QLabel>
2 andreas 34
#include <QtWidgets>
10 andreas 35
#include <QMouseEvent>
15 andreas 36
#include <QMoveEvent>
5 andreas 37
#include <QPalette>
9 andreas 38
#include <QPixmap>
7 andreas 39
#include <QFont>
40
#include <QFontDatabase>
21 andreas 41
#include <QtMultimediaWidgets/QVideoWidget>
42
#include <QtMultimedia/QMediaPlayer>
43
#include <QtMultimedia/QMediaPlaylist>
24 andreas 44
#include <QLayout>
21 andreas 45
#include <QUrl>
13 andreas 46
#include <QThread>
2 andreas 47
 
5 andreas 48
#include <functional>
14 andreas 49
#include <mutex>
23 andreas 50
#ifdef __ANDROID__
51
#include <android/log.h>
52
#endif
4 andreas 53
#include "tpagemanager.h"
2 andreas 54
#include "tqtmain.h"
55
#include "tconfig.h"
56
#include "tqtsettings.h"
5 andreas 57
#include "tcolor.h"
2 andreas 58
 
21 andreas 59
/**
60
 * @def __ANDROID__
61
 * Here we've to define some extra place holders because on Android only 10
62
 * place holders are defined by default. But we've a callback functions which
63
 * need 13 place holders. The defination is taken from the original defination
64
 * of place holders and expanded.
65
 */
66
#ifdef __ANDROID__
67
#if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
68
_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _11;
69
_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _12;
70
_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _13;
22 andreas 71
//_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _14;
72
//_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _15;
73
//_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _16;
74
//_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _17;
75
//_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _18;
76
//_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _19;
77
//_LIBCPP_FUNC_VIS extern const _std::placeholders::_ph<10> _20;
21 andreas 78
#else
79
/* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<11>   _11{};
80
/* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<12>   _12{};
81
/* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<13>   _13{};
22 andreas 82
///* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<14>   _14{};
83
///* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<15>   _15{};
84
///* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<16>   _16{};
85
///* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<17>   _17{};
86
///* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<18>   _18{};
87
///* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<19>   _19{};
88
///* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<20>   _20{};
21 andreas 89
#endif // defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
90
#endif
3 andreas 91
 
21 andreas 92
static TPageManager *pageManager = nullptr;     //!< The pointer to the global defined main class.
93
std::mutex draw_mutex;                          //!< We're using threads and need to block execution sometimes
94
 
5 andreas 95
using std::bind;
21 andreas 96
using std::string;
5 andreas 97
 
21 andreas 98
/**
99
 * @brief qtmain is used here as the entry point for the surface.
100
 *
101
 * The main entry function parses the command line parameters, if there were
102
 * any and sets the basic attributes. It creates the main window and starts the
103
 * application.
104
 *
105
 * @param argc      The number of command line arguments
106
 * @param argv      A pointer to a 2 dimensional array containing the command
107
 *                  line parameters.
108
 * @param pmanager  A pointer to the page manager class which is the main class
109
 *                  managing everything.
110
 *
111
 * @return If no errors occured it returns 0.
112
 */
3 andreas 113
int qtmain(int argc, char **argv, TPageManager *pmanager)
2 andreas 114
{
31 andreas 115
    DECL_TRACER("qtmain(int argc, char **argv, TPageManager *pmanager)");
2 andreas 116
 
3 andreas 117
    pageManager = pmanager;
118
 
21 andreas 119
//    Q_INIT_RESOURCE(tpanel);
2 andreas 120
#ifdef Q_OS_ANDROID
5 andreas 121
    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
2 andreas 122
#endif
123
 
5 andreas 124
    QApplication app(argc, argv);
24 andreas 125
    // Calculate the scale factor
126
    if (TConfig::getScale())
127
    {
128
        QList<QScreen *> screens = QGuiApplication::screens();
129
        QRect screenGeometry = screens.at(0)->availableGeometry();
130
        double width = screenGeometry.width();
131
        double height = screenGeometry.height();
132
        int minWidth = pmanager->getSettings()->getWith();
133
        int minHeight = pmanager->getSettings()->getHeight();
31 andreas 134
        MSG_INFO("Dimension of AMX screen:" << minWidth << " x " << minHeight);
135
        MSG_INFO("Screen size: " << screenGeometry.width() << " x " << screenGeometry.height());
23 andreas 136
 
24 andreas 137
        double scaleW = width / minWidth;
138
        double scaleH = height / minHeight;
139
        double scale = std::min(scaleW, scaleH);
26 andreas 140
 
141
        if (scale != 0.0)
142
        {
143
            pmanager->setScaleFactor(scale);
31 andreas 144
            MSG_INFO("Scale factor: " << scale);
26 andreas 145
        }
31 andreas 146
 
147
        if (scaleW != 0.0)
148
            pmanager->setScaleFactorWidth(scaleW);
149
 
150
        if (scaleH != 0.0)
151
            pmanager->setScaleFactorHeight(scaleH);
24 andreas 152
    }
23 andreas 153
 
24 andreas 154
    // Initialize the application
5 andreas 155
    QCoreApplication::setOrganizationName(TConfig::getProgName().c_str());
156
    QCoreApplication::setApplicationName("AMX panel simulator");
24 andreas 157
    QCoreApplication::setApplicationVersion(VERSION_STRING());
5 andreas 158
    QCommandLineParser parser;
159
    parser.setApplicationDescription(QCoreApplication::applicationName());
160
    parser.addHelpOption();
161
    parser.addVersionOption();
162
    parser.process(app);
2 andreas 163
 
5 andreas 164
    MainWindow mainWin;
22 andreas 165
    mainWin.setConfigFile(TConfig::getConfigPath() + "/" + TConfig::getConfigFileName());
28 andreas 166
    mainWin.setStyleSheet("QMainWindow {background: 'black';}");
31 andreas 167
//    mainWin.showFullScreen();   // Looses menu and control buttons on Android!
5 andreas 168
    mainWin.show();
169
    return app.exec();
2 andreas 170
}
171
 
21 andreas 172
/**
173
 * @brief MainWindow::MainWindow constructor
174
 *
175
 * This method is the constructor for this class. It registers the callback
176
 * functions to the class TPageManager and starts the main run loop.
177
 */
2 andreas 178
MainWindow::MainWindow()
179
{
5 andreas 180
    DECL_TRACER("MainWindow::MainWindow()");
2 andreas 181
 
14 andreas 182
    pageManager->registerCallbackDB(bind(&MainWindow::_displayButton, this,
5 andreas 183
                                       std::placeholders::_1,
184
                                       std::placeholders::_2,
185
                                       std::placeholders::_3,
186
                                       std::placeholders::_4,
187
                                       std::placeholders::_5,
188
                                       std::placeholders::_6,
189
                                       std::placeholders::_7,
190
                                       std::placeholders::_8));
191
 
14 andreas 192
    pageManager->registerCallbackSP(bind(&MainWindow::_setPage, this,
5 andreas 193
                                         std::placeholders::_1,
194
                                         std::placeholders::_2,
195
                                         std::placeholders::_3));
196
 
14 andreas 197
    pageManager->registerCallbackSSP(bind(&MainWindow::_setSubPage, this,
5 andreas 198
                                          std::placeholders::_1,
199
                                          std::placeholders::_2,
200
                                          std::placeholders::_3,
201
                                          std::placeholders::_4,
202
                                          std::placeholders::_5));
203
 
14 andreas 204
    pageManager->registerCallbackSB(bind(&MainWindow::_setBackground, this,
5 andreas 205
                                         std::placeholders::_1,
206
                                         std::placeholders::_2,
207
                                         std::placeholders::_3,
208
                                         std::placeholders::_4,
209
                                         std::placeholders::_5));
210
 
14 andreas 211
    pageManager->registerCallbackFT(bind(&MainWindow::_setText, this,
7 andreas 212
                                         std::placeholders::_1,
213
                                         std::placeholders::_2,
214
                                         std::placeholders::_3,
215
                                         std::placeholders::_4,
216
                                         std::placeholders::_5,
217
                                         std::placeholders::_6,
218
                                         std::placeholders::_7,
219
                                         std::placeholders::_8,
220
                                         std::placeholders::_9,
221
                                         std::placeholders::_10,
21 andreas 222
#ifdef __ANDROID__
223
                                         _11,
224
                                         _12,
225
                                         _13));
226
#else
7 andreas 227
                                         std::placeholders::_11,
228
                                         std::placeholders::_12,
229
                                         std::placeholders::_13));
21 andreas 230
#endif
7 andreas 231
 
14 andreas 232
    pageManager->regCallDropPage(bind(&MainWindow::_dropPage, this, std::placeholders::_1));
233
    pageManager->regCallDropSubPage(bind(&MainWindow::_dropSubPage, this, std::placeholders::_1));
21 andreas 234
    pageManager->regCallPlayVideo(bind(&MainWindow::_playVideo, this,
235
                                       std::placeholders::_1,
236
                                       std::placeholders::_2,
237
                                       std::placeholders::_3,
238
                                       std::placeholders::_4,
239
                                       std::placeholders::_5,
240
                                       std::placeholders::_6,
241
                                       std::placeholders::_7,
242
                                       std::placeholders::_8,
243
                                       std::placeholders::_9));
11 andreas 244
 
26 andreas 245
    pageManager->deployCallbacks();
5 andreas 246
    createActions();
247
 
2 andreas 248
#ifndef QT_NO_SESSIONMANAGER
5 andreas 249
    QGuiApplication::setFallbackSessionManagementEnabled(false);
250
    connect(qApp, &QGuiApplication::commitDataRequest,
251
            this, &MainWindow::writeSettings);
2 andreas 252
#endif
14 andreas 253
 
254
    qRegisterMetaType<size_t>("size_t");
255
    qRegisterMetaType<QByteArray>("QByteArray");
256
 
15 andreas 257
    try
258
    {
259
        connect(this, &MainWindow::sigDisplayButton, this, &MainWindow::displayButton);
24 andreas 260
/*        connect(this, &MainWindow::sigDisplayButton, // same sender and signal
15 andreas 261
                this,                 // context object to break this connection
262
                [this]() {            // debug output
263
                    MSG_DEBUG("Direct? " << ((QThread::currentThread() == this->thread())?"YES":"NO"));
264
                },
24 andreas 265
                Qt::DirectConnection); */
15 andreas 266
        connect(this, &MainWindow::sigSetPage, this, &MainWindow::setPage);
267
        connect(this, &MainWindow::sigSetSubPage, this, &MainWindow::setSubPage);
268
        connect(this, &MainWindow::sigSetBackground, this, &MainWindow::setBackground);
269
        connect(this, &MainWindow::sigSetText, this, &MainWindow::setText);
270
        connect(this, &MainWindow::sigDropPage, this, &MainWindow::dropPage);
271
        connect(this, &MainWindow::sigDropSubPage, this, &MainWindow::dropSubPage);
21 andreas 272
        connect(this, &MainWindow::sigPlayVideo, this, &MainWindow::playVideo);
31 andreas 273
        connect(qApp, &QGuiApplication::applicationStateChanged, this, &MainWindow::appStateChanged);
15 andreas 274
    }
275
    catch (std::exception& e)
276
    {
277
        MSG_ERROR("Connection error: " << e.what());
278
    }
279
 
5 andreas 280
    setUnifiedTitleAndToolBarOnMac(true);
281
    pageManager->run();
2 andreas 282
}
283
 
21 andreas 284
/**
285
 * @brief MainWindow::closeEvent called when the application receives an exit event.
286
 *
287
 * If the user clicks on the exit icon or on the menu point _Exit_ this method
288
 * is called. It makes sure everything is written to the configuration file
289
 * and accepts the evernt.
290
 *
291
 * @param event The exit event
292
 */
2 andreas 293
void MainWindow::closeEvent(QCloseEvent *event)
294
{
5 andreas 295
    DECL_TRACER("MainWindow::closeEvent(QCloseEvent *event)");
24 andreas 296
#ifdef __ANDROID__
23 andreas 297
    __android_log_print(ANDROID_LOG_DEBUG,"tpanel","Close event; settingsChanged=%s", (settingsChanged ? "true":"false"));
24 andreas 298
#endif
5 andreas 299
    if (settingsChanged)
300
    {
301
        writeSettings();
302
        event->accept();
303
    }
304
    else
305
    {
21 andreas 306
        prg_stopped = true;
307
        MSG_TRACE("Program will stop!");
5 andreas 308
        event->accept();
309
    }
2 andreas 310
}
311
 
21 andreas 312
/**
313
 * @brief MainWindow::eventFilter filters the QEvent::MouseMove event
314
 * @param obj   The object where the event occured.
315
 * @param event The event.
316
 * @return `true` when the event should be ignored.
317
 */
15 andreas 318
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
319
{
320
//    DECL_TRACER("MainWindow::eventFilter(QObject *obj, QEvent *event)");
321
 
322
    if (event->type() == QEvent::MouseMove)
323
        return true;    // Filter event out, i.e. stop it being handled further.
324
 
325
    return QMainWindow::eventFilter(obj, event);
326
}
327
 
21 andreas 328
/**
329
 * @brief MainWindow::createActions creates the configuration dialog window.
330
 */
2 andreas 331
void MainWindow::createActions()
332
{
5 andreas 333
    DECL_TRACER("MainWindow::createActions()");
2 andreas 334
 
31 andreas 335
    // Add a toolbar (on the right side)
336
    QToolBar *toolbar = new QToolBar(this);
337
    toolbar->setAllowedAreas(Qt::RightToolBarArea);
338
 
339
/*    QActionGroup actionGroup(this);
340
    QToolButton arrowUp(this);
341
    arrowUp.setArrowType(Qt::UpArrow);
342
    actionGroup.addAction(arrowUp.defaultAction());
343
 
344
    QToolButton arrowLeft(this);
345
    arrowLeft.setArrowType(Qt::LeftArrow);
346
    actionGroup.addAction(arrowLeft.defaultAction());
347
 
348
    QToolButton arrowRight(this);
349
    arrowRight.setArrowType(Qt::RightArrow);
350
    actionGroup.addAction(arrowRight.defaultAction());
351
 
352
    QToolButton arrowDown(this);
353
    arrowDown.setArrowType(Qt::DownArrow);
354
    actionGroup.addAction(arrowDown.defaultAction());
355
 
356
 
357
    toolbar->addAction(QIcon(":/images/ok.png"), "Ok");
358
    toolbar->addSeparator();
359
*/
360
//    toolbar->addAction(QIcon(":/images/settings.png"), "Settings ...");
361
 
4 andreas 362
    // Add a menu
31 andreas 363
//    QMenu *editMenu = menuBar()->addMenu(tr("&Edit"));
2 andreas 364
 
31 andreas 365
//    const QIcon settingsIcon = QIcon::fromTheme("document-open", QIcon(":/images/settings-configure.png"));
366
    const QIcon settingsIcon = QIcon::fromTheme("document-open", QIcon(":/images/settings.png"));
5 andreas 367
    QAction *settingsAct = new QAction(settingsIcon, tr("&Settings..."), this);
368
    settingsAct->setStatusTip(tr("Change the settings"));
369
    connect(settingsAct, &QAction::triggered, this, &MainWindow::settings);
31 andreas 370
    toolbar->addAction(settingsAct);
371
//    editMenu->addAction(settingsAct);
2 andreas 372
 
5 andreas 373
    const QIcon aboutIcon = QIcon::fromTheme("document-open", QIcon(":/images/help-about.png"));
374
    QAction *aboutAct = new QAction(aboutIcon, tr("&About..."), this);
375
    aboutAct->setShortcuts(QKeySequence::Open);
376
    aboutAct->setStatusTip(tr("About this program"));
377
    connect(aboutAct, &QAction::triggered, this, &MainWindow::about);
31 andreas 378
    toolbar->addAction(aboutAct);
379
//    editMenu->addAction(aboutAct);
2 andreas 380
 
31 andreas 381
//    editMenu->addSeparator();
2 andreas 382
 
5 andreas 383
    const QIcon exitIcon = QIcon::fromTheme("application-exit");
31 andreas 384
//    QAction *exitAct = editMenu->addAction(exitIcon, tr("E&xit"), this, &QWidget::close);
385
    QAction *exitAct = toolbar->addAction(exitIcon, tr("E&xit"), this, &QWidget::close);
5 andreas 386
    exitAct->setShortcuts(QKeySequence::Quit);
387
    exitAct->setStatusTip(tr("Exit the application"));
31 andreas 388
 
389
    addToolBar(Qt::RightToolBarArea, toolbar);
2 andreas 390
}
391
 
21 andreas 392
/**
393
 * @brief MainWindow::mousePressEvent catches the event Qt::LeftButton.
394
 *
395
 * If the user presses the left mouse button somewhere in the main window, this
396
 * method is triggered. It retrieves the position of the mouse pointer and
397
 * sends it to the page manager TPageManager.
398
 *
399
 * @param event The event
400
 */
10 andreas 401
void MainWindow::mousePressEvent(QMouseEvent* event)
402
{
403
    if(event->button() == Qt::LeftButton)
404
        pageManager->mouseEvent(event->x(), event->y(), true);
405
}
406
 
21 andreas 407
/**
408
 * @brief MainWindow::mouseReleaseEvent catches the event Qt::LeftButton.
409
 *
410
 * If the user releases the left mouse button somewhere in the main window, this
411
 * method is triggered. It retrieves the position of the mouse pointer and
412
 * sends it to the page manager TPageManager.
413
 *
414
 * @param event The event
415
 */
10 andreas 416
void MainWindow::mouseReleaseEvent(QMouseEvent* event)
417
{
418
    if(event->button() == Qt::LeftButton)
419
        pageManager->mouseEvent(event->x(), event->y(), false);
420
}
421
 
21 andreas 422
/**
423
 * @brief MainWindow::settings initiates the configuration dialog.
424
 */
2 andreas 425
void MainWindow::settings()
426
{
5 andreas 427
    DECL_TRACER("MainWindow::settings()");
2 andreas 428
 
5 andreas 429
    TQtSettings *dlg_settings = new TQtSettings(this);
23 andreas 430
    int ret = dlg_settings->exec();
431
 
432
    if (ret && dlg_settings->hasChanged())
433
        writeSettings();
434
    else if (!ret && dlg_settings->hasChanged())
435
    {
436
        TConfig cf(TConfig::getConfigPath() + "/" + TConfig::getConfigFileName());
437
    }
2 andreas 438
}
439
 
21 andreas 440
/**
441
 * @brief MainWindow::writeSettings Writes the settings into the configuration file.
442
 */
2 andreas 443
void MainWindow::writeSettings()
444
{
5 andreas 445
    DECL_TRACER("MainWindow::writeSettings()");
23 andreas 446
 
447
    TConfig::saveSettings();
448
#ifdef __ANDROID__
449
    __android_log_print(ANDROID_LOG_DEBUG,"tpanel","DEBUG: Wrote settings.");
450
#endif
2 andreas 451
}
452
 
21 andreas 453
/**
454
 * @brief MainWindow::about displays the _about_ dialog.
455
 */
2 andreas 456
void MainWindow::about()
457
{
5 andreas 458
    DECL_TRACER("MainWindow::about()");
2 andreas 459
 
5 andreas 460
    QMessageBox::about(this, tr(std::string("About ").append(TConfig::getProgName()).c_str()),
461
                       tr("Simulation of an AMX G4 panel\n"
22 andreas 462
                          "(C) Copyright 2020, 2021 by Andreas Theofilu <andreas@theosys.at>\n"
5 andreas 463
                          "This program is under the terms of GPL version 3"));
2 andreas 464
}
465
 
14 andreas 466
/******************* Signal handling *************************/
467
 
31 andreas 468
void MainWindow::appStateChanged(Qt::ApplicationState state)
469
{
470
    DECL_TRACER("MainWindow::applicationStateChanged(Qt::ApplicationState state)");
471
 
472
    switch (state)
473
    {
474
        case Qt::ApplicationSuspended:
475
            MSG_DEBUG("Switched to mode SUSPEND");
476
            mHasFocus = false;
477
        break;
478
 
479
        case Qt::ApplicationInactive:
480
            MSG_DEBUG("Switched to mode INACTIVE");
481
            mHasFocus = false;
482
        break;
483
 
484
        case Qt::ApplicationHidden:
485
            MSG_DEBUG("Switched to mode HIDDEN");
486
            mHasFocus = false;
487
        break;
488
 
489
        case Qt::ApplicationActive:
490
            MSG_DEBUG("Switched to mode ACTIVE");
491
            mHasFocus = true;
492
            playShowList();
493
        break;
494
    }
495
}
496
 
14 andreas 497
void MainWindow::_displayButton(ulong handle, ulong parent, unsigned char* buffer, int width, int height, int pixline, int left, int top)
4 andreas 498
{
14 andreas 499
    DECL_TRACER("MainWindow::_displayButton(ulong handle, ulong parent, unsigned char* buffer, int width, int height, int pixline, int left, int top)");
500
 
21 andreas 501
    if (prg_stopped)
502
        return;
503
 
14 andreas 504
    QByteArray buf;
505
 
506
    if (buffer && pixline > 0)
507
    {
508
        size_t size = width * height * (pixline / width);
15 andreas 509
        MSG_DEBUG("Buffer size=" << size << ", width=" << width << ", height=" << height << ", left=" << left << ", top=" << top);
14 andreas 510
        buf.insert(0, (const char *)buffer, size);
511
    }
512
 
15 andreas 513
    try
514
    {
515
        emit sigDisplayButton(handle, parent, buf, width, height, pixline, left, top);
516
    }
517
    catch (std::exception& e)
518
    {
519
        MSG_ERROR("Error triggering function \"displayButton()\": " << e.what());
520
    }
14 andreas 521
}
522
 
523
void MainWindow::_setPage(ulong handle, int width, int height)
524
{
525
    DECL_TRACER("MainWindow::_setPage(ulong handle, int width, int height)");
526
 
21 andreas 527
    if (prg_stopped)
528
        return;
529
 
14 andreas 530
    emit sigSetPage(handle, width, height);
531
}
532
 
533
void MainWindow::_setSubPage(ulong handle, int left, int top, int width, int height)
534
{
535
    DECL_TRACER("MainWindow::_setSubPage(ulong handle, int left, int top, int width, int height)");
536
 
21 andreas 537
    if (prg_stopped)
538
        return;
539
 
14 andreas 540
    emit sigSetSubPage(handle, left, top, width, height);
541
}
542
 
543
void MainWindow::_setBackground(ulong handle, unsigned char *image, size_t size, size_t rowBytes, ulong color)
544
{
545
    DECL_TRACER("MainWindow::_setBackground(ulong handle, unsigned char *image, size_t size, size_t rowBytes, ulong color)");
546
 
21 andreas 547
    if (prg_stopped)
548
        return;
549
 
14 andreas 550
    QByteArray buf;
551
 
552
    if (image && size > 0)
553
        buf.insert(0, (const char *)image, size);
554
 
555
    emit sigSetBackground(handle, buf, rowBytes, color);
556
}
557
 
558
void MainWindow::_setText(ulong handle, const std::string& text, const std::string& font, const std::string& family, int size, int x, int y, ulong color, ulong effectColor, FONT_STYLE style, Button::TEXT_ORIENTATION ori, Button::TEXT_EFFECT effect, bool ww)
559
{
560
    DECL_TRACER("MainWindow::_setText(ulong handle, const std::string& text, const std::string& font, const std::string& family, int size, int x, int y, ulong color, ulong effectColor, FONT_STYLE style, Button::TEXT_ORIENTATION ori, Button::TEXT_EFFECT effect, bool ww)");
561
 
21 andreas 562
    if (prg_stopped)
563
        return;
564
 
14 andreas 565
    emit sigSetText(handle, text, font, family, size, x, y, color, effectColor, style, ori, effect, ww);
566
}
567
 
568
void MainWindow::_dropPage(ulong handle)
569
{
570
    DECL_TRACER("MainWindow::_dropPage(ulong handle)");
571
 
572
    emit sigDropPage(handle);
573
}
574
 
575
void MainWindow::_dropSubPage(ulong handle)
576
{
577
    DECL_TRACER("MainWindow::_dropSubPage(ulong handle)");
578
 
579
    emit sigDropSubPage(handle);
580
}
581
 
21 andreas 582
void MainWindow::_playVideo(ulong handle, ulong parent, int left, int top, int width, int height, const string& url, const string& user, const string& pw)
583
{
584
    DECL_TRACER("MainWindow::_playVideo(ulong handle, const string& url)");
585
 
586
    if (prg_stopped)
587
        return;
588
 
589
    emit sigPlayVideo(handle, parent, left, top, width, height, url, user, pw);
590
}
591
 
14 andreas 592
/******************* Draw elements *************************/
593
 
594
void MainWindow::displayButton(ulong handle, ulong parent, QByteArray buffer, int width, int height, int pixline, int left, int top)
595
{
596
    draw_mutex.lock();
5 andreas 597
    DECL_TRACER("MainWindow::displayButton(ulong handle, unsigned char* buffer, size_t size, int width, int height, int pixline, int left, int top)");
4 andreas 598
 
5 andreas 599
    OBJECT_t *obj = findObject(handle);
6 andreas 600
    OBJECT_t *par = findObject(parent);
601
    MSG_DEBUG("Processing button " << handleToString(handle) << " from parent " << handleToString(parent));
5 andreas 602
 
6 andreas 603
    if (!par)
604
    {
21 andreas 605
        MSG_WARNING("Button " << handle << " has no parent (" << parent << ")! Ignoring it.");
14 andreas 606
        draw_mutex.unlock();
6 andreas 607
        return;
608
    }
609
 
5 andreas 610
    if (!obj)
611
    {
6 andreas 612
        MSG_DEBUG("Adding new object ...");
5 andreas 613
        obj = addObject();
614
 
615
        if (!obj)
616
        {
617
            MSG_ERROR("Error creating an object!");
618
            TError::setError();
14 andreas 619
            draw_mutex.unlock();
5 andreas 620
            return;
621
        }
622
 
623
        obj->type = OBJ_BUTTON;
624
        obj->handle = handle;
625
        obj->width = width;
626
        obj->height = height;
627
        obj->left = left;
628
        obj->top = top;
6 andreas 629
        obj->object.label = new QLabel("", par->object.widget);
15 andreas 630
        obj->object.label->installEventFilter(this);
6 andreas 631
    }
14 andreas 632
    else
633
        MSG_DEBUG("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " found!");
5 andreas 634
 
6 andreas 635
    obj->object.label->setFixedSize(width, height);
636
    obj->object.label->move(left, top);
31 andreas 637
//    obj->object.label->setScaledContents(true);
10 andreas 638
    obj->object.label->setAttribute(Qt::WA_TransparentForMouseEvents);
6 andreas 639
    MSG_DEBUG("Geometry: l:" << left << ", t:" << top << ", w:" << width << ", h:" << height);
640
 
14 andreas 641
    if (buffer.size() > 0 && pixline > 0)
6 andreas 642
    {
14 andreas 643
        MSG_DEBUG("Adding image for " << handleToString(handle) << " ...");
644
        QImage img((unsigned char *)buffer.data(), width, height, pixline, QImage::Format_ARGB32);
6 andreas 645
        QPixmap pixmap(width, height);
646
        pixmap.convertFromImage(img);
647
        obj->object.label->setPixmap(pixmap);
5 andreas 648
    }
6 andreas 649
    else
650
    {
651
        MSG_DEBUG("No image found.");
652
    }
5 andreas 653
 
31 andreas 654
    if (mHasFocus)
655
        obj->object.label->show();
656
    else
657
    {
658
        if (par->type == OBJ_PAGE || par->type == OBJ_SUBPAGE)
659
            mToShow.insert(std::pair<ulong, QWidget *>(par->handle, par->object.widget));
660
    }
661
 
14 andreas 662
    draw_mutex.unlock();
4 andreas 663
}
664
 
5 andreas 665
void MainWindow::setPage(ulong handle, int width, int height)
666
{
14 andreas 667
    draw_mutex.lock();
5 andreas 668
    DECL_TRACER("MainWindow::setPage(ulong handle, int width, int height)");
4 andreas 669
 
6 andreas 670
    QSize qs = menuBar()->sizeHint();
671
    this->setMinimumSize(width, height + qs.height());
5 andreas 672
    OBJECT_t *obj = findObject(handle);
673
 
674
    if (!obj)
675
    {
676
        obj = addObject();
677
 
678
        if (!obj)
679
        {
680
            MSG_ERROR("Error crating an object for handle " << handleToString(handle));
681
            TError::setError();
14 andreas 682
            draw_mutex.unlock();
5 andreas 683
            return;
684
        }
685
 
686
        obj->handle = handle;
687
        obj->height = height;
688
        obj->width = width;
689
        obj->type = OBJ_PAGE;
690
    }
6 andreas 691
 
692
    bool newBackground = false;
693
 
694
    if (!mBackground)
695
    {
696
        mBackground = new QWidget();
697
        mBackground->setAutoFillBackground(true);
31 andreas 698
        mBackground->setBackgroundRole(QPalette::Window);
6 andreas 699
        mBackground->setFixedSize(obj->width, obj->height);
31 andreas 700
#ifndef __ANDROID__
10 andreas 701
        QRect rectBack = mBackground->geometry();
702
        QRect rectMain = this->geometry();
28 andreas 703
        int avHeight = rectMain.height() - rectBack.height();
704
        MSG_DEBUG("avHeight=" << avHeight);
705
        pageManager->setFirstTopPixel(avHeight);
31 andreas 706
#endif
6 andreas 707
        newBackground = true;
708
    }
709
 
710
    // By default set a transparent background
711
    QPixmap pix(width, height);
712
    pix.fill(QColor::fromRgba(qRgba(0,0,0,0xff)));
713
    QPalette palette;
714
    palette.setBrush(QPalette::Window, pix);
715
    mBackground->setPalette(palette);
716
 
717
    if (newBackground)
718
        this->setCentralWidget(mBackground);
719
 
31 andreas 720
    if (mHasFocus)
721
        mBackground->show();
722
    else
723
        mToShow.insert(std::pair<ulong, QWidget *>(handle, mBackground));
724
 
14 andreas 725
    draw_mutex.unlock();
5 andreas 726
}
727
 
728
void MainWindow::setSubPage(ulong handle, int left, int top, int width, int height)
729
{
14 andreas 730
    draw_mutex.lock();
5 andreas 731
    DECL_TRACER("MainWindow::setSubPage(ulong handle, int left, int top, int width, int height)");
732
    OBJECT_t *obj = addObject();
733
 
734
    if (!obj)
735
    {
736
        MSG_ERROR("Error adding an object!");
737
        TError::setError();
14 andreas 738
        draw_mutex.unlock();
5 andreas 739
        return;
740
    }
741
 
742
    obj->type = OBJ_SUBPAGE;
743
    obj->handle = handle;
13 andreas 744
    obj->object.widget = new QWidget(centralWidget());
6 andreas 745
    obj->object.widget->setAutoFillBackground(true);
28 andreas 746
    obj->object.widget->setFixedSize(width, height);
747
    obj->object.widget->move(left, top);
748
    obj->left = left;
749
    obj->top = top;
750
    obj->width = width;
751
    obj->height = height;
15 andreas 752
    // filter move event
753
    obj->object.widget->installEventFilter(this);
5 andreas 754
    // By default set a transparent background
28 andreas 755
    QPixmap pix(width, height);
5 andreas 756
    pix.fill(QColor::fromRgba(qRgba(0,0,0,0xff)));
757
    QPalette palette;
18 andreas 758
    palette.setBrush(QPalette::Window, QBrush(pix));
5 andreas 759
    obj->object.widget->setPalette(palette);
31 andreas 760
 
761
    // TODO: Is this realy necessary?
762
    if (mHasFocus)
763
        obj->object.widget->show();
764
    else
765
        mToShow.insert(std::pair<ulong, QWidget *>(handle, obj->object.widget));
766
 
14 andreas 767
    draw_mutex.unlock();
5 andreas 768
}
769
 
14 andreas 770
void MainWindow::setBackground(ulong handle, QByteArray image, size_t rowBytes, ulong color)
5 andreas 771
{
14 andreas 772
    draw_mutex.lock();
28 andreas 773
    DECL_TRACER("MainWindow::setBackground(ulong handle, QByteArray image, size_t rowBytes, ulong color)");
5 andreas 774
 
775
    OBJECT_t *obj = findObject(handle);
776
 
777
    if (!obj)
778
    {
13 andreas 779
        MSG_WARNING("No object " << handleToString(handle) << " found!");
14 andreas 780
        draw_mutex.unlock();
5 andreas 781
        return;
782
    }
783
 
14 andreas 784
    MSG_DEBUG("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " found!");
5 andreas 785
 
6 andreas 786
    if (obj->type == OBJ_BUTTON || obj->type == OBJ_SUBPAGE)
5 andreas 787
    {
14 andreas 788
        MSG_DEBUG("Processing object " << objectToString(obj->type));
6 andreas 789
        QPixmap pix(obj->width, obj->height);
790
        pix.fill(QColor::fromRgba(qRgba(TColor::getRed(color),TColor::getGreen(color),TColor::getBlue(color),TColor::getAlpha(color))));
5 andreas 791
 
14 andreas 792
        if (image.size() > 0)
5 andreas 793
        {
18 andreas 794
            MSG_DEBUG("Setting image of size " << image.size());
14 andreas 795
            QImage img((unsigned char *)image.data(), obj->width, obj->height, rowBytes, QImage::Format_ARGB32);
6 andreas 796
            pix.convertFromImage(img);
797
        }
798
 
799
        if (obj->type == OBJ_BUTTON)
800
        {
5 andreas 801
            obj->object.label->setPixmap(pix);
31 andreas 802
 
803
            if (mHasFocus)
804
                obj->object.label->show();
5 andreas 805
        }
6 andreas 806
        else
5 andreas 807
        {
19 andreas 808
            MSG_DEBUG("Setting image as background for page " << ((handle >> 16) & 0x0000ffff));
5 andreas 809
            QPalette palette;
18 andreas 810
            palette.setBrush(QPalette::Window, QBrush(pix));
6 andreas 811
            obj->object.widget->setPalette(palette);
31 andreas 812
 
813
            if (mHasFocus)
814
                obj->object.widget->show();
815
            else
816
                mToShow.insert(std::pair<ulong, QWidget *>(handle, obj->object.widget));
5 andreas 817
        }
818
    }
6 andreas 819
    else if (obj->type == OBJ_PAGE)
5 andreas 820
    {
6 andreas 821
        bool newBackground = false;
5 andreas 822
 
6 andreas 823
        if (!mBackground)
5 andreas 824
        {
6 andreas 825
            mBackground = new QWidget();
826
            mBackground->setAutoFillBackground(true);
31 andreas 827
            mBackground->setBackgroundRole(QPalette::Window);
6 andreas 828
            mBackground->setFixedSize(obj->width, obj->height);
829
            newBackground = true;
830
            MSG_DEBUG("New background image added to page with size " << obj->width << " x " << obj->height);
5 andreas 831
        }
6 andreas 832
 
833
        QPixmap pix(obj->width, obj->height);
834
        pix.fill(QColor::fromRgba(qRgba(TColor::getRed(color),TColor::getGreen(color),TColor::getBlue(color),TColor::getAlpha(color))));
835
 
14 andreas 836
        if (image.size() > 0)
5 andreas 837
        {
14 andreas 838
            QImage img((unsigned char *)image.data(), obj->width, obj->height, rowBytes, QImage::Format_ARGB32);
5 andreas 839
            pix.convertFromImage(img);
26 andreas 840
            MSG_DEBUG("Image converted. Width=" << obj->width << ", Height=" << obj->height);
6 andreas 841
        }
5 andreas 842
 
6 andreas 843
        QPalette palette;
18 andreas 844
        palette.setBrush(QPalette::Window, QBrush(pix));
6 andreas 845
        mBackground->setPalette(palette);
846
 
847
        if (newBackground)
848
            this->setCentralWidget(mBackground);
849
 
31 andreas 850
        if (mHasFocus)
851
            mBackground->show();
852
 
6 andreas 853
        MSG_DEBUG("Background set");
5 andreas 854
    }
14 andreas 855
 
856
    draw_mutex.unlock();
5 andreas 857
}
858
 
22 andreas 859
void MainWindow::setText(ulong handle, const std::string& text, const std::string& font, const std::string& family, int size, int x, int y, ulong color, ulong, FONT_STYLE style, Button::TEXT_ORIENTATION ori, Button::TEXT_EFFECT, bool ww)
7 andreas 860
{
14 andreas 861
    draw_mutex.lock();
7 andreas 862
    DECL_TRACER("MainWindow::setText(ulong handle, const std::string& text, const std::string& font, int size, int x, int y, ulong color, ulong effectColor, FONT_STYLE style, Button::TEXT_ORIENTATION ori, Button::TEXT_EFFECT effect, bool ww)");
5 andreas 863
 
7 andreas 864
    OBJECT_t *obj = findObject(handle);
865
 
866
    if (!obj)
867
    {
868
        MSG_ERROR("Object " << handleToString(handle) << " not found!");
869
        TError::setError();
14 andreas 870
        draw_mutex.unlock();
7 andreas 871
        return;
872
    }
873
 
874
    if (!obj->object.label)
875
    {
876
        MSG_ERROR("Object " << handleToString(handle) << " contains no child element!");
877
        TError::setError();
14 andreas 878
        draw_mutex.unlock();
7 andreas 879
        return;
880
    }
14 andreas 881
 
882
    MSG_DEBUG("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " found!");
883
 
10 andreas 884
#if !defined(QT_DISABLE_DEPRECATED_BEFORE) || (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
9 andreas 885
    QPixmap pix = *obj->object.label->pixmap();
886
#else
7 andreas 887
    QPixmap pix = obj->object.label->pixmap(Qt::ReturnByValue);
9 andreas 888
#endif
7 andreas 889
    // Load the font
890
    int fontID = 0;
891
 
892
    if ((fontID = QFontDatabase::addApplicationFont(font.c_str())) == -1)
893
    {
894
        MSG_ERROR("Font " << font << " could not be loaded!");
895
        TError::setError();
14 andreas 896
        draw_mutex.unlock();
7 andreas 897
        return;
898
    }
899
 
900
    QFont ft;
901
    ft.setFamily(family.c_str());
902
    ft.setPointSize(size);
903
 
904
    switch (style)
905
    {
906
        case FONT_BOLD:     ft.setBold(true); break;
907
        case FONT_ITALIC:   ft.setItalic(true); break;
908
        case FONT_BOLD_ITALIC:
909
            ft.setBold(true);
910
            ft.setItalic(true);
911
        break;
912
 
913
        default:
914
            ft.setBold(false);
915
            ft.setItalic(false);
916
    }
917
 
918
    QPalette palette = obj->object.label->palette();
919
    palette.setColor(QPalette::WindowText, QColor::fromRgba(qRgba(TColor::getRed(color),TColor::getGreen(color),TColor::getBlue(color),TColor::getAlpha(color))));
920
    obj->object.label->setPalette(palette);
921
    obj->object.label->setFont(ft);
922
    obj->object.label->setWordWrap(ww);
923
    obj->object.label->setIndent(4);
924
 
925
    switch (ori)
926
    {
927
        case Button::ORI_ABSOLUT:
928
        {
929
            QString pos = "<font style=\"position: absolute;left:";
930
            pos.append(x);
931
            pos.append(";top:");
932
            pos.append(y);
933
            pos.append(";>");
934
            pos.append(text.c_str());
935
            pos.append("</font>");
936
            MSG_DEBUG("Text: " << pos.data());
937
        }
938
        break;
939
 
940
        case Button::ORI_TOP_LEFT:      obj->object.label->setAlignment(Qt::AlignTop | Qt::AlignLeft); break;
941
        case Button::ORI_TOP_MIDDLE:    obj->object.label->setAlignment(Qt::AlignTop | Qt::AlignHCenter); break;
942
        case Button::ORI_TOP_RIGHT:     obj->object.label->setAlignment(Qt::AlignTop | Qt::AlignRight); break;
943
        case Button::ORI_CENTER_LEFT:   obj->object.label->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); break;
944
        case Button::ORI_CENTER_MIDDLE: obj->object.label->setAlignment(Qt::AlignCenter); break;
945
        case Button::ORI_CENTER_RIGHT:  obj->object.label->setAlignment(Qt::AlignVCenter | Qt::AlignRight); break;
946
        case Button::ORI_BOTTOM_LEFT:   obj->object.label->setAlignment(Qt::AlignBottom | Qt::AlignLeft); break;
947
        case Button::ORI_BOTTOM_MIDDLE: obj->object.label->setAlignment(Qt::AlignBottom | Qt::AlignHCenter); break;
948
        case Button::ORI_BOTTOM_RIGHT:  obj->object.label->setAlignment(Qt::AlignBottom | Qt::AlignRight); break;
949
    }
950
 
951
    obj->object.label->setText(text.c_str());
14 andreas 952
    draw_mutex.unlock();
7 andreas 953
}
954
 
11 andreas 955
void MainWindow::dropPage(ulong handle)
956
{
14 andreas 957
    draw_mutex.lock();
11 andreas 958
    DECL_TRACER("MainWindow::dropPage(ulong handle)");
7 andreas 959
 
31 andreas 960
    removeFromShowList(handle);
11 andreas 961
    removeAllChilds(handle);
962
    removeObject(handle);
963
 
964
    if (mBackground)
965
    {
966
        delete mBackground;
967
        mBackground = nullptr;
968
    }
14 andreas 969
 
970
    draw_mutex.unlock();
11 andreas 971
}
972
 
973
void MainWindow::dropSubPage(ulong handle)
974
{
14 andreas 975
    draw_mutex.lock();
11 andreas 976
    DECL_TRACER("MainWindow::dropSubPage(ulong handle)");
977
 
31 andreas 978
    removeFromShowList(handle);
11 andreas 979
    removeAllChilds(handle);
980
    OBJECT_t *obj = findObject(handle);
981
 
982
    if (!obj)
983
    {
984
        MSG_WARNING("Object " << handleToString(handle) << " does not exist. Ignoring!");
14 andreas 985
        draw_mutex.unlock();
11 andreas 986
        return;
987
    }
988
 
14 andreas 989
    dropContent(obj);
11 andreas 990
    removeObject(handle);
14 andreas 991
    draw_mutex.unlock();
11 andreas 992
}
993
 
21 andreas 994
void MainWindow::playVideo(ulong handle, ulong parent, int left, int top, int width, int height, const string& url, const string& user, const string& pw)
995
{
996
    draw_mutex.lock();
997
    DECL_TRACER("MainWindow::playVideo(ulong handle, const string& url, const string& user, const string& pw))");
998
 
999
    OBJECT_t *obj = findObject(handle);
1000
    OBJECT_t *par = findObject(parent);
1001
    MSG_DEBUG("Processing button " << handleToString(handle) << " from parent " << handleToString(parent));
1002
 
1003
    if (!par)
1004
    {
1005
        MSG_WARNING("Button has no parent! Ignoring it.");
1006
        draw_mutex.unlock();
1007
        return;
1008
    }
1009
 
1010
    if (!obj)
1011
    {
1012
        MSG_DEBUG("Adding new video object ...");
1013
        obj = addObject();
1014
 
1015
        if (!obj)
1016
        {
1017
            MSG_ERROR("Error creating a video object!");
1018
            TError::setError();
1019
            draw_mutex.unlock();
1020
            return;
1021
        }
1022
 
1023
        obj->type = OBJ_VIDEO;
1024
        obj->handle = handle;
1025
        obj->width = width;
1026
        obj->height = height;
1027
        obj->left = left;
1028
        obj->top = top;
1029
        obj->object.vwidget = new QVideoWidget(par->object.widget);
1030
        obj->object.vwidget->installEventFilter(this);
1031
    }
1032
    else
1033
        MSG_DEBUG("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " found!");
1034
 
1035
    QMediaPlaylist *playlist = new QMediaPlaylist;
1036
    QUrl qurl(url.c_str());
1037
 
1038
    if (!user.empty())
1039
        qurl.setUserName(user.c_str());
1040
 
1041
    if (!pw.empty())
1042
        qurl.setPassword(pw.c_str());
1043
 
1044
    playlist->addMedia(qurl);
1045
    obj->player = new QMediaPlayer;
1046
    obj->player->setPlaylist(playlist);
1047
    obj->player->setVideoOutput(obj->object.vwidget);
31 andreas 1048
 
1049
    if (mHasFocus)
1050
    {
1051
        obj->object.vwidget->show();
1052
        obj->player->play();
1053
    }
21 andreas 1054
}
1055
 
31 andreas 1056
void MainWindow::removeFromShowList(ulong handle)
1057
{
1058
    DECL_TRACER("MainWindow::removeFromShowList(ulong handle)");
1059
 
1060
    std::map<ulong, QWidget *>::iterator iter = mToShow.find(handle);
1061
 
1062
    if (iter != mToShow.end())
1063
        mToShow.erase(iter);
1064
}
1065
 
1066
void MainWindow::playShowList()
1067
{
1068
    DECL_TRACER("MainWindow::playShowList()");
1069
 
1070
    std::map<ulong, QWidget *>::iterator iter;
1071
 
1072
    for (iter = mToShow.begin(); iter != mToShow.end(); ++iter)
1073
    {
1074
        OBJECT_t *obj = findObject(iter->first);
1075
 
1076
        if (obj)
1077
            iter->second->show();
1078
    }
1079
 
1080
    mToShow.clear();
1081
}
1082
 
2 andreas 1083
#ifndef QT_NO_SESSIONMANAGER
1084
void MainWindow::commitData(QSessionManager &manager)
1085
{
5 andreas 1086
    if (manager.allowsInteraction())
1087
    {
1088
        if (!settingsChanged)
1089
            manager.cancel();
1090
    }
1091
    else
1092
    {
1093
        if (settingsChanged)
1094
            writeSettings();
1095
    }
2 andreas 1096
}
5 andreas 1097
#endif