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