Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 andreas 1
/*
101 andreas 2
 * Copyright (C) 2020 to 2022 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>
59 andreas 37
#include <QTouchEvent>
5 andreas 38
#include <QPalette>
9 andreas 39
#include <QPixmap>
7 andreas 40
#include <QFont>
41
#include <QFontDatabase>
21 andreas 42
#include <QtMultimediaWidgets/QVideoWidget>
43
#include <QtMultimedia/QMediaPlayer>
44
#include <QtMultimedia/QMediaPlaylist>
24 andreas 45
#include <QLayout>
40 andreas 46
#include <QSizePolicy>
21 andreas 47
#include <QUrl>
13 andreas 48
#include <QThread>
71 andreas 49
#include <QSound>
88 andreas 50
#ifdef __ANDROID__
51
#include <QAndroidJniObject>
52
#endif
5 andreas 53
#include <functional>
14 andreas 54
#include <mutex>
23 andreas 55
#ifdef __ANDROID__
56
#include <android/log.h>
57
#endif
4 andreas 58
#include "tpagemanager.h"
2 andreas 59
#include "tqtmain.h"
60
#include "tconfig.h"
61
#include "tqtsettings.h"
62 andreas 62
#include "tqkeyboard.h"
63
#include "tqkeypad.h"
5 andreas 64
#include "tcolor.h"
92 andreas 65
#include "texcept.h"
2 andreas 66
 
21 andreas 67
/**
44 andreas 68
 * @def THREAD_WAIT
69
 * This defines a time in milliseconds. It is used in the callbacks for the
70
 * functions to draw the elements. Qt need a little time to do it's work.
71
 * Therefore we're waiting a little bit. Otherwise it may result in missing
72
 * elements or black areas on the screen.
21 andreas 73
 */
100 andreas 74
#define THREAD_WAIT     1
44 andreas 75
 
76
extern amx::TAmxNet *gAmxNet;                   //!< Pointer to the class running the thread which handles the communication with the controller.
90 andreas 77
extern bool _restart_;                          //!< If this is set to true then the whole program will start over.
92 andreas 78
extern TPageManager *gPageManager;              //!< The pointer to the global defined main class.
21 andreas 79
std::mutex draw_mutex;                          //!< We're using threads and need to block execution sometimes
38 andreas 80
static bool isRunning = false;                  //!< TRUE = the pageManager was started.
100 andreas 81
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
44 andreas 82
static double gScale = 1.0;                     //!< Global variable holding the scale factor.
83
static int gFullWidth = 0;                      //!< Global variable holding the width of the AMX screen. This is used to calculate the scale factor for the settings dialog.
100 andreas 84
#endif
21 andreas 85
 
5 andreas 86
using std::bind;
61 andreas 87
using std::pair;
21 andreas 88
using std::string;
51 andreas 89
using std::vector;
5 andreas 90
 
21 andreas 91
/**
92
 * @brief qtmain is used here as the entry point for the surface.
93
 *
94
 * The main entry function parses the command line parameters, if there were
95
 * any and sets the basic attributes. It creates the main window and starts the
96
 * application.
97
 *
98
 * @param argc      The number of command line arguments
99
 * @param argv      A pointer to a 2 dimensional array containing the command
100
 *                  line parameters.
101
 * @param pmanager  A pointer to the page manager class which is the main class
102
 *                  managing everything.
103
 *
104
 * @return If no errors occured it returns 0.
105
 */
3 andreas 106
int qtmain(int argc, char **argv, TPageManager *pmanager)
2 andreas 107
{
31 andreas 108
    DECL_TRACER("qtmain(int argc, char **argv, TPageManager *pmanager)");
2 andreas 109
 
58 andreas 110
    if (!pmanager)
111
    {
112
        MSG_ERROR("Fatal: No pointer to the page manager received!");
113
        return 1;
114
    }
115
 
92 andreas 116
    if (!gPageManager || gPageManager != pmanager)
117
        gPageManager = pmanager;
88 andreas 118
#ifdef __ANDROID__
119
    MSG_INFO("Android API version: " << __ANDROID_API__);
3 andreas 120
 
88 andreas 121
#   if __ANDROID_API__ < 29
122
#       warn "The Android API version is less than 29! Some functions may not work!"
123
#   endif
124
#endif
58 andreas 125
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
38 andreas 126
    QApplication::setAttribute(Qt::AA_ForceRasterWidgets);
2 andreas 127
#endif
128
 
5 andreas 129
    QApplication app(argc, argv);
58 andreas 130
    // Set the orientation
131
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
132
    QScreen *screen = QGuiApplication::primaryScreen();
133
 
134
    if (!screen)
135
    {
136
        MSG_ERROR("Couldn't determine the primary screen!")
137
        return 1;
138
    }
139
 
140
    if (pmanager->getSettings()->getRotate() == 1)  // portrait?
88 andreas 141
    {
142
        MSG_INFO("Orientation set to portrait mode.");
58 andreas 143
        screen->setOrientationUpdateMask(Qt::PortraitOrientation);
88 andreas 144
    }
145
    else
146
    {
147
        MSG_INFO("Orientation set to landscape mode.");
148
        screen->setOrientationUpdateMask(Qt::LandscapeOrientation);
149
    }
58 andreas 150
 
38 andreas 151
    double scale = 1.0;
24 andreas 152
    // Calculate the scale factor
153
    if (TConfig::getScale())
154
    {
43 andreas 155
        // Because we've no window here we can not know on which screen, if
156
        // there are more than one, the application will start. Because on a
157
        // mobile mostly no external screen is connected, we take always the
158
        // resolution of the first (built in) screen.
159
        // TODO: Find a way to get the screen the application will start and
160
        // take this screen to calculate the scale factor.
24 andreas 161
        QList<QScreen *> screens = QGuiApplication::screens();
162
        QRect screenGeometry = screens.at(0)->availableGeometry();
88 andreas 163
        double width = 0.0;
164
        double height = 0.0;
24 andreas 165
        int minWidth = pmanager->getSettings()->getWith();
166
        int minHeight = pmanager->getSettings()->getHeight();
88 andreas 167
 
168
        if (pmanager->getSettings()->getRotate() == 1)  // portrait?
169
        {
170
            width = std::min(screenGeometry.width(), screenGeometry.height());
171
            height = std::max(screenGeometry.height(), screenGeometry.width());
172
        }
173
        else
174
        {
175
            width = std::max(screenGeometry.width(), screenGeometry.height());
176
            height = std::min(screenGeometry.height(), screenGeometry.width());
177
        }
178
 
31 andreas 179
        MSG_INFO("Dimension of AMX screen:" << minWidth << " x " << minHeight);
88 andreas 180
        MSG_INFO("Screen size: " << width << " x " << height);
43 andreas 181
        // The scale factor is always calculated in difference to the prefered
182
        // size of the original AMX panel.
24 andreas 183
        double scaleW = width / minWidth;
184
        double scaleH = height / minHeight;
38 andreas 185
        scale = std::min(scaleW, scaleH);
43 andreas 186
        gScale = scale;     // The calculated scale factor
88 andreas 187
        gFullWidth = width;
43 andreas 188
        // This preprocessor variable allows the scaling to be done by the Skia
189
        // library, which is used to draw everything. In comparison to Qt this
190
        // library is a bit slower and sometimes does not honor the aspect ratio
44 andreas 191
        // correct. But in case there is another framework than Qt in use, this
43 andreas 192
        // could be necessary.
193
#ifdef _SCALE_SKIA_
26 andreas 194
        if (scale != 0.0)
195
        {
196
            pmanager->setScaleFactor(scale);
31 andreas 197
            MSG_INFO("Scale factor: " << scale);
26 andreas 198
        }
31 andreas 199
 
200
        if (scaleW != 0.0)
201
            pmanager->setScaleFactorWidth(scaleW);
202
 
203
        if (scaleH != 0.0)
204
            pmanager->setScaleFactorHeight(scaleH);
58 andreas 205
#endif  // _SCALE_SKIA_
24 andreas 206
    }
58 andreas 207
#endif  // defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
23 andreas 208
 
24 andreas 209
    // Initialize the application
5 andreas 210
    QCoreApplication::setOrganizationName(TConfig::getProgName().c_str());
211
    QCoreApplication::setApplicationName("AMX panel simulator");
24 andreas 212
    QCoreApplication::setApplicationVersion(VERSION_STRING());
5 andreas 213
    QCommandLineParser parser;
214
    parser.setApplicationDescription(QCoreApplication::applicationName());
215
    parser.addHelpOption();
216
    parser.addVersionOption();
217
    parser.process(app);
2 andreas 218
 
5 andreas 219
    MainWindow mainWin;
58 andreas 220
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
221
#   ifndef _SCALE_SKIA_
43 andreas 222
    if (TConfig::getScale() && scale != 1.0)
38 andreas 223
        mainWin.setScaleFactor(scale);
58 andreas 224
#   endif   // _SCALE_SKIA_
225
#endif  // defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
22 andreas 226
    mainWin.setConfigFile(TConfig::getConfigPath() + "/" + TConfig::getConfigFileName());
43 andreas 227
    mainWin.setStyleSheet("QMainWindow {background: 'black';}");    // Keep the background black. Helps to save battery on OLED displays.
58 andreas 228
    mainWin.grabGesture(Qt::PinchGesture);
38 andreas 229
 
5 andreas 230
    mainWin.show();
231
    return app.exec();
2 andreas 232
}
233
 
21 andreas 234
/**
235
 * @brief MainWindow::MainWindow constructor
236
 *
237
 * This method is the constructor for this class. It registers the callback
238
 * functions to the class TPageManager and starts the main run loop.
43 andreas 239
 *
240
 * Qt is used only to manage widgets to handle pages and subpages. A page as
241
 * well as a subpage may contain a background graphic and some elements. The
242
 * elements could be buttons, bargraphs and other objects. The underlying layer
243
 * draw every element as a ready graphic image and call a callback function to
244
 * let Qt display the graphic.
245
 * If there are some animations on a subpage defined, this is also handled by
246
 * Qt. Especialy sliding and fading.
21 andreas 247
 */
