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