2 andreas 248
MainWindow::MainWindow()
249
{
5 andreas 250
    DECL_TRACER("MainWindow::MainWindow()");
59 andreas 251
 
252
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
253
    setAttribute(Qt::WA_AcceptTouchEvents, true);   // We accept touch events
254
    grabGesture(Qt::PinchGesture);                  // We use a pinch gesture to open the settings dialog
88 andreas 255
 
92 andreas 256
    if (gPageManager && gPageManager->getSettings()->getRotate() == 1)  // portrait?
88 andreas 257
    {
258
        MSG_INFO("Orientation set to portrait mode.");
259
        _setOrientation(O_PORTRAIT);
260
    }
261
    else
262
    {
263
        MSG_INFO("Orientation set to landscape mode.");
264
        _setOrientation(O_LANDSCAPE);
265
    }
59 andreas 266
#endif
92 andreas 267
    if (!gPageManager)
268
    {
269
        EXCEPTFATALMSG("The class TPageManager was not initialized!");
270
    }
271
 
43 andreas 272
    // First we register all our surface callbacks to the underlying work
273
    // layer. All the graphics are drawn by the Skia library. The layer below
274
    // call the following functions to let Qt display the graphics on the
275
    // screen let it manage the widgets containing the graphics.
92 andreas 276
    gPageManager->registerCallbackDB(bind(&MainWindow::_displayButton, this,
5 andreas 277
                                       std::placeholders::_1,
278
                                       std::placeholders::_2,
279
                                       std::placeholders::_3,
280
                                       std::placeholders::_4,
281
                                       std::placeholders::_5,
282
                                       std::placeholders::_6,
283
                                       std::placeholders::_7,
284
                                       std::placeholders::_8));
285
 
92 andreas 286
    gPageManager->registerCallbackSP(bind(&MainWindow::_setPage, this,
5 andreas 287
                                         std::placeholders::_1,
288
                                         std::placeholders::_2,
289
                                         std::placeholders::_3));
290
 
92 andreas 291
    gPageManager->registerCallbackSSP(bind(&MainWindow::_setSubPage, this,
5 andreas 292
                                          std::placeholders::_1,
293
                                          std::placeholders::_2,
294
                                          std::placeholders::_3,
295
                                          std::placeholders::_4,
41 andreas 296
                                          std::placeholders::_5,
297
                                          std::placeholders::_6));
5 andreas 298
 
92 andreas 299
    gPageManager->registerCallbackSB(bind(&MainWindow::_setBackground, this,
5 andreas 300
                                         std::placeholders::_1,
301
                                         std::placeholders::_2,
302
                                         std::placeholders::_3,
303
                                         std::placeholders::_4,
38 andreas 304
                                         std::placeholders::_5,
305
                                         std::placeholders::_6,
306
                                         std::placeholders::_7));
5 andreas 307
 
92 andreas 308
    gPageManager->regCallDropPage(bind(&MainWindow::_dropPage, this, std::placeholders::_1));
309
    gPageManager->regCallDropSubPage(bind(&MainWindow::_dropSubPage, this, std::placeholders::_1));
310
    gPageManager->regCallPlayVideo(bind(&MainWindow::_playVideo, this,
21 andreas 311
                                       std::placeholders::_1,
312
                                       std::placeholders::_2,
313
                                       std::placeholders::_3,
314
                                       std::placeholders::_4,
315
                                       std::placeholders::_5,
316
                                       std::placeholders::_6,
317
                                       std::placeholders::_7,
318
                                       std::placeholders::_8,
319
                                       std::placeholders::_9));
92 andreas 320
    gPageManager->regCallInputText(bind(&MainWindow::_inputText, this, std::placeholders::_1, std::placeholders::_2));
321
    gPageManager->regCallbackKeyboard(bind(&MainWindow::_showKeyboard, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
322
    gPageManager->regCallbackKeypad(bind(&MainWindow::_showKeypad, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
323
    gPageManager->regCallResetKeyboard(bind(&MainWindow::_resetKeyboard, this));
324
    gPageManager->regCallShowSetup(bind(&MainWindow::_showSetup, this));
325
    gPageManager->regCallbackResetSurface(bind(&MainWindow::_resetSurface, this));
326
    gPageManager->regCallbackShutdown(bind(&MainWindow::_shutdown, this));
327
    gPageManager->regCallbackPlaySound(bind(&MainWindow::_playSound, this, std::placeholders::_1));
98 andreas 328
    gPageManager->registerCBsetVisible(bind(&MainWindow::_setVisible, this, std::placeholders::_1, std::placeholders::_2));
92 andreas 329
    gPageManager->deployCallbacks();
5 andreas 330
    createActions();
331
 
2 andreas 332
#ifndef QT_NO_SESSIONMANAGER
5 andreas 333
    QGuiApplication::setFallbackSessionManagementEnabled(false);
334
    connect(qApp, &QGuiApplication::commitDataRequest,
335
            this, &MainWindow::writeSettings);
2 andreas 336
#endif
43 andreas 337
    // Some types used to transport data from the layer below.
14 andreas 338
    qRegisterMetaType<size_t>("size_t");
339
    qRegisterMetaType<QByteArray>("QByteArray");
41 andreas 340
    qRegisterMetaType<ANIMATION_t>("ANIMATION_t");
50 andreas 341
    qRegisterMetaType<Button::TButton *>("TButton");
62 andreas 342
    qRegisterMetaType<std::string>("std::string");
14 andreas 343
 
43 andreas 344
    // All the callback functions doesn't act directly. Instead they emit an
345
    // event. Then Qt decides whether the real function is started directly and
346
    // immediately or if the call is queued and called later in a thread. To
347
    // handle this we're "connecting" the real functions to some signals.
15 andreas 348
    try
349
    {
350
        connect(this, &MainWindow::sigDisplayButton, this, &MainWindow::displayButton);
351
        connect(this, &MainWindow::sigSetPage, this, &MainWindow::setPage);
352
        connect(this, &MainWindow::sigSetSubPage, this, &MainWindow::setSubPage);
353
        connect(this, &MainWindow::sigSetBackground, this, &MainWindow::setBackground);
354
        connect(this, &MainWindow::sigDropPage, this, &MainWindow::dropPage);
355
        connect(this, &MainWindow::sigDropSubPage, this, &MainWindow::dropSubPage);
21 andreas 356
        connect(this, &MainWindow::sigPlayVideo, this, &MainWindow::playVideo);
50 andreas 357
        connect(this, &MainWindow::sigInputText, this, &MainWindow::inputText);
62 andreas 358
        connect(this, &MainWindow::sigKeyboard, this, &MainWindow::showKeyboard);
359
        connect(this, &MainWindow::sigKeypad, this, &MainWindow::showKeypad);
64 andreas 360
        connect(this, &MainWindow::sigShowSetup, this, &MainWindow::showSetup);
71 andreas 361
        connect(this, &MainWindow::sigPlaySound, this, &MainWindow::playSound);
98 andreas 362
        connect(this, &MainWindow::sigDropButton, this, &MainWindow::dropButton);
363
        connect(this, &MainWindow::sigSetVisible, this, &MainWindow::SetVisible);
31 andreas 364
        connect(qApp, &QGuiApplication::applicationStateChanged, this, &MainWindow::appStateChanged);
15 andreas 365
    }
366
    catch (std::exception& e)
367
    {
368
        MSG_ERROR("Connection error: " << e.what());
369
    }
93 andreas 370
    catch(...)
371
    {
372
        MSG_ERROR("Unexpected exception occured [MainWindow::MainWindow()]");
373
    }
15 andreas 374
 
5 andreas 375
    setUnifiedTitleAndToolBarOnMac(true);
61 andreas 376
#ifdef __ANDROID__
377
    // At least initialize the phone call listener
378
    if (gPageManager)
379
        gPageManager->initPhoneState();
92 andreas 380
 
93 andreas 381
    /*
382
     * In case this class was created not the first time, we initiate a small
383
     * thread to send the signal ApplicationActive to initiate the communication
384
     * with the controller again. This also starts the page manager thread
385
     * (TPageManager), which handles all elements of the surface.
386
     */
92 andreas 387
    if (_restart_ && gPageManager)
388
    {
93 andreas 389
        try
390
        {
391
            std::thread mThread = std::thread([=] { this->_signalState(Qt::ApplicationActive); });
392
            mThread.detach();   // We detach immediately to leave this method.
393
        }
394
        catch (std::exception& e)
395
        {
396
            MSG_ERROR("Error starting the thread to reinvoke communication!");
397
        }
398
        catch(...)
399
        {
400
            MSG_ERROR("Unexpected exception occured [MainWindow::MainWindow()]");
401
        }
92 andreas 402
    }
93 andreas 403
#endif
92 andreas 404
    _restart_ = false;
2 andreas 405
}
406
 
34 andreas 407
MainWindow::~MainWindow()
408
{
409
    DECL_TRACER("MainWindow::~MainWindow()");
40 andreas 410
 
34 andreas 411
    killed = true;
412
    prg_stopped = true;
413
 
414
    if (gAmxNet && !gAmxNet->isStopped())
415
        gAmxNet->stop();
90 andreas 416
 
417
    if (mToolbar)
418
    {
419
        removeToolBar(mToolbar);
420
        mToolbar = nullptr;
421
    }
422
 
423
    isRunning = false;
34 andreas 424
}
425
 
93 andreas 426
#ifdef __ANDROID__
21 andreas 427
/**
93 andreas 428
 * @brief Small thread to invoke the initialization on an Android device.
429
 *
430
 * On Android devices the signal ApplicationActive is not send if the class
431
 * \p MainWindow is destroyed and recreated. Therefore we need this little
432
 * helper to send the signal when the class is initialized.
433
 *
434
 * @param state     This defines the signal to send.
435
 */
436
void MainWindow::_signalState(Qt::ApplicationState state)
437
{
438
    DECL_TRACER("MainWindow::_signalState(Qt::ApplicationState state)");
439
 
440
    std::this_thread::sleep_for(std::chrono::seconds(1));   // Wait a second
441
    appStateChanged(state);
442
}
443
#endif
444
 
445
/**
21 andreas 446
 * @brief MainWindow::closeEvent called when the application receives an exit event.
447
 *
448
 * If the user clicks on the exit icon or on the menu point _Exit_ this method
449
 * is called. It makes sure everything is written to the configuration file
450
 * and accepts the evernt.
451
 *
452
 * @param event The exit event
453
 */
2 andreas 454
void MainWindow::closeEvent(QCloseEvent *event)
455
{
5 andreas 456
    DECL_TRACER("MainWindow::closeEvent(QCloseEvent *event)");
24 andreas 457
#ifdef __ANDROID__
23 andreas 458
    __android_log_print(ANDROID_LOG_DEBUG,"tpanel","Close event; settingsChanged=%s", (settingsChanged ? "true":"false"));
24 andreas 459
#endif
5 andreas 460
    if (settingsChanged)
461
    {
462
        writeSettings();
463
        event->accept();
464
    }
465
    else
466
    {
21 andreas 467
        prg_stopped = true;
34 andreas 468
        killed = true;
36 andreas 469
        MSG_INFO("Program will stop!");
37 andreas 470
#ifdef __ANDROID__
92 andreas 471
        if (gPageManager)
472
            gPageManager->stopNetworkState();
37 andreas 473
#endif
5 andreas 474
        event->accept();
475
    }
2 andreas 476
}
477
 
21 andreas 478
/**
479
 * @brief MainWindow::eventFilter filters the QEvent::MouseMove event
61 andreas 480
 * Beside the filtering of the MouseEvent, it waits for a gesture and
481
 * call the method gestureEvent() which handles the gesture and opens the
482
 * setting dialog.
21 andreas 483
 * @param obj   The object where the event occured.
484
 * @param event The event.
485
 * @return `true` when the event should be ignored.
486
 */
15 andreas 487
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
488
{
489
    if (event->type() == QEvent::MouseMove)
490
        return true;    // Filter event out, i.e. stop it being handled further.
491
 
59 andreas 492
    if (event->type() == QEvent::Gesture)
493
        return gestureEvent(static_cast<QGestureEvent*>(event));
494
 
15 andreas 495
    return QMainWindow::eventFilter(obj, event);
496
}
497
 
21 andreas 498
/**
57 andreas 499
 * @brief MainWindow::event Looks for a gesture
500
 * @param event The event occured
501
 * @return TRUE if event was accepted
502
 */
503
bool MainWindow::event(QEvent* event)
504
{
505
    if (event->type() == QEvent::Gesture)
506
        return gestureEvent(static_cast<QGestureEvent*>(event));
507
 
508
    return QWidget::event(event);
509
}
510
 
511
/**
512
 * @brief MainWindow::gestureEvent handles a pinch event
513
 * If a pinch event occured where the scale factor increased, the settings
514
 * dialog is called. This exists for devices, where the left toolbox is not
515
 * visible.
516
 * @param event The guesture occured
517
 * @return TRUE
518
 */
519
bool MainWindow::gestureEvent(QGestureEvent* event)
520
{
521
    DECL_TRACER("MainWindow::gestureEvent(QGestureEvent* event)");
59 andreas 522
 
57 andreas 523
    if (QGesture *pinch = event->gesture(Qt::PinchGesture))
524
    {
525
        string gs;
526
 
527
        QPinchGesture *pg = static_cast<QPinchGesture *>(pinch);
528
 
529
        switch(pg->state())
530
        {
531
            case Qt::NoGesture:         gs.assign("no gesture"); break;
532
            case Qt::GestureStarted:    gs.assign("gesture started"); break;
533
            case Qt::GestureUpdated:    gs.assign("gesture updated"); break;
534
            case Qt::GestureFinished:   gs.assign("gesture finished"); break;
535
            case Qt::GestureCanceled:   gs.assign("gesture canceled"); break;
536
        }
537
 
59 andreas 538
        MSG_DEBUG("PinchGesture state " << gs << " detected");
57 andreas 539
 
540
        if (pg->state() == Qt::GestureFinished)
541
        {
59 andreas 542
            MSG_DEBUG("total scale: " << pg->totalScaleFactor() << ", scale: " << pg->scaleFactor() << ", last scale: " << pg->lastScaleFactor());
543
 
57 andreas 544
            if (pg->totalScaleFactor() > pg->scaleFactor())
545
                settings();
546
        }
547
    }
548
 
549
    return false;
550
}
551
 
552
/**
39 andreas 553
 * @brief MainWindow::createActions creates the toolbar on the right side.
21 andreas 554
 */
2 andreas 555
void MainWindow::createActions()
556
{
5 andreas 557
    DECL_TRACER("MainWindow::createActions()");
2 andreas 558
 
88 andreas 559
    // Add a mToolbar (on the right side)
560
    mToolbar = new QToolBar(this);
58 andreas 561
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
88 andreas 562
    mToolbar->setAllowedAreas(Qt::RightToolBarArea);
563
    mToolbar->setFloatable(false);
564
    mToolbar->setMovable(false);
31 andreas 565
 
92 andreas 566
    if (TConfig::getScale() && gPageManager && gScale != 1.0)
38 andreas 567
    {
92 andreas 568
        int width = (int)((double)gPageManager->getSettings()->getWith() * gScale);
38 andreas 569
        int tbWidth = (int)(48.0 * gScale);
570
        int icWidth = (int)(40.0 * gScale);
571
 
572
        if ((gFullWidth - width) < tbWidth)
573
        {
88 andreas 574
            delete mToolbar;
575
            mToolbar = nullptr;
38 andreas 576
            return;
577
        }
578
 
579
        QSize iSize(icWidth, icWidth);
88 andreas 580
        mToolbar->setIconSize(iSize);
38 andreas 581
    }
39 andreas 582
#else
88 andreas 583
    mToolbar->setFloatable(true);
584
    mToolbar->setMovable(true);
585
    mToolbar->setAllowedAreas(Qt::RightToolBarArea | Qt::BottomToolBarArea);
39 andreas 586
#endif
32 andreas 587
    QAction *arrowUpAct = new QAction(QIcon(":/images/arrow_up.png"), tr("Up"), this);
588
    connect(arrowUpAct, &QAction::triggered, this, &MainWindow::arrowUp);
88 andreas 589
    mToolbar->addAction(arrowUpAct);
31 andreas 590
 
32 andreas 591
    QAction *arrowLeftAct = new QAction(QIcon(":/images/arrow_left.png"), tr("Left"), this);
592
    connect(arrowLeftAct, &QAction::triggered, this, &MainWindow::arrowLeft);
88 andreas 593
    mToolbar->addAction(arrowLeftAct);
31 andreas 594
 
32 andreas 595
    QAction *arrowRightAct = new QAction(QIcon(":/images/arrow_right.png"), tr("Right"), this);
596
    connect(arrowRightAct, &QAction::triggered, this, &MainWindow::arrowRight);
88 andreas 597
    mToolbar->addAction(arrowRightAct);
31 andreas 598
 
32 andreas 599
    QAction *arrowDownAct = new QAction(QIcon(":/images/arrow_down.png"), tr("Down"), this);
600
    connect(arrowDownAct, &QAction::triggered, this, &MainWindow::arrowDown);
88 andreas 601
    mToolbar->addAction(arrowDownAct);
31 andreas 602
 
32 andreas 603
    QAction *selectOkAct = new QAction(QIcon(":/images/ok.png"), tr("Ok"), this);
604
    connect(selectOkAct, &QAction::triggered, this, &MainWindow::selectOk);
88 andreas 605
    mToolbar->addAction(selectOkAct);
31 andreas 606
 
88 andreas 607
    mToolbar->addSeparator();
31 andreas 608
 
35 andreas 609
    QToolButton *btVolUp = new QToolButton(this);
610
    btVolUp->setIcon(QIcon(":/images/vol_up.png"));
611
    connect(btVolUp, &QToolButton::pressed, this, &MainWindow::volumeUpPressed);
612
    connect(btVolUp, &QToolButton::released, this, &MainWindow::volumeUpReleased);
88 andreas 613
    mToolbar->addWidget(btVolUp);
40 andreas 614
 
35 andreas 615
    QToolButton *btVolDown = new QToolButton(this);
616
    btVolDown->setIcon(QIcon(":/images/vol_down.png"));
617
    connect(btVolDown, &QToolButton::pressed, this, &MainWindow::volumeDownPressed);
618
    connect(btVolDown, &QToolButton::released, this, &MainWindow::volumeDownReleased);
88 andreas 619
    mToolbar->addWidget(btVolDown);
38 andreas 620
/*
33 andreas 621
    QAction *volMute = new QAction(QIcon(":/images/vol_mute.png"), tr("X"), this);
622
    connect(volMute, &QAction::triggered, this, &MainWindow::volumeMute);
88 andreas 623
    mToolbar->addAction(volMute);
38 andreas 624
*/
88 andreas 625
    mToolbar->addSeparator();
40 andreas 626
 
36 andreas 627
    const QIcon settingsIcon = QIcon::fromTheme("settings-configure", QIcon(":/images/settings.png"));
5 andreas 628
    QAction *settingsAct = new QAction(settingsIcon, tr("&Settings..."), this);
629
    settingsAct->setStatusTip(tr("Change the settings"));
630
    connect(settingsAct, &QAction::triggered, this, &MainWindow::settings);
88 andreas 631
    mToolbar->addAction(settingsAct);
2 andreas 632
 
38 andreas 633
    const QIcon aboutIcon = QIcon::fromTheme("help-about", QIcon(":/images/info.png"));
5 andreas 634
    QAction *aboutAct = new QAction(aboutIcon, tr("&About..."), this);
635
    aboutAct->setShortcuts(QKeySequence::Open);
636
    aboutAct->setStatusTip(tr("About this program"));
637
    connect(aboutAct, &QAction::triggered, this, &MainWindow::about);
88 andreas 638
    mToolbar->addAction(aboutAct);
2 andreas 639
 
33 andreas 640
    const QIcon exitIcon = QIcon::fromTheme("application-exit", QIcon(":/images/off.png"));
88 andreas 641
    QAction *exitAct = mToolbar->addAction(exitIcon, tr("E&xit"), this, &QWidget::close);
5 andreas 642
    exitAct->setShortcuts(QKeySequence::Quit);
643
    exitAct->setStatusTip(tr("Exit the application"));
31 andreas 644
 
88 andreas 645
    addToolBar(Qt::RightToolBarArea, mToolbar);
2 andreas 646
}
647
 
21 andreas 648
/**
649
 * @brief MainWindow::mousePressEvent catches the event Qt::LeftButton.
650
 *
651
 * If the user presses the left mouse button somewhere in the main window, this
652
 * method is triggered. It retrieves the position of the mouse pointer and
653
 * sends it to the page manager TPageManager.
654
 *
655
 * @param event The event
656
 */
10 andreas 657
void MainWindow::mousePressEvent(QMouseEvent* event)
658
{
70 andreas 659
    DECL_TRACER("MainWindow::mousePressEvent(QMouseEvent* event)");
660
 
10 andreas 661
    if(event->button() == Qt::LeftButton)
38 andreas 662
    {
663
        int x = event->x();
664
        int y = event->y();
665
 
70 andreas 666
        mLastPressX = x;
667
        mLastPressY = y;
668
 
38 andreas 669
        if (isScaled())
670
        {
671
            x = (int)((double)x / mScaleFactor);
672
            y = (int)((double)y / mScaleFactor);
673
        }
674
 
92 andreas 675
        gPageManager->mouseEvent(x, y, true);
38 andreas 676
    }
40 andreas 677
    else if (event->button() == Qt::MiddleButton)
678
        settings();
10 andreas 679
}
680
 
21 andreas 681
/**
682
 * @brief MainWindow::mouseReleaseEvent catches the event Qt::LeftButton.
683
 *
684
 * If the user releases the left mouse button somewhere in the main window, this
685
 * method is triggered. It retrieves the position of the mouse pointer and
686
 * sends it to the page manager TPageManager.
687
 *
688
 * @param event The event
689
 */
10 andreas 690
void MainWindow::mouseReleaseEvent(QMouseEvent* event)
691
{
70 andreas 692
    DECL_TRACER("MainWindow::mouseReleaseEvent(QMouseEvent* event)");
693
 
10 andreas 694
    if(event->button() == Qt::LeftButton)
38 andreas 695
    {
101 andreas 696
        int x = ((mLastPressX >= 0) ? mLastPressX : event->x());
697
        int y = ((mLastPressY >= 0) ? mLastPressY : event->y());
38 andreas 698
 
70 andreas 699
        mLastPressX = mLastPressY = -1;
700
 
38 andreas 701
        if (isScaled())
702
        {
703
            x = (int)((double)x / mScaleFactor);
704
            y = (int)((double)y / mScaleFactor);
705
        }
706
 
92 andreas 707
        gPageManager->mouseEvent(x, y, false);
38 andreas 708
    }
10 andreas 709
}
710
 
21 andreas 711
/**
712
 * @brief MainWindow::settings initiates the configuration dialog.
713
 */
2 andreas 714
void MainWindow::settings()
715
{
5 andreas 716
    DECL_TRACER("MainWindow::settings()");
2 andreas 717
 
90 andreas 718
    // Save some old values to decide whether to start over or not.
719
    string oldHost = TConfig::getController();
720
    int oldPort = TConfig::getPort();
721
    int oldChannelID = TConfig::getChannel();
722
    // Initialize and open the settings dialog.
5 andreas 723
    TQtSettings *dlg_settings = new TQtSettings(this);
58 andreas 724
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
43 andreas 725
    // On mobile devices we set the scale factor always because otherwise the
726
    // dialog will be unusable.
727
    dlg_settings->setScaleFactor(gScale);
40 andreas 728
    dlg_settings->doResize();
729
#endif
23 andreas 730
    int ret = dlg_settings->exec();
731
 
732
    if (ret && dlg_settings->hasChanged())
89 andreas 733
    {
23 andreas 734
        writeSettings();
89 andreas 735
 
90 andreas 736
        if (TConfig::getController() != oldHost ||
737
            TConfig::getChannel() != oldChannelID ||
738
            TConfig::getPort() != oldPort)
89 andreas 739
        {
90 andreas 740
            // Start over by exiting this class
741
            MSG_INFO("Program will start over!");
742
            _restart_ = true;
743
            prg_stopped = true;
744
            killed = true;
745
 
746
            if (gAmxNet)
747
                gAmxNet->stop();
748
 
749
            close();
89 andreas 750
        }
751
    }
23 andreas 752
    else if (!ret && dlg_settings->hasChanged())
753
    {
754
        TConfig cf(TConfig::getConfigPath() + "/" + TConfig::getConfigFileName());
755
    }
44 andreas 756
 
757
    delete dlg_settings;
2 andreas 758
}
759
 
21 andreas 760
/**
761
 * @brief MainWindow::writeSettings Writes the settings into the configuration file.
762
 */
2 andreas 763
void MainWindow::writeSettings()
764
{
5 andreas 765
    DECL_TRACER("MainWindow::writeSettings()");
23 andreas 766
 
767
    TConfig::saveSettings();
43 andreas 768
    MSG_INFO("Wrote settings.");
2 andreas 769
}
770
 
21 andreas 771
/**
772
 * @brief MainWindow::about displays the _about_ dialog.
773
 */
2 andreas 774
void MainWindow::about()
775
{
5 andreas 776
    DECL_TRACER("MainWindow::about()");
2 andreas 777
 
82 andreas 778
    std::string msg = "Simulation of an AMX G4 panel\n";
779
    msg.append("Version v").append(VERSION_STRING()).append("\n");
88 andreas 780
    msg.append("(C) Copyright 2020 to 2022 by Andreas Theofilu <andreas@theosys.at>\n");
82 andreas 781
    msg.append("This program is under the terms of GPL version 3");
782
 
5 andreas 783
    QMessageBox::about(this, tr(std::string("About ").append(TConfig::getProgName()).c_str()),
82 andreas 784
                       tr(msg.c_str()));
2 andreas 785
}
786
 
32 andreas 787
void MainWindow::arrowUp()
788
{
789
    DECL_TRACER("MainWindow::arrowUp()");
35 andreas 790
 
791
    extButtons_t btType = EXT_CURSOR_UP;
792
 
793
    if (TConfig::getPanelType().find("Android") != string::npos)
794
        btType = EXT_GESTURE_UP;
795
 
92 andreas 796
    gPageManager->externalButton(btType, true);
797
    gPageManager->externalButton(btType, false);
32 andreas 798
}
14 andreas 799
 
32 andreas 800
void MainWindow::arrowLeft()
801
{
802
    DECL_TRACER("MainWindow::arrowLeft()");
35 andreas 803
    extButtons_t btType = EXT_CURSOR_LEFT;
804
 
805
    if (TConfig::getPanelType().find("Android") != string::npos)
806
        btType = EXT_GESTURE_LEFT;
807
 
92 andreas 808
    gPageManager->externalButton(btType, true);
809
    gPageManager->externalButton(btType, false);
32 andreas 810
}
811
 
812
void MainWindow::arrowRight()
813
{
814
    DECL_TRACER("MainWindow::arrowRight()");
35 andreas 815
    extButtons_t btType = EXT_CURSOR_RIGHT;
816
 
817
    if (TConfig::getPanelType().find("Android") != string::npos)
818
        btType = EXT_GESTURE_RIGHT;
819
 
92 andreas 820
    gPageManager->externalButton(btType, true);
821
    gPageManager->externalButton(btType, false);
32 andreas 822
}
823
 
824
void MainWindow::arrowDown()
825
{
826
    DECL_TRACER("MainWindow::arrowDown()");
35 andreas 827
    extButtons_t btType = EXT_CURSOR_DOWN;
828
 
829
    if (TConfig::getPanelType().find("Android") != string::npos)
830
        btType = EXT_GESTURE_DOWN;
831
 
92 andreas 832
    gPageManager->externalButton(btType, true);
833
    gPageManager->externalButton(btType, false);
32 andreas 834
}
835
 
836
void MainWindow::selectOk()
837
{
838
    DECL_TRACER("MainWindow::selectOk()");
35 andreas 839
    extButtons_t btType = EXT_CURSOR_SELECT;
840
 
841
    if (TConfig::getPanelType().find("Android") != string::npos)
842
        btType = EXT_GESTURE_DOUBLE_PRESS;
843
 
92 andreas 844
    gPageManager->externalButton(btType, true);
845
    gPageManager->externalButton(btType, false);
32 andreas 846
}
847
 
33 andreas 848
void MainWindow::volumeUpPressed()
849
{
850
    DECL_TRACER("MainWindow::volumeUpPressed()");
35 andreas 851
    extButtons_t btType = EXT_CURSOR_ROTATE_RIGHT;
852
 
853
    if (TConfig::getPanelType().find("Android") != string::npos)
854
        btType = EXT_GESTURE_ROTATE_RIGHT;
855
 
92 andreas 856
    gPageManager->externalButton(btType, true);
33 andreas 857
}
858
 
859
void MainWindow::volumeUpReleased()
860
{
861
    DECL_TRACER("MainWindow::volumeUpReleased()");
35 andreas 862
    extButtons_t btType = EXT_CURSOR_ROTATE_RIGHT;
863
 
864
    if (TConfig::getPanelType().find("Android") != string::npos)
865
        btType = EXT_GESTURE_ROTATE_RIGHT;
866
 
92 andreas 867
    gPageManager->externalButton(btType, false);
33 andreas 868
}
869
 
870
void MainWindow::volumeDownPressed()
871
{
872
    DECL_TRACER("MainWindow::volumeDownPressed()");
35 andreas 873
    extButtons_t btType = EXT_CURSOR_ROTATE_LEFT;
874
 
875
    if (TConfig::getPanelType().find("Android") != string::npos)
876
        btType = EXT_GESTURE_ROTATE_LEFT;
877
 
92 andreas 878
    gPageManager->externalButton(btType, true);
33 andreas 879
}
880
 
881
void MainWindow::volumeDownReleased()
882
{
883
    DECL_TRACER("MainWindow::volumeDownReleased()");
35 andreas 884
    extButtons_t btType = EXT_CURSOR_ROTATE_LEFT;
885
 
886
    if (TConfig::getPanelType().find("Android") != string::npos)
887
        btType = EXT_GESTURE_ROTATE_LEFT;
888
 
92 andreas 889
    gPageManager->externalButton(btType, false);
33 andreas 890
}
38 andreas 891
/*
33 andreas 892
void MainWindow::volumeMute()
893
{
894
    DECL_TRACER("MainWindow::volumeMute()");
92 andreas 895
    gPageManager->externalButton(EXT_GENERAL, true);
896
    gPageManager->externalButton(EXT_GENERAL, false);
33 andreas 897
}
38 andreas 898
*/
42 andreas 899
void MainWindow::animationFinished()
900
{
901
    DECL_TRACER("MainWindow::animationFinished()");
43 andreas 902
 
42 andreas 903
    OBJECT_t *obj = getMarkedRemove();
43 andreas 904
 
42 andreas 905
    while (obj)
906
    {
907
        if (obj->animation && obj->animation->state() != QAbstractAnimation::Running)
908
            break;
43 andreas 909
 
42 andreas 910
        obj = getNextMarkedRemove(obj);
911
    }
43 andreas 912
 
101 andreas 913
    if (obj && obj->animation)
42 andreas 914
    {
915
        MSG_DEBUG("Dropping object " << handleToString(obj->handle));
916
        delete obj->animation;
917
        obj->animation = nullptr;
918
        dropContent(obj);
101 andreas 919
 
920
        if (mLastObject == obj)
921
            mLastObject = nullptr;
922
 
42 andreas 923
        removeObject(obj->handle);
924
    }
925
    else
926
    {
927
        MSG_WARNING("No or invalid object to delete!");
928
    }
929
}
930
 
51 andreas 931
void MainWindow::textChangedMultiLine()
932
{
933
    DECL_TRACER("MainWindow::textChangedMultiLine(const QString& text)");
934
    // Find out from which input line the signal was send
935
    QTextEdit* edit = qobject_cast<QTextEdit*>(sender());
936
 
937
    if (!edit)
938
    {
939
        MSG_ERROR("No QTextEdit widget found! External sender?");
940
        return;
941
    }
942
 
943
    QString text = edit->toPlainText();
944
    WId id = edit->winId();
945
    OBJECT_t *obj = findObject(id);
946
 
947
    if (!obj)
948
    {
949
        MSG_ERROR("No object witb WId " << id << " found!");
950
        return;
951
    }
952
 
92 andreas 953
    if (gPageManager)
954
        gPageManager->setTextToButton(obj->handle, text.toStdString());
51 andreas 955
}
956
 
957
void MainWindow::textSingleLineReturn()
958
{
959
    DECL_TRACER("MainWindow::textChangedSingleLine(const QString& text)");
960
 
961
    // Find out from which input line the signal was send
962
    QLineEdit* edit = qobject_cast<QLineEdit*>(sender());
963
 
964
    if (!edit)
965
    {
966
        MSG_ERROR("No QLineEdit widget found! External sender?");
967
        return;
968
    }
969
 
970
    QString text = edit->text();
971
    WId id = edit->winId();
972
    OBJECT_t *obj = findObject(id);
973
 
974
    if (!obj)
975
    {
976
        MSG_ERROR("No object with WId " << id << " found!");
977
        return;
978
    }
979
 
980
    MSG_DEBUG("Writing text: " << text.toStdString());
981
 
92 andreas 982
    if (gPageManager)
983
        gPageManager->setTextToButton(obj->handle, text.toStdString());
51 andreas 984
}
985
 
61 andreas 986
/**
987
 * @brief MainWindow::appStateChanged - Is called whenever the state of the app changes.
988
 * This callback method is called whenever the state of the application
989
 * changes. This is mostly usefull on mobile devices. Whenever the main window
990
 * looses the focus (screen closed, application is put into background, ...)
991
 * this method is called and updates a flag. If the application is not able
992
 * to draw to the screen (suspended) all events are cached. At the moment the
993
 * application becomes active, all queued messages are applied.
994
 * @param state     The new state of the application.
995
 */
31 andreas 996
void MainWindow::appStateChanged(Qt::ApplicationState state)
997
{
32 andreas 998
    DECL_TRACER("MainWindow::appStateChanged(Qt::ApplicationState state)");
31 andreas 999
 
1000
    switch (state)
1001
    {
61 andreas 1002
        case Qt::ApplicationSuspended:              // Should not occure on a normal desktop
36 andreas 1003
            MSG_INFO("Switched to mode SUSPEND");
31 andreas 1004
            mHasFocus = false;
1005
        break;
61 andreas 1006
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)      // On a normal desktop we can ignore this signals
31 andreas 1007
        case Qt::ApplicationInactive:
36 andreas 1008
            MSG_INFO("Switched to mode INACTIVE");
31 andreas 1009
            mHasFocus = false;
1010
        break;
1011
 
1012
        case Qt::ApplicationHidden:
36 andreas 1013
            MSG_INFO("Switched to mode HIDDEN");
31 andreas 1014
            mHasFocus = false;
1015
        break;
61 andreas 1016
#endif
31 andreas 1017
        case Qt::ApplicationActive:
36 andreas 1018
            MSG_INFO("Switched to mode ACTIVE");
31 andreas 1019
            mHasFocus = true;
38 andreas 1020
 
92 andreas 1021
            if (!isRunning && gPageManager)
38 andreas 1022
            {
1023
                // Start the core application
92 andreas 1024
                gPageManager->startUp();
1025
                gPageManager->run();
38 andreas 1026
                isRunning = true;
1027
            }
1028
            else
1029
                playShowList();
31 andreas 1030
        break;
61 andreas 1031
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
1032
        default:
1033
            mHasFocus = true;
1034
#endif
31 andreas 1035
    }
61 andreas 1036
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
92 andreas 1037
    if (mHasFocus && gPageManager)
38 andreas 1038
    {
92 andreas 1039
        gPageManager->initNetworkState();
1040
        gPageManager->initBatteryState();
38 andreas 1041
    }
92 andreas 1042
    else if (gPageManager)
38 andreas 1043
    {
92 andreas 1044
        gPageManager->stopNetworkState();
1045
        gPageManager->stopBatteryState();
38 andreas 1046
    }
37 andreas 1047
#endif
31 andreas 1048
}
1049
 
64 andreas 1050
void MainWindow::_shutdown()
1051
{
1052
    DECL_TRACER("MainWindow::_shutdown()")
1053
 
1054
    close();
1055
}
1056
 
32 andreas 1057
/******************* Signal handling *************************/
1058
 
44 andreas 1059
void MainWindow::_resetSurface()
1060
{
1061
    DECL_TRACER("MainWindow::_resetSurface()");
1062
 
90 andreas 1063
    // Start over by exiting this class
1064
    MSG_INFO("Program will start over!");
1065
    _restart_ = true;
1066
    prg_stopped = true;
1067
    killed = true;
88 andreas 1068
 
90 andreas 1069
    if (gAmxNet)
1070
        gAmxNet->stop();
88 andreas 1071
 
90 andreas 1072
    close();
44 andreas 1073
}
1074
 
14 andreas 1075
void MainWindow::_displayButton(ulong handle, ulong parent, unsigned char* buffer, int width, int height, int pixline, int left, int top)
4 andreas 1076
{
14 andreas 1077
    DECL_TRACER("MainWindow::_displayButton(ulong handle, ulong parent, unsigned char* buffer, int width, int height, int pixline, int left, int top)");
1078
 
21 andreas 1079
    if (prg_stopped)
1080
        return;
1081
 
61 andreas 1082
    if (!mHasFocus)     // Suspended?
1083
    {
1084
        addButton(handle, parent, buffer, pixline, left, top, width, height);
1085
        return;
1086
    }
1087
 
14 andreas 1088
    QByteArray buf;
1089
 
1090
    if (buffer && pixline > 0)
1091
    {
1092
        size_t size = width * height * (pixline / width);
15 andreas 1093
        MSG_DEBUG("Buffer size=" << size << ", width=" << width << ", height=" << height << ", left=" << left << ", top=" << top);
14 andreas 1094
        buf.insert(0, (const char *)buffer, size);
1095
    }
1096
 
15 andreas 1097
    try
1098
    {
1099
        emit sigDisplayButton(handle, parent, buf, width, height, pixline, left, top);
1100
    }
1101
    catch (std::exception& e)
1102
    {
1103
        MSG_ERROR("Error triggering function \"displayButton()\": " << e.what());
1104
    }
98 andreas 1105
 
44 andreas 1106
    std::this_thread::sleep_for(std::chrono::milliseconds(THREAD_WAIT));
14 andreas 1107
}
1108
 
98 andreas 1109
void MainWindow::_setVisible(ulong handle, bool state)
1110
{
1111
    DECL_TRACER("MainWindow::_setVisible(ulong handle, bool state)");
1112
 
1113
    if (prg_stopped)
1114
        return;
1115
 
100 andreas 1116
    MSG_DEBUG("Object " << handleToString(handle) << " marked for " << (state ? "VISIBLE" : "INVISIBLE") << " state.");
98 andreas 1117
    emit sigSetVisible(handle, state);
1118
}
1119
 
14 andreas 1120
void MainWindow::_setPage(ulong handle, int width, int height)
1121
{
1122
    DECL_TRACER("MainWindow::_setPage(ulong handle, int width, int height)");
1123
 
21 andreas 1124
    if (prg_stopped)
1125
        return;
1126
 
61 andreas 1127
    if (!mHasFocus)
1128
    {
1129
        addPage(handle, width, height);
1130
        return;
1131
    }
1132
 
14 andreas 1133
    emit sigSetPage(handle, width, height);
57 andreas 1134
#ifndef __ANDROID__
44 andreas 1135
    std::this_thread::sleep_for(std::chrono::milliseconds(THREAD_WAIT));
57 andreas 1136
#endif
14 andreas 1137
}
1138
 
41 andreas 1139
void MainWindow::_setSubPage(ulong handle, int left, int top, int width, int height, ANIMATION_t animate)
14 andreas 1140
{
1141
    DECL_TRACER("MainWindow::_setSubPage(ulong handle, int left, int top, int width, int height)");
1142
 
21 andreas 1143
    if (prg_stopped)
1144
        return;
1145
 
61 andreas 1146
    if (!mHasFocus)
1147
    {
1148
        addSubPage(handle, left, top, width, height, animate);
1149
        return;
1150
    }
1151
 
41 andreas 1152
    emit sigSetSubPage(handle, left, top, width, height, animate);
57 andreas 1153
#ifndef __ANDROID__
44 andreas 1154
    std::this_thread::sleep_for(std::chrono::milliseconds(THREAD_WAIT));
57 andreas 1155
#endif
14 andreas 1156
}
1157
 
38 andreas 1158
void MainWindow::_setBackground(ulong handle, unsigned char *image, size_t size, size_t rowBytes, int width, int height, ulong color)
14 andreas 1159
{
1160
    DECL_TRACER("MainWindow::_setBackground(ulong handle, unsigned char *image, size_t size, size_t rowBytes, ulong color)");
1161
 
21 andreas 1162
    if (prg_stopped)
1163
        return;
1164
 
61 andreas 1165
    if (!mHasFocus)
1166
    {
1167
        addBackground(handle, image, size, rowBytes, width, height, color);
1168
        return;
1169
    }
1170
 
14 andreas 1171
    QByteArray buf;
1172
 
1173
    if (image && size > 0)
1174
        buf.insert(0, (const char *)image, size);
1175
 
38 andreas 1176
    emit sigSetBackground(handle, buf, rowBytes, width, height, color);
57 andreas 1177
#ifndef __ANDROID__
44 andreas 1178
    std::this_thread::sleep_for(std::chrono::milliseconds(THREAD_WAIT));
57 andreas 1179
#endif
14 andreas 1180
}
1181
 
1182
void MainWindow::_dropPage(ulong handle)
1183
{
1184
    DECL_TRACER("MainWindow::_dropPage(ulong handle)");
1185
 
70 andreas 1186
    doReleaseButton();
1187
 
61 andreas 1188
    if (!mHasFocus)
1189
    {
1190
        markDrop(handle);
1191
        return;
1192
    }
1193
 
14 andreas 1194
    emit sigDropPage(handle);
70 andreas 1195
 
57 andreas 1196
#ifndef __ANDROID__
44 andreas 1197
    std::this_thread::sleep_for(std::chrono::milliseconds(THREAD_WAIT));
57 andreas 1198
#endif
14 andreas 1199
}
1200
 
1201
void MainWindow::_dropSubPage(ulong handle)
1202
{
1203
    DECL_TRACER("MainWindow::_dropSubPage(ulong handle)");
1204
 
70 andreas 1205
    doReleaseButton();
1206
 
61 andreas 1207
    if (!mHasFocus)
1208
    {
1209
        markDrop(handle);
1210
        return;
1211
    }
1212
 
14 andreas 1213
    emit sigDropSubPage(handle);
70 andreas 1214
 
57 andreas 1215
#ifndef __ANDROID__
44 andreas 1216
    std::this_thread::sleep_for(std::chrono::milliseconds(THREAD_WAIT));
57 andreas 1217
#endif
14 andreas 1218
}
1219
 
98 andreas 1220
void MainWindow::_dropButton(ulong handle)
1221
{
1222
    DECL_TRACER("MainWindow::_dropButton(ulong handle)");
1223
 
1224
    if (!mHasFocus)
1225
    {
1226
        markDrop(handle);
1227
        return;
1228
    }
1229
 
1230
    emit sigDropButton(handle);
1231
}
1232
 
21 andreas 1233
void MainWindow::_playVideo(ulong handle, ulong parent, int left, int top, int width, int height, const string& url, const string& user, const string& pw)
1234
{
1235
    DECL_TRACER("MainWindow::_playVideo(ulong handle, const string& url)");
1236
 
1237
    if (prg_stopped)
1238
        return;
1239
 
61 andreas 1240
    if (!mHasFocus)
1241
    {
1242
        addVideo(handle, parent, left, top, width, height, url, user, pw);
1243
        return;
1244
    }
1245
 
21 andreas 1246
    emit sigPlayVideo(handle, parent, left, top, width, height, url, user, pw);
57 andreas 1247
#ifndef __ANDROID__
44 andreas 1248
    std::this_thread::sleep_for(std::chrono::milliseconds(THREAD_WAIT));
57 andreas 1249
#endif
21 andreas 1250
}
1251
 
52 andreas 1252
void MainWindow::_inputText(Button::TButton* button, Button::BITMAP_t& bm)
50 andreas 1253
{
52 andreas 1254
    DECL_TRACER("MainWindow::_inputText(Button::TButton* button, Button::BITMAP_t& bm)");
50 andreas 1255
 
1256
    if (prg_stopped)
1257
        return;
1258
 
61 andreas 1259
    if (!mHasFocus)
1260
    {
1261
        addInText(button->getHandle(), button, bm);
1262
        return;
1263
    }
1264
 
52 andreas 1265
    QByteArray buf;
1266
 
1267
    if (bm.buffer && bm.rowBytes > 0)
1268
    {
1269
        size_t size = bm.width * bm.height * (bm.rowBytes / bm.width);
1270
        buf.insert(0, (const char *)bm.buffer, size);
1271
    }
57 andreas 1272
 
52 andreas 1273
    emit sigInputText(button, buf, bm.width, bm.height, bm.rowBytes);
57 andreas 1274
#ifndef __ANDROID__
50 andreas 1275
    std::this_thread::sleep_for(std::chrono::milliseconds(THREAD_WAIT));
57 andreas 1276
#endif
50 andreas 1277
}
1278
 
63 andreas 1279
void MainWindow::_showKeyboard(const std::string& init, const std::string& prompt, bool priv)
62 andreas 1280
{
63 andreas 1281
    DECL_TRACER("MainWindow::_showKeyboard(std::string &init, std::string &prompt, bool priv)");
62 andreas 1282
 
1283
    if (prg_stopped)
1284
        return;
1285
 
70 andreas 1286
    doReleaseButton();
63 andreas 1287
    emit sigKeyboard(init, prompt, priv);
62 andreas 1288
}
1289
 
63 andreas 1290
void MainWindow::_showKeypad(const std::string& init, const std::string& prompt, bool priv)
62 andreas 1291
{
63 andreas 1292
    DECL_TRACER("MainWindow::_showKeypad(std::string &init, std::string &prompt, bool priv)");
62 andreas 1293
 
1294
    if (prg_stopped)
1295
        return;
1296
 
70 andreas 1297
    doReleaseButton();
63 andreas 1298
    emit sigKeypad(init, prompt, priv);
62 andreas 1299
}
1300
 
63 andreas 1301
void MainWindow::_resetKeyboard()
1302
{
1303
    DECL_TRACER("MainWindow::_resetKeyboard()");
1304
 
1305
    emit sigResetKeyboard();
1306
}
1307
 
64 andreas 1308
void MainWindow::_showSetup()
1309
{
1310
    DECL_TRACER("MainWindow::_showSetup()");
1311
 
1312
    emit sigShowSetup();
1313
}
1314
 
71 andreas 1315
void MainWindow::_playSound(const string& file)
1316
{
1317
    DECL_TRACER("MainWindow::_playSound(const string& file)");
1318
 
1319
    emit sigPlaySound(file);
1320
}
1321
 
88 andreas 1322
void MainWindow::_setOrientation(J_ORIENTATION ori)
1323
{
1324
#ifdef __ANDROID__
1325
    DECL_TRACER("MainWindow::_setOriantation(J_ORIENTATION ori)");
1326
 
1327
    QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
1328
 
1329
    if ( activity.isValid() )
1330
    {
1331
        activity.callMethod<void>
1332
                ("setRequestedOrientation"  // method name
1333
                 , "(I)V"                   // signature
1334
                 , ori);
1335
    }
1336
#endif
1337
}
1338
 
70 andreas 1339
void MainWindow::doReleaseButton()
1340
{
1341
    DECL_TRACER("MainWindow::doReleaseButton()");
1342
 
92 andreas 1343
    if (mLastPressX >= 0 && mLastPressX >= 0 && gPageManager)
70 andreas 1344
    {
1345
        MSG_DEBUG("Sending outstanding mouse release event for coordinates x" << mLastPressX << ", y" << mLastPressY);
1346
        int x = mLastPressX;
1347
        int y = mLastPressY;
1348
 
1349
        if (isScaled())
1350
        {
1351
            x = (int)((double)x / mScaleFactor);
1352
            y = (int)((double)y / mScaleFactor);
1353
        }
1354
 
92 andreas 1355
        gPageManager->mouseEvent(x, y, false);
70 andreas 1356
    }
1357
 
1358
    mLastPressX = mLastPressY = -1;
1359
}
1360
 
14 andreas 1361
/******************* Draw elements *************************/
1362
 
1363
void MainWindow::displayButton(ulong handle, ulong parent, QByteArray buffer, int width, int height, int pixline, int left, int top)
1364
{
1365
    draw_mutex.lock();
5 andreas 1366
    DECL_TRACER("MainWindow::displayButton(ulong handle, unsigned char* buffer, size_t size, int width, int height, int pixline, int left, int top)");
4 andreas 1367
 
38 andreas 1368
    if (isScaled())
1369
    {
1370
        MSG_DEBUG("Scaling to factor " << mScaleFactor);
1371
    }
1372
 
5 andreas 1373
    OBJECT_t *obj = findObject(handle);
6 andreas 1374
    OBJECT_t *par = findObject(parent);
50 andreas 1375
    MSG_TRACE("Processing button " << handleToString(handle) << " from parent " << handleToString(parent));
5 andreas 1376
 
6 andreas 1377
    if (!par)
1378
    {
59 andreas 1379
        if (TStreamError::checkFilter(HLOG_DEBUG))
1380
            MSG_WARNING("Button " << handleToString(handle) << " has no parent (" << handleToString(parent) << ")! Ignoring it.");
1381
 
14 andreas 1382
        draw_mutex.unlock();
6 andreas 1383
        return;
1384
    }
1385
 
5 andreas 1386
    if (!obj)
1387
    {
59 andreas 1388
        MSG_DEBUG("Adding new object " << handleToString(handle) << " ...");
5 andreas 1389
        obj = addObject();
1390
 
1391
        if (!obj)
1392
        {
1393
            MSG_ERROR("Error creating an object!");
1394
            TError::setError();
14 andreas 1395
            draw_mutex.unlock();
5 andreas 1396
            return;
1397
        }
1398
 
1399
        obj->type = OBJ_BUTTON;
1400
        obj->handle = handle;
38 andreas 1401
        obj->width = scale(width);
1402
        obj->height = scale(height);
1403
        obj->left = scale(left);
1404
        obj->top = scale(top);
40 andreas 1405
 
1406
        if (par->type == OBJ_PAGE)
1407
            obj->object.label = new QLabel("", mBackground);
1408
        else
1409
            obj->object.label = new QLabel("", par->object.widget);
1410
 
15 andreas 1411
        obj->object.label->installEventFilter(this);
57 andreas 1412
        obj->object.label->grabGesture(Qt::PinchGesture);
59 andreas 1413
        obj->object.label->setFixedSize(obj->width, obj->height);
1414
        obj->object.label->move(obj->left, obj->top);
1415
        obj->object.label->setAttribute(Qt::WA_TransparentForMouseEvents);
6 andreas 1416
    }
14 andreas 1417
    else
1418
        MSG_DEBUG("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " found!");
5 andreas 1419
 
59 andreas 1420
//    MSG_DEBUG("Geometry: l:" << obj->left << ", t:" << obj->top << ", w:" << obj->width << ", h:" << obj->height);
6 andreas 1421
 
75 andreas 1422
    try
6 andreas 1423
    {
75 andreas 1424
        if (buffer.size() > 0 && pixline > 0)
1425
        {
1426
            MSG_DEBUG("Setting image for " << handleToString(handle) << " ...");
1427
            QImage img((unsigned char *)buffer.data(), width, height, pixline, QImage::Format_ARGB32);  // Original size
1428
            QSize size(obj->width, obj->height);
1429
            QPixmap pixmap(size);
38 andreas 1430
 
75 andreas 1431
            if (isScaled())
1432
                pixmap.convertFromImage(img.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); // Scaled size
1433
            else
1434
                pixmap.convertFromImage(img);
38 andreas 1435
 
75 andreas 1436
            obj->object.label->setPixmap(pixmap);
1437
        }
1438
 
1439
    //    if (mHasFocus)
1440
            obj->object.label->show();
1441
    /*    else
1442
        {
1443
            if (par->type == OBJ_PAGE || par->type == OBJ_SUBPAGE)
1444
                mToShow.insert(std::pair<ulong, QWidget *>(par->handle, par->object.widget));
1445
        }
1446
    */
5 andreas 1447
    }
75 andreas 1448
    catch(std::exception& e)
31 andreas 1449
    {
75 andreas 1450
        MSG_ERROR("Error drawing button " << handleToString(handle) << ": " << e.what());
31 andreas 1451
    }
93 andreas 1452
    catch(...)
1453
    {
1454
        MSG_ERROR("Unexpected exception occured [MainWindow::displayButton()]");
1455
    }
75 andreas 1456
 
14 andreas 1457
    draw_mutex.unlock();
4 andreas 1458
}
1459
 
98 andreas 1460
void MainWindow::SetVisible(ulong handle, bool state)
1461
{
1462
    DECL_TRACER("MainWindow::SetVisible(ulong handle, bool state)");
1463
 
1464
    OBJECT_t *obj = findObject(handle);
1465
 
1466
    if (!obj)
1467
    {
1468
        MSG_ERROR("Object " << handleToString(handle) << " not found!");
1469
        return;
1470
    }
1471
 
1472
    if (obj->type == OBJ_BUTTON && obj->object.label)
99 andreas 1473
    {
1474
        MSG_DEBUG("Setting object " << handleToString(handle) << " visibility to " << (state ? "TRUE" : "FALSE"));
98 andreas 1475
        obj->object.label->setVisible(state);
99 andreas 1476
    }
1477
    else
1478
    {
1479
        MSG_DEBUG("Ignoring non button object " << handleToString(handle));
1480
    }
98 andreas 1481
}
1482
 
5 andreas 1483
void MainWindow::setPage(ulong handle, int width, int height)
1484
{
14 andreas 1485
    draw_mutex.lock();
5 andreas 1486
    DECL_TRACER("MainWindow::setPage(ulong handle, int width, int height)");
4 andreas 1487
 
6 andreas 1488
    QSize qs = menuBar()->sizeHint();
38 andreas 1489
    this->setMinimumSize(scale(width), scale(height) + qs.height());
5 andreas 1490
    OBJECT_t *obj = findObject(handle);
1491
 
1492
    if (!obj)
1493
    {
1494
        obj = addObject();
1495
 
1496
        if (!obj)
1497
        {
1498
            MSG_ERROR("Error crating an object for handle " << handleToString(handle));
1499
            TError::setError();
14 andreas 1500
            draw_mutex.unlock();
5 andreas 1501
            return;
1502
        }
1503
 
1504
        obj->handle = handle;
38 andreas 1505
        obj->height = scale(height);
1506
        obj->width = scale(width);
5 andreas 1507
        obj->type = OBJ_PAGE;
1508
    }
6 andreas 1509
 
1510
    bool newBackground = false;
1511
 
1512
    if (!mBackground)
1513
    {
1514
        mBackground = new QWidget();
57 andreas 1515
        mBackground->grabGesture(Qt::PinchGesture);
6 andreas 1516
        mBackground->setAutoFillBackground(true);
31 andreas 1517
        mBackground->setBackgroundRole(QPalette::Window);
58 andreas 1518
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
6 andreas 1519
        mBackground->setFixedSize(obj->width, obj->height);
40 andreas 1520
#else
10 andreas 1521
        QRect rectBack = mBackground->geometry();
1522
        QRect rectMain = this->geometry();
40 andreas 1523
 
1524
        QSize icSize =  this->iconSize();
90 andreas 1525
        int width = rectMain.width() + icSize.width() + 16;
40 andreas 1526
        rectMain.setWidth(width);
1527
        setGeometry(rectMain);
1528
        // If our first top pixel is not 0, maybe because of a menu, window
1529
        // decorations or a toolbar, we must add this extra height to the
1530
        // positions of widgets and mouse presses.
28 andreas 1531
        int avHeight = rectMain.height() - rectBack.height();
1532
        MSG_DEBUG("avHeight=" << avHeight);
92 andreas 1533
        gPageManager->setFirstTopPixel(avHeight);
31 andreas 1534
#endif
6 andreas 1535
        newBackground = true;
1536
    }
1537
 
1538
    // By default set a transparent background
38 andreas 1539
    QPixmap pix(obj->width, obj->height);
6 andreas 1540
    pix.fill(QColor::fromRgba(qRgba(0,0,0,0xff)));
1541
    QPalette palette;
1542
    palette.setBrush(QPalette::Window, pix);
1543
    mBackground->setPalette(palette);
1544
 
1545
    if (newBackground)
1546
        this->setCentralWidget(mBackground);
1547
 
62 andreas 1548
    mBackground->show();
14 andreas 1549
    draw_mutex.unlock();
5 andreas 1550
}
1551
 
41 andreas 1552
void MainWindow::setSubPage(ulong handle, int left, int top, int width, int height, ANIMATION_t animate)
5 andreas 1553
{
14 andreas 1554
    draw_mutex.lock();
5 andreas 1555
    DECL_TRACER("MainWindow::setSubPage(ulong handle, int left, int top, int width, int height)");
38 andreas 1556
 
1557
    if (isScaled())
1558
    {
1559
        MSG_DEBUG("Scaling to factor " << mScaleFactor);
1560
    }
1561
 
5 andreas 1562
    OBJECT_t *obj = addObject();
1563
 
1564
    if (!obj)
1565
    {
1566
        MSG_ERROR("Error adding an object!");
1567
        TError::setError();
14 andreas 1568
        draw_mutex.unlock();
5 andreas 1569
        return;
1570
    }
1571
 
38 andreas 1572
    int scLeft = scale(left);
1573
    int scTop = scale(top);
1574
    int scWidth = scale(width);
1575
    int scHeight = scale(height);
1576
 
5 andreas 1577
    obj->type = OBJ_SUBPAGE;
1578
    obj->handle = handle;
13 andreas 1579
    obj->object.widget = new QWidget(centralWidget());
6 andreas 1580
    obj->object.widget->setAutoFillBackground(true);
38 andreas 1581
    obj->object.widget->setFixedSize(scWidth, scHeight);
1582
    obj->object.widget->move(scLeft, scTop);
1583
    obj->left = scLeft;
1584
    obj->top = scTop;
1585
    obj->width = scWidth;
1586
    obj->height = scHeight;
15 andreas 1587
    // filter move event
1588
    obj->object.widget->installEventFilter(this);
57 andreas 1589
    obj->object.widget->grabGesture(Qt::PinchGesture);
5 andreas 1590
    // By default set a transparent background
38 andreas 1591
    QPixmap pix(scWidth, scHeight);
5 andreas 1592
    pix.fill(QColor::fromRgba(qRgba(0,0,0,0xff)));
1593
    QPalette palette;
18 andreas 1594
    palette.setBrush(QPalette::Window, QBrush(pix));
5 andreas 1595
    obj->object.widget->setPalette(palette);
31 andreas 1596
 
61 andreas 1597
//    if (mHasFocus)
1598
//    {
58 andreas 1599
        startAnimation(obj, animate);
1600
//        obj->object.widget->show();
61 andreas 1601
/*    }
31 andreas 1602
    else
1603
        mToShow.insert(std::pair<ulong, QWidget *>(handle, obj->object.widget));
61 andreas 1604
*/
14 andreas 1605
    draw_mutex.unlock();
5 andreas 1606
}
1607
 
38 andreas 1608
void MainWindow::setBackground(ulong handle, QByteArray image, size_t rowBytes, int width, int height, ulong color)
5 andreas 1609
{
14 andreas 1610
    draw_mutex.lock();
28 andreas 1611
    DECL_TRACER("MainWindow::setBackground(ulong handle, QByteArray image, size_t rowBytes, ulong color)");
5 andreas 1612
 
1613
    OBJECT_t *obj = findObject(handle);
1614
 
1615
    if (!obj)
1616
    {
13 andreas 1617
        MSG_WARNING("No object " << handleToString(handle) << " found!");
14 andreas 1618
        draw_mutex.unlock();
5 andreas 1619
        return;
1620
    }
1621
 
50 andreas 1622
    MSG_TRACE("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " found!");
5 andreas 1623
 
6 andreas 1624
    if (obj->type == OBJ_BUTTON || obj->type == OBJ_SUBPAGE)
5 andreas 1625
    {
14 andreas 1626
        MSG_DEBUG("Processing object " << objectToString(obj->type));
6 andreas 1627
        QPixmap pix(obj->width, obj->height);
1628
        pix.fill(QColor::fromRgba(qRgba(TColor::getRed(color),TColor::getGreen(color),TColor::getBlue(color),TColor::getAlpha(color))));
5 andreas 1629
 
14 andreas 1630
        if (image.size() > 0)
5 andreas 1631
        {
38 andreas 1632
            MSG_DEBUG("Setting image of size " << image.size() << " (" << width << " x " << height << ")");
1633
            QImage img((unsigned char *)image.data(), width, height, rowBytes, QImage::Format_ARGB32);
1634
 
1635
            if (isScaled())
1636
            {
1637
                QSize size(obj->width, obj->height);
1638
                pix.convertFromImage(img.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
1639
            }
1640
            else
1641
                pix.convertFromImage(img);
6 andreas 1642
        }
1643
 
1644
        if (obj->type == OBJ_BUTTON)
1645
        {
5 andreas 1646
            obj->object.label->setPixmap(pix);
31 andreas 1647
 
1648
            if (mHasFocus)
1649
                obj->object.label->show();
5 andreas 1650
        }
6 andreas 1651
        else
5 andreas 1652
        {
19 andreas 1653
            MSG_DEBUG("Setting image as background for page " << ((handle >> 16) & 0x0000ffff));
5 andreas 1654
            QPalette palette;
18 andreas 1655
            palette.setBrush(QPalette::Window, QBrush(pix));
6 andreas 1656
            obj->object.widget->setPalette(palette);
31 andreas 1657
 
61 andreas 1658
//            if (mHasFocus)
31 andreas 1659
                obj->object.widget->show();
61 andreas 1660
//            else
1661
//                mToShow.insert(std::pair<ulong, QWidget *>(handle, obj->object.widget));
5 andreas 1662
        }
1663
    }
6 andreas 1664
    else if (obj->type == OBJ_PAGE)
5 andreas 1665
    {
6 andreas 1666
        bool newBackground = false;
5 andreas 1667
 
6 andreas 1668
        if (!mBackground)
5 andreas 1669
        {
6 andreas 1670
            mBackground = new QWidget();
1671
            mBackground->setAutoFillBackground(true);
31 andreas 1672
            mBackground->setBackgroundRole(QPalette::Window);
6 andreas 1673
            mBackground->setFixedSize(obj->width, obj->height);
1674
            newBackground = true;
1675
            MSG_DEBUG("New background image added to page with size " << obj->width << " x " << obj->height);
5 andreas 1676
        }
6 andreas 1677
 
1678
        QPixmap pix(obj->width, obj->height);
1679
        pix.fill(QColor::fromRgba(qRgba(TColor::getRed(color),TColor::getGreen(color),TColor::getBlue(color),TColor::getAlpha(color))));
1680
 
14 andreas 1681
        if (image.size() > 0)
5 andreas 1682
        {
38 andreas 1683
            QImage img((unsigned char *)image.data(), width, height, rowBytes, QImage::Format_ARGB32);
1684
 
1685
            if (isScaled())
1686
                pix.convertFromImage(img.scaled(obj->width, obj->height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
1687
            else
1688
                pix.convertFromImage(img);
1689
 
26 andreas 1690
            MSG_DEBUG("Image converted. Width=" << obj->width << ", Height=" << obj->height);
6 andreas 1691
        }
5 andreas 1692
 
6 andreas 1693
        QPalette palette;
18 andreas 1694
        palette.setBrush(QPalette::Window, QBrush(pix));
6 andreas 1695
        mBackground->setPalette(palette);
1696
 
1697
        if (newBackground)
1698
            this->setCentralWidget(mBackground);
1699
 
31 andreas 1700
        if (mHasFocus)
1701
            mBackground->show();
1702
 
6 andreas 1703
        MSG_DEBUG("Background set");
5 andreas 1704
    }
14 andreas 1705
 
1706
    draw_mutex.unlock();
5 andreas 1707
}
1708
 
11 andreas 1709
void MainWindow::dropPage(ulong handle)
1710
{
14 andreas 1711
    draw_mutex.lock();
11 andreas 1712
    DECL_TRACER("MainWindow::dropPage(ulong handle)");
7 andreas 1713
 
11 andreas 1714
    removeAllChilds(handle);
1715
    removeObject(handle);
1716
 
1717
    if (mBackground)
1718
    {
1719
        delete mBackground;
1720
        mBackground = nullptr;
1721
    }
14 andreas 1722
 
1723
    draw_mutex.unlock();
11 andreas 1724
}
1725
 
1726
void MainWindow::dropSubPage(ulong handle)
1727
{
14 andreas 1728
    draw_mutex.lock();
11 andreas 1729
    DECL_TRACER("MainWindow::dropSubPage(ulong handle)");
1730
 
1731
    removeAllChilds(handle);
1732
    OBJECT_t *obj = findObject(handle);
1733
 
1734
    if (!obj)
1735
    {
1736
        MSG_WARNING("Object " << handleToString(handle) << " does not exist. Ignoring!");
14 andreas 1737
        draw_mutex.unlock();
11 andreas 1738
        return;
1739
    }
1740
 
42 andreas 1741
    startAnimation(obj, obj->animate, false);
1742
    OBJECT_t *o = mLastObject;
43 andreas 1743
 
42 andreas 1744
    if (obj->animate.hideEffect == SE_NONE || !o)
1745
    {
1746
        dropContent(obj);
1747
        removeObject(handle);
1748
    }
1749
 
14 andreas 1750
    draw_mutex.unlock();
11 andreas 1751
}
1752
 
98 andreas 1753
void MainWindow::dropButton(ulong handle)
1754
{
1755
    draw_mutex.lock();
1756
    DECL_TRACER("MainWindow::dropButton(ulong handle)");
1757
 
1758
    OBJECT_t *obj = findObject(handle);
1759
 
1760
    if (!obj)
1761
    {
1762
        MSG_WARNING("Object " << handleToString(handle) << " does not exist. Ignoring!");
1763
        draw_mutex.unlock();
1764
        return;
1765
    }
1766
 
1767
    if (obj->type == OBJ_BUTTON && obj->object.label)
1768
    {
1769
        obj->object.label->close();
1770
        obj->object.label = nullptr;
1771
    }
1772
 
1773
    removeObject(handle);
1774
    draw_mutex.unlock();
1775
}
1776
 
21 andreas 1777
void MainWindow::playVideo(ulong handle, ulong parent, int left, int top, int width, int height, const string& url, const string& user, const string& pw)
1778
{
1779
    draw_mutex.lock();
1780
    DECL_TRACER("MainWindow::playVideo(ulong handle, const string& url, const string& user, const string& pw))");
1781
 
1782
    OBJECT_t *obj = findObject(handle);
1783
    OBJECT_t *par = findObject(parent);
50 andreas 1784
    MSG_TRACE("Processing button " << handleToString(handle) << " from parent " << handleToString(parent));
21 andreas 1785
 
1786
    if (!par)
1787
    {
1788
        MSG_WARNING("Button has no parent! Ignoring it.");
1789
        draw_mutex.unlock();
1790
        return;
1791
    }
1792
 
1793
    if (!obj)
1794
    {
1795
        MSG_DEBUG("Adding new video object ...");
1796
        obj = addObject();
1797
 
1798
        if (!obj)
1799
        {
1800
            MSG_ERROR("Error creating a video object!");
1801
            TError::setError();
1802
            draw_mutex.unlock();
1803
            return;
1804
        }
1805
 
1806
        obj->type = OBJ_VIDEO;
1807
        obj->handle = handle;
1808
        obj->width = width;
1809
        obj->height = height;
1810
        obj->left = left;
1811
        obj->top = top;
1812
        obj->object.vwidget = new QVideoWidget(par->object.widget);
1813
        obj->object.vwidget->installEventFilter(this);
1814
    }
1815
    else
1816
        MSG_DEBUG("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " found!");
1817
 
1818
    QMediaPlaylist *playlist = new QMediaPlaylist;
1819
    QUrl qurl(url.c_str());
1820
 
1821
    if (!user.empty())
1822
        qurl.setUserName(user.c_str());
1823
 
1824
    if (!pw.empty())
1825
        qurl.setPassword(pw.c_str());
1826
 
1827
    playlist->addMedia(qurl);
1828
    obj->player = new QMediaPlayer;
1829
    obj->player->setPlaylist(playlist);
1830
    obj->player->setVideoOutput(obj->object.vwidget);
31 andreas 1831
 
61 andreas 1832
//    if (mHasFocus)
1833
//    {
31 andreas 1834
        obj->object.vwidget->show();
1835
        obj->player->play();
61 andreas 1836
//    }
21 andreas 1837
}
1838
 
52 andreas 1839
void MainWindow::inputText(Button::TButton* button, QByteArray buf, int width, int height, size_t pixline)
50 andreas 1840
{
1841
    DECL_TRACER("MainWindow::inputText(Button::TButton* button)");
1842
 
1843
    if (!button)
1844
    {
1845
        MSG_WARNING("No valid button!");
1846
        return;
1847
    }
1848
 
1849
    ulong handle = button->getHandle();
1850
    ulong parent = button->getParent();
1851
    OBJECT_t *obj = findObject(handle);
1852
    OBJECT_t *par = findObject(parent);
1853
    MSG_TRACE("Processing button " << handleToString(handle) << " from parent " << handleToString(parent));
1854
 
1855
    if (!par)
1856
    {
1857
        MSG_WARNING("Button has no parent! Ignoring it.");
1858
        return;
1859
    }
1860
 
1861
    if (!obj)
1862
    {
1863
        MSG_DEBUG("Adding new input object ...");
1864
        obj = addObject();
1865
 
1866
        if (!obj)
1867
        {
1868
            MSG_ERROR("Error creating an input object!");
1869
            TError::setError();
1870
            return;
1871
        }
1872
 
1873
        obj->type = OBJ_INPUT;
1874
        obj->handle = handle;
52 andreas 1875
        obj->width = scale(width);
1876
        obj->height = scale(height);
50 andreas 1877
        obj->left = scale(button->getLeftPosition());
1878
        obj->top = scale(button->getTopPosition());
51 andreas 1879
 
1880
        if (button->isSingleLine())
1881
        {
1882
            obj->object.linetext = new QLineEdit(button->getText().c_str(), par->object.widget);
1883
            obj->object.linetext->setFixedSize(obj->width, obj->height);
1884
            obj->object.linetext->move(obj->left, obj->top);
52 andreas 1885
//            obj->object.linetext->setAutoFillBackground(true);
51 andreas 1886
            obj->object.linetext->installEventFilter(this);
1887
            obj->object.linetext->connect(obj->object.linetext, &QLineEdit::editingFinished, this, &MainWindow::textSingleLineReturn);
1888
            obj->wid = obj->object.linetext->winId();
1889
        }
1890
        else
1891
        {
1892
            obj->object.multitext = new QTextEdit(button->getText().c_str(), par->object.widget);
1893
            obj->object.multitext->setFixedSize(obj->width, obj->height);
1894
            obj->object.multitext->move(obj->left, obj->top);
52 andreas 1895
//            obj->object.multitext->setAutoFillBackground(true);
51 andreas 1896
            obj->object.multitext->installEventFilter(this);
1897
            obj->object.multitext->connect(obj->object.multitext, &QTextEdit::textChanged, this, &MainWindow::textChangedMultiLine);
1898
            obj->wid = obj->object.multitext->winId();
1899
        }
1900
 
52 andreas 1901
        if (!buf.size() || pixline == 0)
51 andreas 1902
        {
1903
            MSG_ERROR("No image!");
1904
            TError::setError();
1905
            return;
1906
        }
1907
 
52 andreas 1908
        MSG_DEBUG("Background image size: " << width << " x " << height << ", rowBytes: " << pixline);
1909
        QPixmap pix(width, height);
1910
        QImage img((uchar *)buf.data(), width, height, QImage::Format_ARGB32);
50 andreas 1911
 
1912
        if (isScaled())
52 andreas 1913
            pix.convertFromImage(img.scaled(scale(width), scale(height), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
50 andreas 1914
        else
1915
            pix.convertFromImage(img);
1916
 
1917
        // Load the font
1918
        FONT_T font = button->getFont();
1919
        int fontID = 0;
51 andreas 1920
        vector<string> fontList = TFont::getFontPathList();
1921
        vector<string>::iterator iter;
1922
        string ffile;
50 andreas 1923
 
51 andreas 1924
        for (iter = fontList.begin(); iter != fontList.end(); ++iter)
50 andreas 1925
        {
51 andreas 1926
            TValidateFile vf;
50 andreas 1927
 
51 andreas 1928
            if (!vf.isValidFile(*iter + "/" + font.file))
1929
                continue;
1930
 
1931
            ffile = *iter + "/" + font.file;
1932
            break;
50 andreas 1933
        }
1934
 
51 andreas 1935
        if (ffile.empty())
1936
        {
1937
            MSG_ERROR("Font " << font.file << " doesn't exists!");
1938
            return;
1939
        }
1940
 
50 andreas 1941
        if ((fontID = QFontDatabase::addApplicationFont(ffile.c_str())) == -1)
1942
        {
1943
            MSG_ERROR("Font " << ffile << " could not be loaded!");
1944
            TError::setError();
1945
            return;
1946
        }
1947
 
1948
        QFont ft;
1949
        ft.setFamily(font.name.c_str());
1950
        ft.setPointSize(font.size);
51 andreas 1951
        MSG_DEBUG("Using font \"" << font.name << "\" with size " << font.size << "pt.");
50 andreas 1952
 
1953
        switch (button->getFontStyle())
1954
        {
1955
            case FONT_BOLD:     ft.setBold(true); break;
1956
            case FONT_ITALIC:   ft.setItalic(true); break;
1957
            case FONT_BOLD_ITALIC:
1958
                ft.setBold(true);
1959
                ft.setItalic(true);
1960
                break;
1961
 
1962
            default:
1963
                ft.setBold(false);
1964
                ft.setItalic(false);
1965
        }
1966
 
52 andreas 1967
        QPalette palette;
50 andreas 1968
        TColor::COLOR_T textColor = TColor::getAMXColor(button->getTextColor());
52 andreas 1969
        TColor::COLOR_T fillColor = TColor::getAMXColor(button->getFillColor());
51 andreas 1970
        QColor txcolor(QColor::fromRgba(qRgba(textColor.red, textColor.green, textColor.blue, textColor.alpha)));
52 andreas 1971
        QColor cfcolor(QColor::fromRgba(qRgba(fillColor.red, fillColor.green, fillColor.blue, fillColor.alpha)));
1972
        palette.setColor(QPalette::Base, cfcolor);
51 andreas 1973
        palette.setColor(QPalette::Text, txcolor);
52 andreas 1974
        //        pix.save("frame.png");
51 andreas 1975
 
1976
        if (button->isSingleLine())
1977
        {
1978
            MSG_DEBUG("Initializing a single line ...");
53 andreas 1979
//            palette.setBrush(QPalette::Base, QBrush(pix));
52 andreas 1980
            obj->object.linetext->setFont(ft);
51 andreas 1981
            obj->object.linetext->setPalette(palette);
1982
            obj->object.linetext->setMaxLength(button->getTextMaxChars());
52 andreas 1983
//            obj->object.linetext->setFrame(false);
51 andreas 1984
            obj->object.linetext->setText(button->getText().c_str());
1985
            obj->object.linetext->show();
1986
        }
1987
        else
1988
        {
1989
            MSG_DEBUG("Initializing a multiline text area ...");
53 andreas 1990
            palette.setBrush(QPalette::Base, QBrush(pix));
51 andreas 1991
            obj->object.multitext->setPalette(palette);
1992
            obj->object.multitext->setFont(ft);
1993
            obj->object.multitext->setAcceptRichText(false);
1994
            obj->object.multitext->setText(button->getText().c_str());
1995
 
1996
            if (button->getTextWordWrap())
1997
                obj->object.multitext->setWordWrapMode(QTextOption::WordWrap);
1998
            else
1999
                obj->object.multitext->setWordWrapMode(QTextOption::NoWrap);
2000
 
2001
            obj->object.multitext->show();
2002
        }
50 andreas 2003
    }
2004
    else
2005
        MSG_DEBUG("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " found!");
2006
}
62 andreas 2007
 
63 andreas 2008
void MainWindow::showKeyboard(const std::string& init, const std::string& prompt, bool priv)
31 andreas 2009
{
63 andreas 2010
    DECL_TRACER("MainWindow::showKeyboard(std::string &init, std::string &prompt, bool priv)");
31 andreas 2011
 
63 andreas 2012
    if (mKeyboard)
2013
        return;
2014
 
2015
    mQKeyboard = new TQKeyboard(init, prompt, this);
2016
    mKeyboard = true;
62 andreas 2017
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
65 andreas 2018
    mQKeyboard->setScaleFactor(mScaleFactor);
62 andreas 2019
#endif
63 andreas 2020
    mQKeyboard->setPrivate(priv);
2021
    mQKeyboard->doResize();
2022
    mQKeyboard->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::FramelessWindowHint);
2023
    int ret = mQKeyboard->exec();
31 andreas 2024
 
62 andreas 2025
    if (ret == QDialog::Accepted)
2026
    {
2027
        string text = "KEYB-";
63 andreas 2028
        text.append(mQKeyboard->getText());
62 andreas 2029
 
2030
        if (gPageManager)
2031
            gPageManager->sendKeyboard(text);
2032
    }
2033
    else
2034
    {
2035
        string text = "KEYB-ABORT";
2036
 
2037
        if (gPageManager)
2038
            gPageManager->sendKeyboard(text);
2039
    }
2040
 
63 andreas 2041
    delete mQKeyboard;
2042
    mQKeyboard = nullptr;
2043
    mKeyboard = false;
31 andreas 2044
}
62 andreas 2045
 
63 andreas 2046
void MainWindow::showKeypad(const std::string& init, const std::string& prompt, bool priv)
62 andreas 2047
{
63 andreas 2048
    DECL_TRACER("MainWindow::showKeypad(std::string& init, std::string& prompt, bool priv)");
62 andreas 2049
 
65 andreas 2050
    if (mKeypad)
63 andreas 2051
        return;
2052
 
2053
    mQKeypad = new TQKeypad(init, prompt, this);
65 andreas 2054
    mKeypad = true;
62 andreas 2055
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
63 andreas 2056
    mQKeypad->setScaleFactor(mScaleFactor);
65 andreas 2057
#endif
2058
    mQKeypad->setPrivate(priv);
63 andreas 2059
    mQKeypad->doResize();
2060
    mQKeypad->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::FramelessWindowHint);
65 andreas 2061
    int ret = mQKeypad->exec();
62 andreas 2062
 
2063
    if (ret == QDialog::Accepted)
2064
    {
2065
        string text = "KEYP-";
63 andreas 2066
        text.append(mQKeypad->getText());
62 andreas 2067
 
2068
        if (gPageManager)
2069
            gPageManager->sendKeypad(text);
2070
    }
2071
    else
2072
    {
2073
        string text = "KEYP-ABORT";
2074
 
2075
        if (gPageManager)
2076
            gPageManager->sendKeypad(text);
2077
    }
2078
 
63 andreas 2079
    delete mQKeypad;
2080
    mQKeypad = nullptr;
65 andreas 2081
    mKeypad = false;
62 andreas 2082
}
2083
 
63 andreas 2084
void MainWindow::resetKeyboard()
2085
{
2086
    DECL_TRACER("MainWindow::resetKeyboard()");
2087
 
2088
    if (mQKeyboard)
2089
        mQKeyboard->reject();
2090
 
2091
    if (mQKeypad)
2092
        mQKeyboard->reject();
2093
}
2094
 
64 andreas 2095
void MainWindow::showSetup()
2096
{
2097
    DECL_TRACER("MainWindow::showSetup()");
2098
 
2099
    settings();
2100
}
2101
 
71 andreas 2102
void MainWindow::playSound(const string& file)
2103
{
2104
    DECL_TRACER("MainWindow::playSound(const string& file)");
2105
 
2106
    MSG_DEBUG("Playing file " << file);
2107
    QSound::play(file.c_str());
2108
}
2109
 
31 andreas 2110
void MainWindow::playShowList()
2111
{
2112
    DECL_TRACER("MainWindow::playShowList()");
2113
 
61 andreas 2114
    _EMIT_TYPE_t etype = getNextType();
2115
 
2116
    while (etype != ET_NONE)
2117
    {
2118
        ulong handle = 0;
2119
        ulong parent = 0;
2120
        unsigned char *buffer;
2121
        int pixline = 0;
2122
        int left = 0;
2123
        int top = 0;
2124
        int width = 0;
2125
        int height = 0;
2126
        unsigned char *image;
2127
        size_t size = 0;
2128
        size_t rowBytes = 0;
2129
        ulong color = 0;
2130
        ANIMATION_t animate;
2131
        std::string url;
2132
        std::string user;
2133
        std::string pw;
2134
        Button::TButton *button;
2135
        Button::BITMAP_t bm;
2136
 
2137
        switch(etype)
2138
        {
2139
            case ET_BACKGROUND:
2140
                if (getBackground(&handle, &image, &size, &rowBytes, &width, &height, &color))
2141
                {
2142
                    QByteArray buf;
2143
 
2144
                    if (image && size > 0)
2145
                        buf.insert(0, (const char *)image, size);
2146
 
2147
                    emit sigSetBackground(handle, buf, rowBytes, width, height, color);
2148
                }
2149
            break;
2150
 
2151
            case ET_BUTTON:
2152
                if (getButton(&handle, &parent, &buffer, &pixline, &left, &top, &width, &height))
2153
                {
2154
                    QByteArray buf;
2155
 
2156
                    if (buffer && pixline > 0)
2157
                    {
2158
                        size_t size = width * height * (pixline / width);
2159
                        MSG_DEBUG("Buffer size=" << size << ", width=" << width << ", height=" << height << ", left=" << left << ", top=" << top);
2160
                        buf.insert(0, (const char *)buffer, size);
2161
                    }
2162
 
2163
                    emit sigDisplayButton(handle, parent, buf, width, height, pixline, left, top);
2164
                }
2165
            break;
2166
 
2167
            case ET_INTEXT:
2168
                if (getInText(&handle, &button, &bm))
2169
                {
2170
                    QByteArray buf;
2171
 
2172
                    if (bm.buffer && bm.rowBytes > 0)
2173
                    {
2174
                        size_t size = bm.width * bm.height * (bm.rowBytes / bm.width);
2175
                        buf.insert(0, (const char *)bm.buffer, size);
2176
                    }
2177
 
2178
                    emit sigInputText(button, buf, bm.width, bm.height, bm.rowBytes);
2179
                }
2180
            break;
2181
 
2182
            case ET_PAGE:
2183
                if (getPage(&handle, &width, &height))
2184
                {
2185
                    if (isDeleted())
2186
                        emit sigDropPage(handle);
2187
                    else
2188
                        emit sigSetPage(handle, width, height);
2189
                }
2190
            break;
2191
 
2192
            case ET_SUBPAGE:
2193
                if (getSubPage(&handle, &left, &top, &width, &height, &animate))
2194
                {
2195
                    if (isDeleted())
2196
                        emit sigDropSubPage(handle);
2197
                    else
2198
                        emit sigSetSubPage(handle, left, top, width, height, animate);
2199
                }
2200
            break;
2201
 
2202
            case ET_VIDEO:
2203
                if (getVideo(&handle, &parent, &left, &top, &width, &height, &url, &user, &pw))
2204
                {
2205
                    emit sigPlayVideo(handle, parent, left, top, width, height, url, user, pw);
2206
                }
2207
            break;
2208
 
2209
            default:
2210
                MSG_WARNING("Type " << etype << " is currently not supported!");
2211
        }
2212
 
2213
        dropType(etype);
2214
        etype = getNextType();
2215
    }
2216
/*
31 andreas 2217
    std::map<ulong, QWidget *>::iterator iter;
2218
 
2219
    for (iter = mToShow.begin(); iter != mToShow.end(); ++iter)
2220
    {
2221
        OBJECT_t *obj = findObject(iter->first);
2222
 
2223
        if (obj)
2224
            iter->second->show();
2225
    }
2226
 
2227
    mToShow.clear();
61 andreas 2228
*/
31 andreas 2229
}
2230
 
42 andreas 2231
 
38 andreas 2232
int MainWindow::scale(int value)
2233
{
2234
    if (value <= 0 || mScaleFactor == 1.0)
2235
        return value;
2236
 
2237
    return (int)((double)value * mScaleFactor);
2238
}
2239
 
42 andreas 2240
void MainWindow::startAnimation(OBJECT_t* obj, ANIMATION_t& ani, bool in)
2241
{
2242
    DECL_TRACER("MainWindow::startAnimation(OBJECT_t* obj, ANIMATION_t& ani)");
43 andreas 2243
 
42 andreas 2244
    SHOWEFFECT_t effect;
2245
    int scLeft = obj->left;
2246
    int scTop = obj->top;
2247
    int scWidth = obj->width;
2248
    int scHeight = obj->height;
2249
    mLastObject = nullptr;
43 andreas 2250
 
42 andreas 2251
    obj->animate = ani;
43 andreas 2252
 
42 andreas 2253
    if (in)
2254
        effect = ani.showEffect;
2255
    else
2256
        effect = ani.hideEffect;
2257
 
54 andreas 2258
    if (effect == SE_NONE)
2259
        return;
43 andreas 2260
 
58 andreas 2261
    if (effect == SE_FADE)
2262
    {
2263
        QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(obj->object.widget);
2264
        obj->object.widget->setGraphicsEffect(effect);
2265
        obj->animation = new QPropertyAnimation(effect, "opacity");
2266
    }
2267
    else
2268
    {
2269
        obj->animation = new QPropertyAnimation(obj->object.widget);
2270
        obj->animation->setTargetObject(obj->object.widget);
2271
    }
42 andreas 2272
 
54 andreas 2273
    if (in)
101 andreas 2274
        obj->animation->setDuration(ani.showTime * 100);    // convert 10th of seconds into milliseconds
54 andreas 2275
    else
101 andreas 2276
        obj->animation->setDuration(ani.hideTime * 100);    // convert 10th of seconds into milliseconds
43 andreas 2277
 
54 andreas 2278
    switch(effect)
2279
    {
2280
        case SE_SLIDE_BOTTOM_FADE:
2281
        case SE_SLIDE_BOTTOM:
2282
            obj->animation->setPropertyName("geometry");
42 andreas 2283
 
54 andreas 2284
            if (in)
2285
            {
2286
                obj->animation->setStartValue(QRect(scLeft, scTop + (scHeight * 2), scWidth, scHeight));
2287
                obj->animation->setEndValue(QRect(scLeft, scTop, scWidth, scHeight));
2288
            }
2289
            else
2290
            {
2291
                obj->animation->setStartValue(QRect(scLeft, scTop, scWidth, scHeight));
2292
                obj->animation->setEndValue(QRect(scLeft, scTop + (scHeight * 2), scWidth, scHeight));
2293
                obj->remove = true;
2294
                mLastObject = obj;
2295
                connect(obj->animation, &QPropertyAnimation::finished, this, &MainWindow::animationFinished);
2296
            }
42 andreas 2297
 
54 andreas 2298
            obj->animation->start();
2299
        break;
43 andreas 2300
 
54 andreas 2301
        case SE_SLIDE_LEFT_FADE:
2302
        case SE_SLIDE_LEFT:
2303
            obj->animation->setPropertyName("geometry");
43 andreas 2304
 
54 andreas 2305
            if (in)
2306
            {
2307
                obj->animation->setStartValue(QRect(scLeft - scWidth, scTop, scWidth, scHeight));
2308
                obj->animation->setEndValue(QRect(scLeft, scTop, scWidth, scHeight));
2309
            }
2310
            else
2311
            {
2312
                obj->animation->setStartValue(QRect(scLeft, scTop, scWidth, scHeight));
2313
                obj->animation->setEndValue(QRect(scLeft - scWidth, scTop, scWidth, scHeight));
2314
                obj->remove = true;
2315
                mLastObject = obj;
2316
                connect(obj->animation, &QPropertyAnimation::finished, this, &MainWindow::animationFinished);
2317
            }
42 andreas 2318
 
54 andreas 2319
            obj->animation->start();
2320
        break;
43 andreas 2321
 
54 andreas 2322
        case SE_SLIDE_RIGHT_FADE:
2323
        case SE_SLIDE_RIGHT:
2324
            obj->animation->setPropertyName("geometry");
43 andreas 2325
 
54 andreas 2326
            if (in)
2327
            {
2328
                obj->animation->setStartValue(QRect(scLeft + scWidth, scTop, scWidth, scHeight));
2329
                obj->animation->setEndValue(QRect(scLeft, scTop, scWidth, scHeight));
2330
            }
2331
            else
2332
            {
2333
                obj->animation->setStartValue(QRect(scLeft, scTop, scWidth, scHeight));
2334
                obj->animation->setEndValue(QRect(scLeft + scWidth, scTop, scWidth, scHeight));
2335
                obj->remove = true;
2336
                mLastObject = obj;
2337
                connect(obj->animation, &QPropertyAnimation::finished, this, &MainWindow::animationFinished);
2338
            }
42 andreas 2339
 
54 andreas 2340
            obj->animation->start();
2341
        break;
43 andreas 2342
 
54 andreas 2343
        case SE_SLIDE_TOP_FADE:
2344
        case SE_SLIDE_TOP:
2345
            obj->animation->setPropertyName("geometry");
43 andreas 2346
 
54 andreas 2347
            if (in)
2348
            {
2349
                obj->animation->setStartValue(QRect(scLeft, scTop - scHeight, scWidth, scHeight));
2350
                obj->animation->setEndValue(QRect(scLeft, scTop, scWidth, scHeight));
2351
            }
2352
            else
2353
            {
2354
                obj->animation->setStartValue(QRect(scLeft, scTop, scWidth, scHeight));
2355
                obj->animation->setEndValue(QRect(scLeft, scTop - scHeight, scWidth, scHeight));
2356
                obj->remove = true;
2357
                mLastObject = obj;
2358
                connect(obj->animation, &QPropertyAnimation::finished, this, &MainWindow::animationFinished);
2359
            }
43 andreas 2360
 
54 andreas 2361
            obj->animation->start();
2362
        break;
2363
 
58 andreas 2364
        case SE_FADE:
2365
            if (in)
2366
            {
2367
                obj->object.widget->setWindowOpacity(0.0);
2368
                obj->object.widget->show();
2369
                obj->animation->setStartValue(0.0);
2370
                obj->animation->setEndValue(1.0);
2371
            }
2372
            else
2373
            {
2374
                obj->animation->setStartValue(1.0);
2375
                obj->animation->setEndValue(0.0);
2376
                obj->remove = true;
2377
                mLastObject = obj;
2378
                connect(obj->animation, &QPropertyAnimation::finished, this, &MainWindow::animationFinished);
2379
            }
2380
 
2381
            obj->animation->setEasingCurve(QEasingCurve::Linear);
2382
            obj->animation->start();
2383
        break;
2384
 
54 andreas 2385
        default:
2386
            MSG_WARNING("Subpage effect " << ani.showEffect << " is not supported.");
42 andreas 2387
    }
2388
}
2389
 
2 andreas 2390
#ifndef QT_NO_SESSIONMANAGER
2391
void MainWindow::commitData(QSessionManager &manager)
2392
{
5 andreas 2393
    if (manager.allowsInteraction())
2394
    {
2395
        if (!settingsChanged)
2396
            manager.cancel();
2397
    }
2398
    else
2399
    {
2400
        if (settingsChanged)
2401
            writeSettings();
2402
    }
2 andreas 2403
}
5 andreas 2404
#endif