Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
408 andreas 1
/*
258 andreas 2
 * Copyright (C) 2020 to 2023 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>
264 andreas 35
#include <QStackedWidget>
10 andreas 36
#include <QMouseEvent>
15 andreas 37
#include <QMoveEvent>
59 andreas 38
#include <QTouchEvent>
5 andreas 39
#include <QPalette>
9 andreas 40
#include <QPixmap>
7 andreas 41
#include <QFont>
42
#include <QFontDatabase>
21 andreas 43
#include <QtMultimediaWidgets/QVideoWidget>
44
#include <QtMultimedia/QMediaPlayer>
264 andreas 45
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
181 andreas 46
#   include <QtMultimedia/QMediaPlaylist>
47
#else
48
#   include <QAudioOutput>
346 andreas 49
#   include <QMediaMetaData>
181 andreas 50
#endif
205 andreas 51
#include <QListWidget>
24 andreas 52
#include <QLayout>
40 andreas 53
#include <QSizePolicy>
21 andreas 54
#include <QUrl>
13 andreas 55
#include <QThread>
258 andreas 56
#ifdef Q_OS_IOS
368 andreas 57
#include <QtSensors/QOrientationSensor>
253 andreas 58
#endif
264 andreas 59
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
181 andreas 60
#   include <QSound>
267 andreas 61
#if defined(Q_OS_IOS) || defined(Q_OS_ANDROID)
181 andreas 62
#   include <QtSensors/QOrientationSensor>
217 andreas 63
#   include <qpa/qplatformscreen.h>
267 andreas 64
#endif
187 andreas 65
#else
267 andreas 66
#   include <QPlainTextEdit>
67
#if defined(Q_OS_IOS) || defined(Q_OS_ANDROID)
254 andreas 68
#   include <QGeoPositionInfoSource>
217 andreas 69
#   include <QtSensors/QOrientationReading>
386 andreas 70
#   include <QPermissions>
181 andreas 71
#endif
267 andreas 72
#endif
264 andreas 73
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) && defined(Q_OS_ANDROID)
183 andreas 74
#include <QtAndroidExtras/QAndroidJniObject>
211 andreas 75
#include <QtAndroidExtras/QtAndroid>
88 andreas 76
#endif
5 andreas 77
#include <functional>
14 andreas 78
#include <mutex>
255 andreas 79
#ifdef Q_OS_ANDROID
23 andreas 80
#include <android/log.h>
81
#endif
4 andreas 82
#include "tpagemanager.h"
2 andreas 83
#include "tqtmain.h"
84
#include "tconfig.h"
251 andreas 85
#if !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID)
2 andreas 86
#include "tqtsettings.h"
213 andreas 87
#endif
62 andreas 88
#include "tqkeyboard.h"
89
#include "tqkeypad.h"
5 andreas 90
#include "tcolor.h"
92 andreas 91
#include "texcept.h"
118 andreas 92
#include "ttpinit.h"
179 andreas 93
#include "tqdownload.h"
140 andreas 94
#include "tqtphone.h"
190 andreas 95
#include "tqeditline.h"
396 andreas 96
#include "tqtinputline.h"
391 andreas 97
#include "tqmarquee.h"
260 andreas 98
#include "tqtwait.h"
211 andreas 99
#include "terror.h"
270 andreas 100
#include "tresources.h"
285 andreas 101
#include "tqscrollarea.h"
292 andreas 102
#include "tlock.h"
243 andreas 103
#ifdef Q_OS_IOS
250 andreas 104
#include "ios/QASettings.h"
105
#include "ios/tiosrotate.h"
106
#include "ios/tiosbattery.h"
243 andreas 107
#endif
326 andreas 108
#if TESTMODE == 1
109
#include "testmode.h"
110
#endif
2 andreas 111
 
209 andreas 112
#if __cplusplus < 201402L
113
#   error "This module requires at least C++14 standard!"
386 andreas 114
#else   // __cplusplus < 201402L
209 andreas 115
#   if __cplusplus < 201703L
116
#       include <experimental/filesystem>
117
namespace fs = std::experimental::filesystem;
118
#       warning "Support for C++14 and experimental filesystem will be removed in a future version!"
386 andreas 119
#   else    // __cplusplus < 201703L
209 andreas 120
#       include <filesystem>
121
#       ifdef __ANDROID__
122
namespace fs = std::__fs::filesystem;
386 andreas 123
#       else    // __ANDROID__
209 andreas 124
namespace fs = std::filesystem;
386 andreas 125
#       endif   // __ANDROID__
126
#   endif   // __cplusplus < 201703L
127
#endif  // __cplusplus < 201402L
209 andreas 128
 
44 andreas 129
 
130
extern amx::TAmxNet *gAmxNet;                   //!< Pointer to the class running the thread which handles the communication with the controller.
90 andreas 131
extern bool _restart_;                          //!< If this is set to true then the whole program will start over.
92 andreas 132
extern TPageManager *gPageManager;              //!< The pointer to the global defined main class.
38 andreas 133
static bool isRunning = false;                  //!< TRUE = the pageManager was started.
100 andreas 134
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
44 andreas 135
static double gScale = 1.0;                     //!< Global variable holding the scale factor.
136
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.
155 andreas 137
std::atomic<double> mScaleFactorW{1.0};
138
std::atomic<double> mScaleFactorH{1.0};
139
int gScreenWidth{0};
140
int gScreenHeight{0};
264 andreas 141
bool isPortrait{false};
100 andreas 142
#endif
21 andreas 143
 
5 andreas 144
using std::bind;
296 andreas 145
using std::map;
61 andreas 146
using std::pair;
21 andreas 147
using std::string;
51 andreas 148
using std::vector;
5 andreas 149
 
398 andreas 150
static string _NO_OBJECT = "The global class TObject is not available!";
107 andreas 151
 
21 andreas 152
/**
153
 * @brief qtmain is used here as the entry point for the surface.
154
 *
155
 * The main entry function parses the command line parameters, if there were
156
 * any and sets the basic attributes. It creates the main window and starts the
157
 * application.
158
 *
159
 * @param argc      The number of command line arguments
160
 * @param argv      A pointer to a 2 dimensional array containing the command
161
 *                  line parameters.
162
 * @param pmanager  A pointer to the page manager class which is the main class
163
 *                  managing everything.
164
 *
165
 * @return If no errors occured it returns 0.
166
 */
3 andreas 167
int qtmain(int argc, char **argv, TPageManager *pmanager)
2 andreas 168
{
31 andreas 169
    DECL_TRACER("qtmain(int argc, char **argv, TPageManager *pmanager)");
2 andreas 170
 
58 andreas 171
    if (!pmanager)
172
    {
173
        MSG_ERROR("Fatal: No pointer to the page manager received!");
174
        return 1;
175
    }
176
 
299 andreas 177
    gPageManager = pmanager;
88 andreas 178
#ifdef __ANDROID__
179
    MSG_INFO("Android API version: " << __ANDROID_API__);
3 andreas 180
 
256 andreas 181
#if __ANDROID_API__ < 30
258 andreas 182
#warning "The Android API version is less than 30! Some functions may not work!"
256 andreas 183
#endif  // __ANDROID_API__
264 andreas 184
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
256 andreas 185
    QAndroidJniObject activity = QtAndroid::androidActivity();
186
    QAndroidJniObject::callStaticMethod<void>("org/qtproject/theosys/HideToolbar", "hide", "(Landroid/app/Activity;Z)V", activity.object(), true);
187
#else
188
    QJniObject activity = QNativeInterface::QAndroidApplication::context();
189
    QJniObject::callStaticMethod<void>("org/qtproject/theosys/HideToolbar", "hide", "(Landroid/app/Activity;Z)V", activity.object(), true);
190
#endif  // QT5_LINUX
191
#endif  // __ANDROID__
192
 
264 andreas 193
#if defined(Q_OS_ANDROID)
38 andreas 194
    QApplication::setAttribute(Qt::AA_ForceRasterWidgets);
264 andreas 195
//    QApplication::setAttribute(Qt::AA_Use96Dpi);
178 andreas 196
//    QApplication::setAttribute(Qt::AA_DontUseNativeDialogs);
2 andreas 197
#endif
198
 
5 andreas 199
    QApplication app(argc, argv);
58 andreas 200
    // Set the orientation
201
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
202
    QScreen *screen = QGuiApplication::primaryScreen();
203
 
204
    if (!screen)
205
    {
206
        MSG_ERROR("Couldn't determine the primary screen!")
207
        return 1;
208
    }
264 andreas 209
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
151 andreas 210
    if (pmanager->getSettings()->isPortrait())  // portrait?
88 andreas 211
    {
212
        MSG_INFO("Orientation set to portrait mode.");
264 andreas 213
        screen->setOrientationUpdateMask(Qt::PortraitOrientation);
88 andreas 214
    }
215
    else
216
    {
217
        MSG_INFO("Orientation set to landscape mode.");
264 andreas 218
        screen->setOrientationUpdateMask(Qt::LandscapeOrientation);
88 andreas 219
    }
264 andreas 220
#endif  // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
38 andreas 221
    double scale = 1.0;
212 andreas 222
    double setupScaleFactor = 1.0;
24 andreas 223
    // Calculate the scale factor
224
    if (TConfig::getScale())
225
    {
43 andreas 226
        // Because we've no window here we can not know on which screen, if
227
        // there are more than one, the application will start. Because on a
228
        // mobile mostly no external screen is connected, we take always the
229
        // resolution of the first (built in) screen.
230
        // TODO: Find a way to get the screen the application will start and
231
        // take this screen to calculate the scale factor.
264 andreas 232
        QRect screenGeometry = screen->availableGeometry();
88 andreas 233
        double width = 0.0;
234
        double height = 0.0;
212 andreas 235
        double sysWidth = 0.0;
236
        double sysHeight = 0.0;
264 andreas 237
        gScreenWidth = std::max(screenGeometry.width(), screenGeometry.height());
238
        gScreenHeight = std::min(screenGeometry.height(), screenGeometry.width());
217 andreas 239
 
264 andreas 240
        if (screenGeometry.width() > screenGeometry.height())
241
            isPortrait = false;
242
        else
243
            isPortrait = true;
217 andreas 244
 
245
        int minWidth = pmanager->getSettings()->getWidth();
24 andreas 246
        int minHeight = pmanager->getSettings()->getHeight();
217 andreas 247
        int minSysWidth = pmanager->getSystemSettings()->getWidth();
212 andreas 248
        int minSysHeight = pmanager->getSystemSettings()->getHeight();
88 andreas 249
 
151 andreas 250
        if (pmanager->getSettings()->isPortrait())  // portrait?
88 andreas 251
        {
217 andreas 252
            width = std::min(gScreenWidth, gScreenHeight);
253
            height = std::max(gScreenHeight, gScreenWidth);
88 andreas 254
        }
255
        else
256
        {
217 andreas 257
            width = std::max(gScreenWidth, gScreenHeight);
258
            height = std::min(gScreenHeight, gScreenWidth);
88 andreas 259
        }
212 andreas 260
        // The setup pages are always landscape
217 andreas 261
        sysWidth = std::max(gScreenWidth, gScreenHeight);
262
        sysHeight = std::min(gScreenHeight, gScreenWidth);
88 andreas 263
 
156 andreas 264
        if (!TConfig::getToolbarSuppress() && TConfig::getToolbarForce())
120 andreas 265
            minWidth += 48;
266
 
31 andreas 267
        MSG_INFO("Dimension of AMX screen:" << minWidth << " x " << minHeight);
88 andreas 268
        MSG_INFO("Screen size: " << width << " x " << height);
43 andreas 269
        // The scale factor is always calculated in difference to the prefered
270
        // size of the original AMX panel.
212 andreas 271
        mScaleFactorW = width / (double)minWidth;
272
        mScaleFactorH = height / (double)minHeight;
217 andreas 273
        double scaleFactorW = sysWidth / (double)minSysWidth;
274
        double scaleFactorH = sysHeight / (double)minSysHeight;
155 andreas 275
        scale = std::min(mScaleFactorW, mScaleFactorH);
212 andreas 276
        setupScaleFactor = std::min(scaleFactorW, scaleFactorH);
235 andreas 277
#ifdef __ANDROID__
212 andreas 278
        __android_log_print(ANDROID_LOG_DEBUG, "tpanel", "scale: %f (Screen: %1.0fx%1.0f, Page: %dx%d)", scale, width, height, minWidth, minHeight);
279
        __android_log_print(ANDROID_LOG_DEBUG, "tpanel", "setupScaleFactor: %f (Screen: %1.0fx%1.0f, Page: %dx%d)", setupScaleFactor, sysWidth, sysHeight, minSysWidth, minSysHeight);
235 andreas 280
#endif
43 andreas 281
        gScale = scale;     // The calculated scale factor
88 andreas 282
        gFullWidth = width;
155 andreas 283
        MSG_INFO("Calculated scale factor: " << scale);
43 andreas 284
        // This preprocessor variable allows the scaling to be done by the Skia
285
        // library, which is used to draw everything. In comparison to Qt this
286
        // library is a bit slower and sometimes does not honor the aspect ratio
44 andreas 287
        // correct. But in case there is another framework than Qt in use, this
43 andreas 288
        // could be necessary.
289
#ifdef _SCALE_SKIA_
26 andreas 290
        if (scale != 0.0)
291
        {
292
            pmanager->setScaleFactor(scale);
31 andreas 293
            MSG_INFO("Scale factor: " << scale);
26 andreas 294
        }
31 andreas 295
 
296
        if (scaleW != 0.0)
297
            pmanager->setScaleFactorWidth(scaleW);
298
 
299
        if (scaleH != 0.0)
300
            pmanager->setScaleFactorHeight(scaleH);
58 andreas 301
#endif  // _SCALE_SKIA_
24 andreas 302
    }
58 andreas 303
#endif  // defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
235 andreas 304
#if not defined(Q_OS_ANDROID) && not defined(Q_OS_IOS)
213 andreas 305
    double setupScaleFactor = 1.0;
222 andreas 306
 
307
    if (pmanager->getSettings() != pmanager->getSystemSettings())
211 andreas 308
    {
212 andreas 309
        double width = 0.0;
310
        double height = 0.0;
217 andreas 311
        int minWidth = pmanager->getSystemSettings()->getWidth();
212 andreas 312
        int minHeight = pmanager->getSystemSettings()->getHeight();
313
 
314
        if (!TConfig::getToolbarSuppress() && TConfig::getToolbarForce())
315
            minWidth += 48;
316
 
219 andreas 317
        width = std::max(pmanager->getSettings()->getWidth(), pmanager->getSettings()->getHeight());
318
        height = std::min(pmanager->getSettings()->getHeight(), pmanager->getSettings()->getWidth());
222 andreas 319
 
212 andreas 320
        MSG_INFO("Dimension of AMX screen:" << minWidth << " x " << minHeight);
321
        MSG_INFO("Screen size: " << width << " x " << height);
322
        // The scale factor is always calculated in difference to the prefered
323
        // size of the original AMX panel.
398 andreas 324
        double scaleFactorW = width / static_cast<double>(minWidth);
325
        double scaleFactorH = height / static_cast<double>(minHeight);
212 andreas 326
        setupScaleFactor = std::min(scaleFactorW, scaleFactorH);
265 andreas 327
        MSG_DEBUG("Scale factor for setup screen: " << setupScaleFactor);
198 andreas 328
    }
222 andreas 329
#endif
24 andreas 330
    // Initialize the application
164 andreas 331
    pmanager->setDPI(QGuiApplication::primaryScreen()->logicalDotsPerInch());
5 andreas 332
    QCoreApplication::setOrganizationName(TConfig::getProgName().c_str());
164 andreas 333
    QCoreApplication::setApplicationName("TPanel");
24 andreas 334
    QCoreApplication::setApplicationVersion(VERSION_STRING());
5 andreas 335
    QCommandLineParser parser;
336
    parser.setApplicationDescription(QCoreApplication::applicationName());
337
    parser.addHelpOption();
338
    parser.addVersionOption();
339
    parser.process(app);
2 andreas 340
 
5 andreas 341
    MainWindow mainWin;
58 andreas 342
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
343
#   ifndef _SCALE_SKIA_
43 andreas 344
    if (TConfig::getScale() && scale != 1.0)
38 andreas 345
        mainWin.setScaleFactor(scale);
58 andreas 346
#   endif   // _SCALE_SKIA_
347
#endif  // defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
22 andreas 348
    mainWin.setConfigFile(TConfig::getConfigPath() + "/" + TConfig::getConfigFileName());
299 andreas 349
    QPalette palette(mainWin.palette());
350
    palette.setColor(QPalette::Window, Qt::black);  // Keep the background black. Helps to save battery on OLED displays.
351
    mainWin.setPalette(palette);
58 andreas 352
    mainWin.grabGesture(Qt::PinchGesture);
153 andreas 353
    mainWin.grabGesture(Qt::SwipeGesture);
264 andreas 354
    mainWin.setOrientation(Qt::PrimaryOrientation);
355
//#ifdef Q_OS_IOS
356
 //   mainWin.setWindowFlag(Qt::MaximizeUsingFullscreenGeometryHint, true);
357
//#endif
198 andreas 358
    if (setupScaleFactor != 1.0 && setupScaleFactor > 0.0)
359
        mainWin.setSetupScaleFactor(setupScaleFactor);
360
 
5 andreas 361
    mainWin.show();
362
    return app.exec();
2 andreas 363
}
364
 
21 andreas 365
/**
366
 * @brief MainWindow::MainWindow constructor
367
 *
368
 * This method is the constructor for this class. It registers the callback
369
 * functions to the class TPageManager and starts the main run loop.
43 andreas 370
 *
371
 * Qt is used only to manage widgets to handle pages and subpages. A page as
372
 * well as a subpage may contain a background graphic and some elements. The
373
 * elements could be buttons, bargraphs and other objects. The underlying layer
374
 * draw every element as a ready graphic image and call a callback function to
375
 * let Qt display the graphic.
376
 * If there are some animations on a subpage defined, this is also handled by
377
 * Qt. Especialy sliding and fading.
21 andreas 378
 */
2 andreas 379
MainWindow::MainWindow()
380
{
5 andreas 381
    DECL_TRACER("MainWindow::MainWindow()");
59 andreas 382
 
296 andreas 383
    TObject::setParent(this);
384
 
264 andreas 385
    if (!gPageManager)
386
    {
387
        EXCEPTFATALMSG("The class TPageManager was not initialized!");
388
    }
389
 
323 andreas 390
    mGestureFilter = new TQGestureFilter(this);
391
    connect(mGestureFilter, &TQGestureFilter::gestureEvent, this, &MainWindow::onGestureEvent);
59 andreas 392
    setAttribute(Qt::WA_AcceptTouchEvents, true);   // We accept touch events
393
    grabGesture(Qt::PinchGesture);                  // We use a pinch gesture to open the settings dialog
153 andreas 394
    grabGesture(Qt::SwipeGesture);                  // We support swiping also
88 andreas 395
 
252 andreas 396
#ifdef Q_OS_IOS                                     // Block autorotate on IOS
386 andreas 397
//    initGeoLocation();
263 andreas 398
    mIosRotate = new TIOSRotate;
386 andreas 399
//    mIosRotate->automaticRotation(false);           // FIXME: This doesn't work!
252 andreas 400
 
401
    if (!mSensor)
402
    {
403
        mSensor = new QOrientationSensor(this);
404
 
405
        if (mSensor)
406
        {
386 andreas 407
            mSensor->setAxesOrientationMode(QSensor::AutomaticOrientation);
263 andreas 408
 
409
            if (gPageManager && gPageManager->getSettings()->isPortrait())
410
                mSensor->setCurrentOrientation(Qt::PortraitOrientation);
411
            else
412
                mSensor->setCurrentOrientation(Qt::LandscapeOrientation);
252 andreas 413
        }
414
    }
263 andreas 415
#endif  // Q_OS_IOS
264 andreas 416
 
417
    // We create the central widget here to make sure the application
418
    // initializes correct. On mobiles the whole screen is used while on
419
    // desktops a window with the necessary size is created.
266 andreas 420
    QWidget *central = new QWidget;
264 andreas 421
    central->setObjectName("centralWidget");
422
    central->setBackgroundRole(QPalette::Window);
271 andreas 423
#if defined(Q_OS_IOS) || defined(Q_OS_ANDROID)
277 andreas 424
//    central->setAutoFillBackground(false);
264 andreas 425
    central->setFixedSize(gScreenWidth, gScreenHeight);
426
#endif  // defined(Q_OS_IOS) || defined(Q_OSANDROID)
275 andreas 427
    setCentralWidget(central);      // Here we set the central widget
428
    central->show();
264 andreas 429
    // This is a stacked widget used to hold all pages. With it we can also
430
    // simply manage the objects bound to a page.
431
    mCentralWidget = new QStackedWidget(central);
266 andreas 432
    mCentralWidget->setObjectName("stackedPageWidgets");
265 andreas 433
#if defined(Q_OS_IOS) || defined(Q_OS_ANDROID)
264 andreas 434
    MSG_DEBUG("Size will be set for " << (isPortrait ? "PORTRAIT" : "LANDSCAPE"));
435
 
436
    if (gPageManager && gPageManager->getSettings()->isLandscape())
88 andreas 437
    {
264 andreas 438
        if (!isPortrait)
439
            mCentralWidget->setFixedSize((mToolbar ? gScreenWidth - mToolbar->width() : gScreenWidth), gScreenHeight);
440
        else
441
            mCentralWidget->setFixedSize(gScreenWidth, gScreenHeight);
442
    }
443
    else
444
    {
445
        if (isPortrait)
446
            mCentralWidget->setFixedSize((mToolbar ? gScreenHeight - mToolbar->width() : gScreenHeight), gScreenWidth);
447
        else
448
            mCentralWidget->setFixedSize(gScreenHeight, gScreenWidth);
449
    }
266 andreas 450
#else
270 andreas 451
    QSize qs = menuBar()->sizeHint();
266 andreas 452
    QSize icSize =  iconSize();
453
    int lwidth = gPageManager->getSettings()->getWidth() + icSize.width() + 16;
270 andreas 454
    int lheight = gPageManager->getSettings()->getHeight() + qs.height();
455
    mCentralWidget->setFixedSize(gPageManager->getSettings()->getWidth(), gPageManager->getSettings()->getHeight());
265 andreas 456
#endif  // defined(Q_OS_IOS) || defined(Q_OS_ANDROID)
275 andreas 457
 
266 andreas 458
#if defined(Q_OS_IOS) || defined(Q_OS_ANDROID)
264 andreas 459
    if (gPageManager->getSettings()->isPortrait())  // portrait?
460
    {
88 andreas 461
        MSG_INFO("Orientation set to portrait mode.");
462
        _setOrientation(O_PORTRAIT);
264 andreas 463
        mOrientation = Qt::PortraitOrientation;
88 andreas 464
    }
465
    else
466
    {
467
        MSG_INFO("Orientation set to landscape mode.");
468
        _setOrientation(O_LANDSCAPE);
264 andreas 469
        mOrientation = Qt::LandscapeOrientation;
88 andreas 470
    }
266 andreas 471
#else
472
    QRect rectMain = geometry();
473
    rectMain.setWidth(lwidth);
474
    rectMain.setHeight(lheight);
270 andreas 475
    setGeometry(rectMain);
266 andreas 476
    MSG_DEBUG("Height of main window:  " << rectMain.height());
477
    MSG_DEBUG("Height of panel screen: " << lheight);
478
    // If our first top pixel is not 0, maybe because of a menu, window
479
    // decorations or a toolbar, we must add this extra height to the
480
    // positions of widgets and mouse presses.
481
    int avHeight = rectMain.height() - gPageManager->getSettings()->getHeight();
482
    MSG_DEBUG("Difference in height:   " << avHeight);
483
    gPageManager->setFirstTopPixel(avHeight);
264 andreas 484
#endif
113 andreas 485
    setWindowIcon(QIcon(":images/icon.png"));
92 andreas 486
 
43 andreas 487
    // First we register all our surface callbacks to the underlying work
488
    // layer. All the graphics are drawn by the Skia library. The layer below
489
    // call the following functions to let Qt display the graphics on the
490
    // screen let it manage the widgets containing the graphics.
92 andreas 491
    gPageManager->registerCallbackDB(bind(&MainWindow::_displayButton, this,
5 andreas 492
                                       std::placeholders::_1,
493
                                       std::placeholders::_2,
494
                                       std::placeholders::_3,
495
                                       std::placeholders::_4,
496
                                       std::placeholders::_5,
497
                                       std::placeholders::_6,
298 andreas 498
                                       std::placeholders::_7,
391 andreas 499
                                       std::placeholders::_8,
500
                                       std::placeholders::_9,
501
                                       std::placeholders::_10));
5 andreas 502
 
391 andreas 503
    gPageManager->registerSetMarqueeText(bind(&MainWindow::_setMarqueeText, this, std::placeholders::_1));
504
 
280 andreas 505
    gPageManager->regDisplayViewButton(bind(&MainWindow::_displayViewButton, this,
506
                                          std::placeholders::_1,
507
                                          std::placeholders::_2,
508
                                          std::placeholders::_3,
509
                                          std::placeholders::_4,
510
                                          std::placeholders::_5,
511
                                          std::placeholders::_6,
512
                                          std::placeholders::_7,
513
                                          std::placeholders::_8,
285 andreas 514
                                          std::placeholders::_9,
515
                                          std::placeholders::_10));
280 andreas 516
 
281 andreas 517
    gPageManager->regAddViewButtonItems(bind(&MainWindow::_addViewButtonItems, this,
285 andreas 518
                                             std::placeholders::_1,
519
                                             std::placeholders::_2));
281 andreas 520
 
300 andreas 521
    gPageManager->regUpdateViewButton(bind(&MainWindow::_updateViewButton, this,
522
                                           std::placeholders::_1,
523
                                           std::placeholders::_2,
524
                                           std::placeholders::_3,
525
                                           std::placeholders::_4));
526
 
527
    gPageManager->regUpdateViewButtonItem(bind(&MainWindow::_updateViewButtonItem, this,
528
                                               std::placeholders::_1,
529
                                               std::placeholders::_2));
530
 
531
    gPageManager->regShowSubViewItem(bind(&MainWindow::_showViewButtonItem, this,
532
                                          std::placeholders::_1,
533
                                          std::placeholders::_2,
534
                                          std::placeholders::_3,
535
                                          std::placeholders::_4));
536
 
318 andreas 537
    gPageManager->regHideAllSubViewItems(bind(&MainWindow::_hideAllViewItems, this, std::placeholders::_1));
538
    gPageManager->regHideSubViewItem(bind(&MainWindow::_hideViewItem, this, std::placeholders::_1, std::placeholders::_2));
539
    gPageManager->regSetSubViewPadding(bind(&MainWindow::_setSubViewPadding, this, std::placeholders::_1, std::placeholders::_2));
540
 
92 andreas 541
    gPageManager->registerCallbackSP(bind(&MainWindow::_setPage, this,
5 andreas 542
                                         std::placeholders::_1,
543
                                         std::placeholders::_2,
544
                                         std::placeholders::_3));
545
 
92 andreas 546
    gPageManager->registerCallbackSSP(bind(&MainWindow::_setSubPage, this,
5 andreas 547
                                          std::placeholders::_1,
548
                                          std::placeholders::_2,
549
                                          std::placeholders::_3,
550
                                          std::placeholders::_4,
41 andreas 551
                                          std::placeholders::_5,
217 andreas 552
                                          std::placeholders::_6,
553
                                          std::placeholders::_7));
5 andreas 554
 
92 andreas 555
    gPageManager->registerCallbackSB(bind(&MainWindow::_setBackground, this,
5 andreas 556
                                         std::placeholders::_1,
557
                                         std::placeholders::_2,
558
                                         std::placeholders::_3,
559
                                         std::placeholders::_4,
262 andreas 560
#ifdef _OPAQUE_SKIA_
289 andreas 561
                                         std::placeholders::_5));
262 andreas 562
#else
289 andreas 563
                                         std::placeholders::_5,
564
                                         std::placeholders::_6));
262 andreas 565
#endif
92 andreas 566
    gPageManager->regCallDropPage(bind(&MainWindow::_dropPage, this, std::placeholders::_1));
350 andreas 567
    gPageManager->regCallDropSubPage(bind(&MainWindow::_dropSubPage, this, std::placeholders::_1, std::placeholders::_2));
92 andreas 568
    gPageManager->regCallPlayVideo(bind(&MainWindow::_playVideo, this,
21 andreas 569
                                       std::placeholders::_1,
570
                                       std::placeholders::_2,
571
                                       std::placeholders::_3,
572
                                       std::placeholders::_4,
573
                                       std::placeholders::_5,
574
                                       std::placeholders::_6,
575
                                       std::placeholders::_7,
576
                                       std::placeholders::_8,
577
                                       std::placeholders::_9));
192 andreas 578
    gPageManager->regCallInputText(bind(&MainWindow::_inputText, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
200 andreas 579
    gPageManager->regCallListBox(bind(&MainWindow::_listBox, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
190 andreas 580
    gPageManager->registerDropButton(bind(&MainWindow::_dropButton, this, std::placeholders::_1));
92 andreas 581
    gPageManager->regCallbackKeyboard(bind(&MainWindow::_showKeyboard, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
582
    gPageManager->regCallbackKeypad(bind(&MainWindow::_showKeypad, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
583
    gPageManager->regCallResetKeyboard(bind(&MainWindow::_resetKeyboard, this));
584
    gPageManager->regCallShowSetup(bind(&MainWindow::_showSetup, this));
585
    gPageManager->regCallbackResetSurface(bind(&MainWindow::_resetSurface, this));
586
    gPageManager->regCallbackShutdown(bind(&MainWindow::_shutdown, this));
587
    gPageManager->regCallbackPlaySound(bind(&MainWindow::_playSound, this, std::placeholders::_1));
141 andreas 588
    gPageManager->regCallbackStopSound(bind(&MainWindow::_stopSound, this));
589
    gPageManager->regCallbackMuteSound(bind(&MainWindow::_muteSound, this, std::placeholders::_1));
335 andreas 590
    gPageManager->regCallbackSetVolume(bind(&MainWindow::_setVolume, this, std::placeholders::_1));
98 andreas 591
    gPageManager->registerCBsetVisible(bind(&MainWindow::_setVisible, this, std::placeholders::_1, std::placeholders::_2));
111 andreas 592
    gPageManager->regSendVirtualKeys(bind(&MainWindow::_sendVirtualKeys, this, std::placeholders::_1));
140 andreas 593
    gPageManager->regShowPhoneDialog(bind(&MainWindow::_showPhoneDialog, this, std::placeholders::_1));
594
    gPageManager->regSetPhoneNumber(bind(&MainWindow::_setPhoneNumber, this, std::placeholders::_1));
595
    gPageManager->regSetPhoneStatus(bind(&MainWindow::_setPhoneStatus, this, std::placeholders::_1));
141 andreas 596
    gPageManager->regSetPhoneState(bind(&MainWindow::_setPhoneState, this, std::placeholders::_1, std::placeholders::_2));
130 andreas 597
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
598
    gPageManager->regOnOrientationChange(bind(&MainWindow::_orientationChanged, this, std::placeholders::_1));
259 andreas 599
    gPageManager->regOnSettingsChanged(bind(&MainWindow::_activateSettings, this, std::placeholders::_1,
600
                                            std::placeholders::_2,
601
                                            std::placeholders::_3,
602
                                            std::placeholders::_4,
603
                                            std::placeholders::_5,
604
                                            std::placeholders::_6));
130 andreas 605
#endif
142 andreas 606
    gPageManager->regRepaintWindows(bind(&MainWindow::_repaintWindows, this));
151 andreas 607
    gPageManager->regToFront(bind(&MainWindow::_toFront, this, std::placeholders::_1));
252 andreas 608
#if !defined (Q_OS_ANDROID) && !defined(Q_OS_IOS)
197 andreas 609
    gPageManager->regSetMainWindowSize(bind(&MainWindow::_setSizeMainWindow, this, std::placeholders::_1, std::placeholders::_2));
211 andreas 610
#endif
206 andreas 611
    gPageManager->regDownloadSurface(bind(&MainWindow::_downloadSurface, this, std::placeholders::_1, std::placeholders::_2));
612
    gPageManager->regDisplayMessage(bind(&MainWindow::_displayMessage, this, std::placeholders::_1, std::placeholders::_2));
396 andreas 613
    gPageManager->regAskPassword(bind(&MainWindow::_askPassword, this, std::placeholders::_1,
614
                                      std::placeholders::_2,
401 andreas 615
                                      std::placeholders::_3,
616
                                      std::placeholders::_4,
617
                                      std::placeholders::_5));
209 andreas 618
    gPageManager->regFileDialogFunction(bind(&MainWindow::_fileDialog, this,
619
                                             std::placeholders::_1,
620
                                             std::placeholders::_2,
621
                                             std::placeholders::_3,
622
                                             std::placeholders::_4));
260 andreas 623
    gPageManager->regStartWait(bind(&MainWindow::_startWait, this, std::placeholders::_1));
624
    gPageManager->regStopWait(bind(&MainWindow::_stopWait, this));
271 andreas 625
    gPageManager->regPageFinished(bind(&MainWindow::_pageFinished, this, std::placeholders::_1));
92 andreas 626
    gPageManager->deployCallbacks();
5 andreas 627
 
264 andreas 628
    createActions();        // Create the toolbar, if enabled by settings.
629
 
2 andreas 630
#ifndef QT_NO_SESSIONMANAGER
264 andreas 631
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
5 andreas 632
    QGuiApplication::setFallbackSessionManagementEnabled(false);
633
    connect(qApp, &QGuiApplication::commitDataRequest,
634
            this, &MainWindow::writeSettings);
264 andreas 635
#endif  // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
636
#endif  // QT_NO_SESSIONMANAGER
637
 
43 andreas 638
    // Some types used to transport data from the layer below.
14 andreas 639
    qRegisterMetaType<size_t>("size_t");
640
    qRegisterMetaType<QByteArray>("QByteArray");
41 andreas 641
    qRegisterMetaType<ANIMATION_t>("ANIMATION_t");
291 andreas 642
    qRegisterMetaType<Button::TButton*>("Button::TButton*");
62 andreas 643
    qRegisterMetaType<std::string>("std::string");
279 andreas 644
    qRegisterMetaType<SUBVIEWLIST_T>("SUBVIEWLIST_T");
283 andreas 645
    qRegisterMetaType<PGSUBVIEWITEM_T>("PGSUBVIEWITEM_T");
303 andreas 646
    qRegisterMetaType<PGSUBVIEWITEM_T>("PGSUBVIEWITEM_T&");
283 andreas 647
    qRegisterMetaType<PGSUBVIEWATOM_T>("PGSUBVIEWATOM_T");
648
    qRegisterMetaType<TBitmap>("TBitmap");
14 andreas 649
 
43 andreas 650
    // All the callback functions doesn't act directly. Instead they emit an
651
    // event. Then Qt decides whether the real function is started directly and
652
    // immediately or if the call is queued and called later in a thread. To
653
    // handle this we're "connecting" the real functions to some signals.
15 andreas 654
    try
655
    {
656
        connect(this, &MainWindow::sigDisplayButton, this, &MainWindow::displayButton);
391 andreas 657
        connect(this, &MainWindow::sigSetMarqueeText, this, &MainWindow::setMarqueeText);
280 andreas 658
        connect(this, &MainWindow::sigDisplayViewButton, this, &MainWindow::displayViewButton);
659
        connect(this, &MainWindow::sigAddViewButtonItems, this, &MainWindow::addViewButtonItems);
303 andreas 660
        connect(this, &MainWindow::sigShowViewButtonItem, this, &MainWindow::showViewButtonItem);
661
        connect(this, &MainWindow::sigUpdateViewButton, this, &MainWindow::updateViewButton);
662
        connect(this, &MainWindow::sigUpdateViewButtonItem, this, &MainWindow::updateViewButtonItem);
15 andreas 663
        connect(this, &MainWindow::sigSetPage, this, &MainWindow::setPage);
664
        connect(this, &MainWindow::sigSetSubPage, this, &MainWindow::setSubPage);
665
        connect(this, &MainWindow::sigSetBackground, this, &MainWindow::setBackground);
666
        connect(this, &MainWindow::sigDropPage, this, &MainWindow::dropPage);
667
        connect(this, &MainWindow::sigDropSubPage, this, &MainWindow::dropSubPage);
21 andreas 668
        connect(this, &MainWindow::sigPlayVideo, this, &MainWindow::playVideo);
50 andreas 669
        connect(this, &MainWindow::sigInputText, this, &MainWindow::inputText);
200 andreas 670
        connect(this, &MainWindow::sigListBox, this, &MainWindow::listBox);
62 andreas 671
        connect(this, &MainWindow::sigKeyboard, this, &MainWindow::showKeyboard);
672
        connect(this, &MainWindow::sigKeypad, this, &MainWindow::showKeypad);
64 andreas 673
        connect(this, &MainWindow::sigShowSetup, this, &MainWindow::showSetup);
71 andreas 674
        connect(this, &MainWindow::sigPlaySound, this, &MainWindow::playSound);
335 andreas 675
        connect(this, &MainWindow::sigSetVolume, this, &MainWindow::setVolume);
98 andreas 676
        connect(this, &MainWindow::sigDropButton, this, &MainWindow::dropButton);
677
        connect(this, &MainWindow::sigSetVisible, this, &MainWindow::SetVisible);
111 andreas 678
        connect(this, &MainWindow::sigSendVirtualKeys, this, &MainWindow::sendVirtualKeys);
140 andreas 679
        connect(this, &MainWindow::sigShowPhoneDialog, this, &MainWindow::showPhoneDialog);
680
        connect(this, &MainWindow::sigSetPhoneNumber, this, &MainWindow::setPhoneNumber);
681
        connect(this, &MainWindow::sigSetPhoneStatus, this, &MainWindow::setPhoneStatus);
141 andreas 682
        connect(this, &MainWindow::sigSetPhoneState, this, &MainWindow::setPhoneState);
142 andreas 683
        connect(this, &MainWindow::sigRepaintWindows, this, &MainWindow::repaintWindows);
151 andreas 684
        connect(this, &MainWindow::sigToFront, this, &MainWindow::toFront);
179 andreas 685
        connect(this, &MainWindow::sigOnProgressChanged, this, &MainWindow::onProgressChanged);
252 andreas 686
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
197 andreas 687
        connect(this, &MainWindow::sigSetSizeMainWindow, this, &MainWindow::setSizeMainWindow);
211 andreas 688
#endif
206 andreas 689
        connect(this, &MainWindow::sigDownloadSurface, this, &MainWindow::downloadSurface);
690
        connect(this, &MainWindow::sigDisplayMessage, this, &MainWindow::displayMessage);
396 andreas 691
        connect(this, &MainWindow::sigAskPassword, this, &MainWindow::askPassword);
209 andreas 692
        connect(this, &MainWindow::sigFileDialog, this, &MainWindow::fileDialog);
260 andreas 693
        connect(this, &MainWindow::sigStartWait, this, &MainWindow::startWait);
694
        connect(this, &MainWindow::sigStopWait, this, &MainWindow::stopWait);
271 andreas 695
        connect(this, &MainWindow::sigPageFinished, this, &MainWindow::pageFinished);
213 andreas 696
        connect(qApp, &QGuiApplication::applicationStateChanged, this, &MainWindow::onAppStateChanged);
130 andreas 697
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
698
        QScreen *screen = QGuiApplication::primaryScreen();
699
        connect(screen, &QScreen::orientationChanged, this, &MainWindow::onScreenOrientationChanged);
259 andreas 700
        connect(this, &MainWindow::sigActivateSettings, this, &MainWindow::activateSettings);
130 andreas 701
#endif
15 andreas 702
    }
703
    catch (std::exception& e)
704
    {
705
        MSG_ERROR("Connection error: " << e.what());
706
    }
93 andreas 707
    catch(...)
708
    {
709
        MSG_ERROR("Unexpected exception occured [MainWindow::MainWindow()]");
710
    }
15 andreas 711
 
5 andreas 712
    setUnifiedTitleAndToolBarOnMac(true);
182 andreas 713
#ifdef Q_OS_ANDROID
61 andreas 714
    // At least initialize the phone call listener
715
    if (gPageManager)
716
        gPageManager->initPhoneState();
92 andreas 717
 
93 andreas 718
    /*
719
     * In case this class was created not the first time, we initiate a small
720
     * thread to send the signal ApplicationActive to initiate the communication
721
     * with the controller again. This also starts the page manager thread
722
     * (TPageManager), which handles all elements of the surface.
723
     */
92 andreas 724
    if (_restart_ && gPageManager)
725
    {
93 andreas 726
        try
727
        {
728
            std::thread mThread = std::thread([=] { this->_signalState(Qt::ApplicationActive); });
729
            mThread.detach();   // We detach immediately to leave this method.
730
        }
731
        catch (std::exception& e)
732
        {
733
            MSG_ERROR("Error starting the thread to reinvoke communication!");
734
        }
735
        catch(...)
736
        {
737
            MSG_ERROR("Unexpected exception occured [MainWindow::MainWindow()]");
738
        }
92 andreas 739
    }
93 andreas 740
#endif
392 andreas 741
 
247 andreas 742
#ifdef Q_OS_IOS
743
    // To get the battery level periodicaly we setup a timer.
744
    if (!mIosBattery)
745
        mIosBattery = new TIOSBattery;
746
 
747
    mIosBattery->update();
748
 
264 andreas 749
    int left = mIosBattery->getBatteryLeft();
750
    int state = mIosBattery->getBatteryState();
751
    // At this point no buttons are registered and therefore the battery
752
    // state will not be visible. To have the state at the moment a button
753
    // is registered, we tell the page manager to store the values.
754
    gPageManager->setBattery(left, state);
755
    MSG_DEBUG("Battery state was set to " << left << "% and state " << state);
247 andreas 756
#endif  // Q_OS_IOS
392 andreas 757
 
92 andreas 758
    _restart_ = false;
2 andreas 759
}
760
 
34 andreas 761
MainWindow::~MainWindow()
762
{
763
    DECL_TRACER("MainWindow::~MainWindow()");
40 andreas 764
 
34 andreas 765
    killed = true;
766
    prg_stopped = true;
296 andreas 767
 
768
    disconnect(this, &MainWindow::sigDisplayButton, this, &MainWindow::displayButton);
769
    disconnect(this, &MainWindow::sigDisplayViewButton, this, &MainWindow::displayViewButton);
770
    disconnect(this, &MainWindow::sigAddViewButtonItems, this, &MainWindow::addViewButtonItems);
771
    disconnect(this, &MainWindow::sigSetPage, this, &MainWindow::setPage);
772
    disconnect(this, &MainWindow::sigSetSubPage, this, &MainWindow::setSubPage);
773
    disconnect(this, &MainWindow::sigSetBackground, this, &MainWindow::setBackground);
774
    disconnect(this, &MainWindow::sigDropPage, this, &MainWindow::dropPage);
775
    disconnect(this, &MainWindow::sigDropSubPage, this, &MainWindow::dropSubPage);
776
    disconnect(this, &MainWindow::sigPlayVideo, this, &MainWindow::playVideo);
777
    disconnect(this, &MainWindow::sigInputText, this, &MainWindow::inputText);
778
    disconnect(this, &MainWindow::sigListBox, this, &MainWindow::listBox);
779
    disconnect(this, &MainWindow::sigKeyboard, this, &MainWindow::showKeyboard);
780
    disconnect(this, &MainWindow::sigKeypad, this, &MainWindow::showKeypad);
781
    disconnect(this, &MainWindow::sigShowSetup, this, &MainWindow::showSetup);
782
    disconnect(this, &MainWindow::sigPlaySound, this, &MainWindow::playSound);
783
    disconnect(this, &MainWindow::sigDropButton, this, &MainWindow::dropButton);
784
    disconnect(this, &MainWindow::sigSetVisible, this, &MainWindow::SetVisible);
785
    disconnect(this, &MainWindow::sigSendVirtualKeys, this, &MainWindow::sendVirtualKeys);
786
    disconnect(this, &MainWindow::sigShowPhoneDialog, this, &MainWindow::showPhoneDialog);
787
    disconnect(this, &MainWindow::sigSetPhoneNumber, this, &MainWindow::setPhoneNumber);
788
    disconnect(this, &MainWindow::sigSetPhoneStatus, this, &MainWindow::setPhoneStatus);
789
    disconnect(this, &MainWindow::sigSetPhoneState, this, &MainWindow::setPhoneState);
790
    disconnect(this, &MainWindow::sigRepaintWindows, this, &MainWindow::repaintWindows);
791
    disconnect(this, &MainWindow::sigToFront, this, &MainWindow::toFront);
792
    disconnect(this, &MainWindow::sigOnProgressChanged, this, &MainWindow::onProgressChanged);
793
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
794
    disconnect(this, &MainWindow::sigSetSizeMainWindow, this, &MainWindow::setSizeMainWindow);
795
#endif
796
    disconnect(this, &MainWindow::sigDownloadSurface, this, &MainWindow::downloadSurface);
797
    disconnect(this, &MainWindow::sigDisplayMessage, this, &MainWindow::displayMessage);
798
    disconnect(this, &MainWindow::sigFileDialog, this, &MainWindow::fileDialog);
799
    disconnect(this, &MainWindow::sigStartWait, this, &MainWindow::startWait);
800
    disconnect(this, &MainWindow::sigStopWait, this, &MainWindow::stopWait);
801
    disconnect(this, &MainWindow::sigPageFinished, this, &MainWindow::pageFinished);
802
    disconnect(qApp, &QGuiApplication::applicationStateChanged, this, &MainWindow::onAppStateChanged);
803
 
254 andreas 804
#ifdef Q_OS_IOS
252 andreas 805
    if (mSource)
806
    {
807
        delete mSource;
808
        mSource = nullptr;
809
    }
254 andreas 810
#endif
141 andreas 811
    if (mMediaPlayer)
181 andreas 812
    {
264 andreas 813
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
181 andreas 814
        delete mAudioOutput;
815
#endif
141 andreas 816
        delete mMediaPlayer;
181 andreas 817
    }
141 andreas 818
 
34 andreas 819
    if (gAmxNet && !gAmxNet->isStopped())
820
        gAmxNet->stop();
90 andreas 821
 
822
    if (mToolbar)
823
    {
824
        removeToolBar(mToolbar);
825
        mToolbar = nullptr;
826
    }
827
 
828
    isRunning = false;
247 andreas 829
#ifdef Q_OS_IOS
252 andreas 830
    if (mIosRotate)
831
        mIosRotate->automaticRotation(true);
247 andreas 832
 
833
    if (mIosBattery)
834
    {
835
        delete mIosBattery;
836
        mIosBattery = nullptr;
837
    }
252 andreas 838
 
839
    if (mIosRotate)
840
        delete mIosRotate;
247 andreas 841
#endif
323 andreas 842
 
843
    if (mGestureFilter)
844
    {
845
        disconnect(mGestureFilter, &TQGestureFilter::gestureEvent, this, &MainWindow::onGestureEvent);
846
        delete mGestureFilter;
847
    }
34 andreas 848
}
849
 
235 andreas 850
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
21 andreas 851
/**
93 andreas 852
 * @brief Small thread to invoke the initialization on an Android device.
853
 *
854
 * On Android devices the signal ApplicationActive is not send if the class
855
 * \p MainWindow is destroyed and recreated. Therefore we need this little
856
 * helper to send the signal when the class is initialized.
857
 *
858
 * @param state     This defines the signal to send.
859
 */
860
void MainWindow::_signalState(Qt::ApplicationState state)
861
{
862
    DECL_TRACER("MainWindow::_signalState(Qt::ApplicationState state)");
863
 
864
    std::this_thread::sleep_for(std::chrono::seconds(1));   // Wait a second
213 andreas 865
    onAppStateChanged(state);
93 andreas 866
}
130 andreas 867
 
868
void MainWindow::_orientationChanged(int orientation)
869
{
870
    DECL_TRACER("MainWindow::_orientationChanged(int orientation)");
871
 
264 andreas 872
    if (gPageManager && gPageManager->getSettings()->isPortrait())  // portrait?
131 andreas 873
    {
874
        if (orientation == O_REVERSE_PORTRAIT && mOrientation != Qt::InvertedPortraitOrientation)
245 andreas 875
        {
131 andreas 876
            _setOrientation((J_ORIENTATION)orientation);
245 andreas 877
            mOrientation = Qt::InvertedPortraitOrientation;
878
        }
131 andreas 879
        else if (orientation == O_PORTRAIT && mOrientation != Qt::PortraitOrientation)
245 andreas 880
        {
131 andreas 881
            _setOrientation((J_ORIENTATION)orientation);
245 andreas 882
            mOrientation = Qt::PortraitOrientation;
883
        }
131 andreas 884
    }
885
    else
886
    {
887
        if (orientation == O_REVERSE_LANDSCAPE && mOrientation != Qt::InvertedLandscapeOrientation)
245 andreas 888
        {
131 andreas 889
            _setOrientation((J_ORIENTATION)orientation);
245 andreas 890
            mOrientation = Qt::InvertedLandscapeOrientation;
891
        }
131 andreas 892
        else if (orientation == O_LANDSCAPE && mOrientation != Qt::LandscapeOrientation)
245 andreas 893
        {
131 andreas 894
            _setOrientation((J_ORIENTATION)orientation);
245 andreas 895
            mOrientation = Qt::LandscapeOrientation;
896
        }
131 andreas 897
    }
130 andreas 898
}
93 andreas 899
 
259 andreas 900
void MainWindow::_activateSettings(const std::string& oldNetlinx, int oldPort, int oldChannelID, const std::string& oldSurface, bool oldToolbarSuppress, bool oldToolbarForce)
901
{
902
    DECL_TRACER("MainWindow::_activateSettings(const std::string& oldNetlinx, int oldPort, int oldChannelID, const std::string& oldSurface, bool oldToolbarSuppress, bool oldToolbarForce)");
903
 
369 andreas 904
    if (!mHasFocus)
905
        return;
906
 
259 andreas 907
    emit sigActivateSettings(oldNetlinx, oldPort, oldChannelID, oldSurface, oldToolbarSuppress, oldToolbarForce);
908
}
909
 
217 andreas 910
/**
259 andreas 911
 * @brief MainWindow::activateSettings
912
 * This method activates some urgent settings. It is called on Android and IOS
913
 * after the setup dialog was closed. The method expects some values taken
914
 * immediately before the setup dialog was started. If takes some actions like
915
 * downloading a surface when the setting for it changed or removes the
916
 * toolbar on the right if the user reuqsted it.
917
 *
918
 * @param oldNetlinx        The IP or name of the Netlinx
919
 * @param oldPort           The network port number used to connect to Netlinx
920
 * @param oldChannelID      The channel ID TPanel uses to identify against the
921
 *                          Netlinx.
922
 * @param oldSurface        The name of theprevious TP4 file.
923
 * @param oldToolbarSuppress    State of toolbar suppress switch
924
 * @param oldToolbarForce   The state of toolbar force switch
925
 */
926
void MainWindow::activateSettings(const std::string& oldNetlinx, int oldPort, int oldChannelID, const std::string& oldSurface, bool oldToolbarSuppress, bool oldToolbarForce)
927
{
928
    DECL_TRACER("MainWindow::activateSettings(const std::string& oldNetlinx, int oldPort, int oldChannelID, const std::string& oldSurface, bool oldToolbarSuppress, bool oldToolbarForce)");
929
 
930
#ifdef Q_OS_IOS
931
    TConfig cf(TConfig::getConfigPath() + "/" + TConfig::getConfigFileName());
932
#endif
933
    bool rebootAnyway = false;
260 andreas 934
    bool doDownload = false;
259 andreas 935
    string newSurface = TConfig::getFtpSurface();
936
 
937
    if (!TConfig::getToolbarSuppress() && oldToolbarForce != TConfig::getToolbarForce())
938
    {
939
        QMessageBox msgBox(this);
940
        msgBox.setText("The change for the visibility of the toolbar will be active on the next start of TPanel!");
941
        msgBox.exec();
942
    }
943
    else if (oldToolbarSuppress != TConfig::getToolbarSuppress() && TConfig::getToolbarSuppress())
944
    {
945
        if (mToolbar)
946
        {
947
            mToolbar->close();
948
            delete mToolbar;
949
            mToolbar = nullptr;
950
        }
951
    }
260 andreas 952
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
259 andreas 953
    if (newSurface != oldSurface || TTPInit::haveSystemMarker())
954
#else
262 andreas 955
    time_t dlTime = TConfig::getFtpDownloadTime();
956
    time_t actTime = time(NULL);
957
 
259 andreas 958
    if (newSurface != oldSurface || dlTime == 0 || dlTime < (actTime - 60))
959
#endif
960
    {
961
        MSG_DEBUG("Surface should be downloaded (Old: " << oldSurface << ", New: " << newSurface << ")");
962
 
963
        QMessageBox msgBox(this);
964
        msgBox.setText(QString("Should the surface <b>") + newSurface.c_str() + "</b> be installed?");
965
        msgBox.addButton(QMessageBox::Yes);
966
        msgBox.addButton(QMessageBox::No);
967
        int ret = msgBox.exec();
968
 
969
        if (ret == QMessageBox::Yes)
970
        {
260 andreas 971
            doDownload = true;
259 andreas 972
            TTPInit tpinit;
973
            std::vector<TTPInit::FILELIST_t> mFileList;
974
            // Get the list of TP4 files from NetLinx, if there are any.
260 andreas 975
            TQtWait waitBox(this, string("Please wait while I'm looking at the disc of Netlinx (") + TConfig::getController().c_str() + ") for TP4 files ...");
976
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
977
            waitBox.setScaleFactor(mScaleFactor);
978
            waitBox.doResize();
979
            waitBox.start();
980
#endif
259 andreas 981
            tpinit.setPath(TConfig::getProjectPath());
982
            tpinit.regCallbackProcessEvents(bind(&MainWindow::runEvents, this));
983
            tpinit.regCallbackProgressBar(bind(&MainWindow::_onProgressChanged, this, std::placeholders::_1));
984
            mFileList = tpinit.getFileList(".tp4");
985
            bool found = false;
986
 
987
            if (mFileList.size() > 0)
988
            {
989
                vector<TTPInit::FILELIST_t>::iterator iter;
990
 
991
                for (iter = mFileList.begin(); iter != mFileList.end(); ++iter)
992
                {
993
                    if (iter->fname == newSurface)
994
                    {
995
                        tpinit.setFileSize(iter->size);
996
                        found = true;
997
                        break;
998
                    }
999
                }
1000
            }
1001
 
260 andreas 1002
            waitBox.end();
259 andreas 1003
 
1004
            if (found)
1005
            {
1006
                string msg = "Loading file <b>" + newSurface + "</b>.";
1007
                MSG_DEBUG("Download of surface " << newSurface << " was forced!");
1008
 
1009
                downloadBar(msg, this);
1010
 
1011
                if (tpinit.loadSurfaceFromController(true))
1012
                    rebootAnyway = true;
1013
 
1014
                mDownloadBar->close();
1015
                mBusy = false;
1016
            }
1017
            else
1018
            {
1019
                MSG_PROTOCOL("The surface " << newSurface << " does not exist on NetLinx or the NetLinx " << TConfig::getController() << " was not found!");
1020
                displayMessage("The surface " + newSurface + " does not exist on NetLinx or the NetLinx " + TConfig::getController() + " was not found!", "Information");
1021
            }
1022
        }
1023
    }
1024
 
260 andreas 1025
    if (doDownload &&
1026
        (TConfig::getController() != oldNetlinx ||
259 andreas 1027
        TConfig::getChannel() != oldChannelID ||
260 andreas 1028
        TConfig::getPort() != oldPort || rebootAnyway))
259 andreas 1029
    {
1030
        // Start over by exiting this class
1031
        MSG_INFO("Program will start over!");
1032
        _restart_ = true;
1033
        prg_stopped = true;
1034
        killed = true;
1035
 
1036
        if (gAmxNet)
1037
            gAmxNet->stop();
1038
 
1039
        close();
1040
    }
1041
#ifdef Q_OS_ANDROID
1042
    else
1043
    {
1044
        TConfig cf(TConfig::getConfigPath() + "/" + TConfig::getConfigFileName());
1045
    }
1046
#endif
1047
}
1048
 
1049
/**
217 andreas 1050
 * @brief MainWindow::_freezeWorkaround: A workaround for the screen freeze.
271 andreas 1051
 * On Mobiles the screen sometimes stay frozen after the application state
1052
 * changes to ACTIVE or some yet unidentified things happened.
217 andreas 1053
 * The workaround produces a faked geometry change which makes the Qt framework
271 andreas 1054
 * to reattach to the screen.
1055
 * There may be situations where this workaround could trigger a repaint of all
1056
 * objects on the screen but then the surface is still frozen. At the moment of
1057
 * writing this comment I have no workaround or even an explanation for this.
217 andreas 1058
 */
264 andreas 1059
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
271 andreas 1060
/**
1061
 * @brief MainWindow::_freezeWorkaround
1062
 * This hack was made from Thomas Andersen. You'll find it at:
1063
 * https://bugreports.qt.io/browse/QTBUG-76142
1064
 */
217 andreas 1065
void MainWindow::_freezeWorkaround()
1066
{
1067
    DECL_TRACER("MainWindow::_freezeWorkaround()");
1068
 
1069
    QScreen* scr = QGuiApplication::screens().first();
1070
    QPlatformScreen* l_pScr = scr->handle(); /*QAndroidPlatformScreen*/
1071
    QRect l_geomHackAdjustedRect = l_pScr->availableGeometry();
1072
    QRect l_geomHackRect = l_geomHackAdjustedRect;
271 andreas 1073
    l_geomHackAdjustedRect.adjust(0, 0, 0, 5);
217 andreas 1074
    QMetaObject::invokeMethod(dynamic_cast<QObject*>(l_pScr), "setAvailableGeometry", Qt::DirectConnection, Q_ARG( const QRect &, l_geomHackAdjustedRect ));
1075
    QMetaObject::invokeMethod(dynamic_cast<QObject*>(l_pScr), "setAvailableGeometry", Qt::QueuedConnection, Q_ARG( const QRect &, l_geomHackRect ));
1076
}
271 andreas 1077
#endif  // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
235 andreas 1078
#endif  // Q_OS_ANDROID || Q_OS_IOS
217 andreas 1079
 
142 andreas 1080
void MainWindow::_repaintWindows()
1081
{
1082
    DECL_TRACER("MainWindow::_repaintWindows()");
1083
 
369 andreas 1084
    if (mHasFocus)
1085
        emit sigRepaintWindows();
142 andreas 1086
}
151 andreas 1087
 
1088
void MainWindow::_toFront(ulong handle)
1089
{
1090
    DECL_TRACER("MainWindow::_toFront(ulong handle)");
1091
 
369 andreas 1092
    if (mHasFocus)
1093
        emit sigToFront(handle);
151 andreas 1094
}
1095
 
206 andreas 1096
void MainWindow::_downloadSurface(const string &file, size_t size)
1097
{
1098
    DECL_TRACER("MainWindow::_downloadSurface(const string &file, size_t size)");
1099
 
369 andreas 1100
    if (mHasFocus)
1101
        emit sigDownloadSurface(file, size);
206 andreas 1102
}
1103
 
260 andreas 1104
void MainWindow::_startWait(const string& text)
1105
{
1106
    DECL_TRACER("MainWindow::_startWait(const string& text)");
1107
 
1108
    emit sigStartWait(text);
1109
}
1110
 
1111
void MainWindow::_stopWait()
1112
{
1113
    DECL_TRACER("MainWindow::_stopWait()");
1114
 
1115
    emit sigStopWait();
1116
}
1117
 
271 andreas 1118
void MainWindow::_pageFinished(uint handle)
1119
{
1120
    DECL_TRACER("MainWindow::_pageFinished(uint handle)");
1121
 
1122
    emit sigPageFinished(handle);
1123
}
1124
 
93 andreas 1125
/**
21 andreas 1126
 * @brief MainWindow::closeEvent called when the application receives an exit event.
1127
 *
1128
 * If the user clicks on the exit icon or on the menu point _Exit_ this method
1129
 * is called. It makes sure everything is written to the configuration file
1130
 * and accepts the evernt.
1131
 *
1132
 * @param event The exit event
1133
 */
2 andreas 1134
void MainWindow::closeEvent(QCloseEvent *event)
1135
{
5 andreas 1136
    DECL_TRACER("MainWindow::closeEvent(QCloseEvent *event)");
24 andreas 1137
#ifdef __ANDROID__
23 andreas 1138
    __android_log_print(ANDROID_LOG_DEBUG,"tpanel","Close event; settingsChanged=%s", (settingsChanged ? "true":"false"));
24 andreas 1139
#endif
5 andreas 1140
    if (settingsChanged)
1141
    {
1142
        writeSettings();
1143
        event->accept();
1144
    }
1145
    else
1146
    {
21 andreas 1147
        prg_stopped = true;
34 andreas 1148
        killed = true;
36 andreas 1149
        MSG_INFO("Program will stop!");
37 andreas 1150
#ifdef __ANDROID__
92 andreas 1151
        if (gPageManager)
1152
            gPageManager->stopNetworkState();
37 andreas 1153
#endif
5 andreas 1154
        event->accept();
1155
    }
2 andreas 1156
}
1157
 
21 andreas 1158
/**
57 andreas 1159
 * @brief MainWindow::event Looks for a gesture
1160
 * @param event The event occured
1161
 * @return TRUE if event was accepted
1162
 */
1163
bool MainWindow::event(QEvent* event)
1164
{
1165
    if (event->type() == QEvent::Gesture)
1166
        return gestureEvent(static_cast<QGestureEvent*>(event));
1167
 
323 andreas 1168
    return QMainWindow::event(event);
57 andreas 1169
}
1170
 
1171
/**
1172
 * @brief MainWindow::gestureEvent handles a pinch event
1173
 * If a pinch event occured where the scale factor increased, the settings
1174
 * dialog is called. This exists for devices, where the left toolbox is not
1175
 * visible.
1176
 * @param event The guesture occured
130 andreas 1177
 * @return FALSE
57 andreas 1178
 */
1179
bool MainWindow::gestureEvent(QGestureEvent* event)
1180
{
1181
    DECL_TRACER("MainWindow::gestureEvent(QGestureEvent* event)");
59 andreas 1182
 
57 andreas 1183
    if (QGesture *pinch = event->gesture(Qt::PinchGesture))
1184
    {
323 andreas 1185
        QPinchGesture *pg = static_cast<QPinchGesture *>(pinch);
298 andreas 1186
#ifdef QT_DEBUG
57 andreas 1187
        string gs;
323 andreas 1188
 
57 andreas 1189
        switch(pg->state())
1190
        {
1191
            case Qt::NoGesture:         gs.assign("no gesture"); break;
1192
            case Qt::GestureStarted:    gs.assign("gesture started"); break;
1193
            case Qt::GestureUpdated:    gs.assign("gesture updated"); break;
1194
            case Qt::GestureFinished:   gs.assign("gesture finished"); break;
1195
            case Qt::GestureCanceled:   gs.assign("gesture canceled"); break;
1196
        }
1197
 
59 andreas 1198
        MSG_DEBUG("PinchGesture state " << gs << " detected");
298 andreas 1199
#endif
57 andreas 1200
        if (pg->state() == Qt::GestureFinished)
1201
        {
59 andreas 1202
            MSG_DEBUG("total scale: " << pg->totalScaleFactor() << ", scale: " << pg->scaleFactor() << ", last scale: " << pg->lastScaleFactor());
1203
 
57 andreas 1204
            if (pg->totalScaleFactor() > pg->scaleFactor())
1205
                settings();
323 andreas 1206
 
1207
            return true;
57 andreas 1208
        }
1209
    }
153 andreas 1210
    else if (QGesture *swipe = event->gesture(Qt::SwipeGesture))
1211
    {
1212
        if (!gPageManager)
1213
            return false;
1214
 
1215
        QSwipeGesture *sw = static_cast<QSwipeGesture *>(swipe);
1216
        MSG_DEBUG("Swipe gesture detected.");
1217
 
1218
        if (sw->state() == Qt::GestureFinished)
1219
        {
1220
            if (sw->horizontalDirection() == QSwipeGesture::Left)
1221
                gPageManager->onSwipeEvent(TPageManager::SW_LEFT);
1222
            else if (sw->horizontalDirection() == QSwipeGesture::Right)
1223
                gPageManager->onSwipeEvent(TPageManager::SW_RIGHT);
1224
            else if (sw->verticalDirection() == QSwipeGesture::Up)
1225
                gPageManager->onSwipeEvent(TPageManager::SW_UP);
1226
            else if (sw->verticalDirection() == QSwipeGesture::Down)
1227
                gPageManager->onSwipeEvent(TPageManager::SW_DOWN);
323 andreas 1228
 
1229
            return true;
153 andreas 1230
        }
1231
    }
1232
 
57 andreas 1233
    return false;
1234
}
1235
 
1236
/**
319 andreas 1237
 * @brief MainWindow::mousePressEvent catches the event Qt::LeftButton.
1238
 *
1239
 * If the user presses the left mouse button somewhere in the main window, this
1240
 * method is triggered. It retrieves the position of the mouse pointer and
1241
 * sends it to the page manager TPageManager.
1242
 *
1243
 * @param event The event
1244
 */
1245
void MainWindow::mousePressEvent(QMouseEvent* event)
1246
{
1247
    DECL_TRACER("MainWindow::mousePressEvent(QMouseEvent* event)");
1248
 
1249
    if (!gPageManager)
1250
        return;
1251
 
1252
    if(event->button() == Qt::LeftButton)
1253
    {
1254
        int nx = 0, ny = 0;
320 andreas 1255
#ifdef Q_OS_IOS
319 andreas 1256
        if (mHaveNotchPortrait && gPageManager->getSettings()->isPortrait())
1257
        {
1258
            nx = mNotchPortrait.left();
1259
            ny = mNotchPortrait.top();
1260
        }
1261
        else if (mHaveNotchLandscape && gPageManager->getSettings()->isLandscape())
1262
        {
1263
            nx = mNotchLandscape.left();
1264
            ny = mNotchLandscape.top();
1265
        }
1266
        else
1267
        {
1268
            MSG_WARNING("Have no notch distances!");
1269
        }
320 andreas 1270
#endif
398 andreas 1271
        int x = static_cast<int>(event->position().x()) - nx;
1272
        int y = static_cast<int>(event->position().y()) - ny;
361 andreas 1273
        MSG_DEBUG("Mouse press coordinates: x: " << event->position().x() << ", y: " << event->position().y() << " [new x: " << x << ", y: " << y << " -- \"notch\" nx: " << nx << ", ny: " << ny << "]");
1274
 
319 andreas 1275
        mLastPressX = x;
1276
        mLastPressY = y;
320 andreas 1277
/*
319 andreas 1278
        QWidget *w = childAt(event->x(), event->y());
1279
 
1280
        if (w)
1281
        {
1282
            MSG_DEBUG("Object " << w->objectName().toStdString() << " is under mouse cursor.");
1283
            QObject *par = w->parent();
1284
 
1285
            if (par)
1286
            {
1287
                MSG_DEBUG("The parent is " << par->objectName().toStdString());
1288
 
1289
                if (par->objectName().startsWith("Item_"))
1290
                {
1291
                    QObject *ppar = par->parent();
1292
 
1293
                    if (ppar)
1294
                    {
1295
                        MSG_DEBUG("The pparent is " << ppar->objectName().toStdString());
1296
 
1297
                        if (ppar->objectName().startsWith("View_"))
1298
                        {
1299
                            QMouseEvent *mev = new QMouseEvent(event->type(), event->localPos(), event->globalPos(), event->button(), event->buttons(), event->modifiers());
1300
                            QApplication::postEvent(ppar, mev);
1301
                            return;
1302
                        }
1303
                    }
1304
                }
1305
            }
1306
        }
320 andreas 1307
*/
319 andreas 1308
        if (gPageManager->isSetupActive() && isSetupScaled())
1309
        {
398 andreas 1310
            x = static_cast<int>(static_cast<double>(x) / mSetupScaleFactor);
1311
            y = static_cast<int>(static_cast<double>(y) / mSetupScaleFactor);
319 andreas 1312
        }
1313
        else if (isScaled())
1314
        {
398 andreas 1315
            x = static_cast<int>(static_cast<double>(x) / mScaleFactor);
1316
            y = static_cast<int>(static_cast<double>(y) / mScaleFactor);
319 andreas 1317
        }
1318
 
1319
        gPageManager->mouseEvent(x, y, true);
1320
        mTouchStart = std::chrono::steady_clock::now();
1321
        mTouchX = mLastPressX;
1322
        mTouchY = mLastPressY;
1323
    }
1324
    else if (event->button() == Qt::MiddleButton)
1325
        settings();
1326
}
1327
 
1328
/**
1329
 * @brief MainWindow::mouseReleaseEvent catches the event Qt::LeftButton.
1330
 *
1331
 * If the user releases the left mouse button somewhere in the main window, this
1332
 * method is triggered. It retrieves the position of the mouse pointer and
1333
 * sends it to the page manager TPageManager.
1334
 *
1335
 * @param event The event
1336
 */
1337
void MainWindow::mouseReleaseEvent(QMouseEvent* event)
1338
{
1339
    DECL_TRACER("MainWindow::mouseReleaseEvent(QMouseEvent* event)");
1340
 
1341
    if (!gPageManager)
1342
        return;
1343
 
1344
    if(event->button() == Qt::LeftButton)
1345
    {
1346
        int nx = 0, ny = 0;
320 andreas 1347
#ifdef Q_OS_IOS
319 andreas 1348
        if (mHaveNotchPortrait && gPageManager->getSettings()->isPortrait())
1349
        {
1350
            nx = mNotchPortrait.left();
1351
            ny = mNotchPortrait.top();
1352
        }
1353
        else if (mHaveNotchLandscape && gPageManager->getSettings()->isLandscape())
1354
        {
1355
            nx = mNotchLandscape.left();
1356
            ny = mNotchLandscape.top();
1357
        }
320 andreas 1358
#endif
398 andreas 1359
        int x = ((mLastPressX >= 0) ? mLastPressX : (static_cast<int>(event->position().x()) - nx));
1360
        int y = ((mLastPressY >= 0) ? mLastPressY : (static_cast<int>(event->position().y()) - ny));
361 andreas 1361
        MSG_DEBUG("Mouse press coordinates: x: " << event->position().x() << ", y: " << event->position().y());
319 andreas 1362
        mLastPressX = mLastPressY = -1;
320 andreas 1363
/*
319 andreas 1364
        QWidget *w = childAt(event->x(), event->y());
1365
 
1366
        if (w)
1367
        {
1368
            MSG_DEBUG("Object " << w->objectName().toStdString() << " is under mouse cursor.");
1369
            QObject *par = w->parent();
1370
 
1371
            if (par)
1372
            {
1373
                MSG_DEBUG("The parent is " << par->objectName().toStdString());
1374
 
1375
                if (par->objectName().startsWith("Item_"))
1376
                {
1377
                    QObject *ppar = par->parent();
1378
 
1379
                    if (ppar)
1380
                    {
1381
                        MSG_DEBUG("The pparent is " << ppar->objectName().toStdString());
1382
 
1383
                        if (ppar->objectName().startsWith("View_"))
1384
                        {
1385
                            QMouseEvent *mev = new QMouseEvent(event->type(), event->localPos(), event->globalPos(), event->button(), event->buttons(), event->modifiers());
1386
                            QApplication::postEvent(ppar, mev);
1387
                            return;
1388
                        }
1389
                    }
1390
                }
1391
            }
1392
        }
320 andreas 1393
*/
319 andreas 1394
        if (gPageManager->isSetupActive() && isSetupScaled())
1395
        {
398 andreas 1396
            x = static_cast<int>(static_cast<double>(x) / mSetupScaleFactor);
1397
            y = static_cast<int>(static_cast<double>(y) / mSetupScaleFactor);
319 andreas 1398
        }
1399
        else if (isScaled())
1400
        {
398 andreas 1401
            x = static_cast<int>(static_cast<double>(x) / mScaleFactor);
1402
            y = static_cast<int>(static_cast<double>(y) / mScaleFactor);
319 andreas 1403
        }
1404
 
1405
        gPageManager->mouseEvent(x, y, false);
1406
        std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
1407
        std::chrono::nanoseconds difftime = end - mTouchStart;
1408
        std::chrono::milliseconds msecs = std::chrono::duration_cast<std::chrono::milliseconds>(difftime);
1409
 
1410
        if (msecs.count() < 100)    // 1/10 of a second
1411
        {
1412
            MSG_DEBUG("Time was too short: " << msecs.count());
1413
            return;
1414
        }
1415
 
398 andreas 1416
        x = static_cast<int>(event->position().x());
1417
        y = static_cast<int>(event->position().y());
319 andreas 1418
        bool setupActive = gPageManager->isSetupActive();
1419
        int width = (setupActive ? scaleSetup(gPageManager->getSystemSettings()->getWidth()) : scale(gPageManager->getSettings()->getWidth()));
1420
        int height = (setupActive ? scaleSetup(gPageManager->getSystemSettings()->getHeight()) : scale(gPageManager->getSettings()->getHeight()));
1421
        MSG_DEBUG("Coordinates: x1=" << mTouchX << ", y1=" << mTouchY << ", x2=" << x << ", y2=" << y << ", width=" << width << ", height=" << height);
1422
 
1423
        if (mTouchX < x && (x - mTouchX) > (width / 3))
1424
            gPageManager->onSwipeEvent(TPageManager::SW_RIGHT);
1425
        else if (x < mTouchX && (mTouchX - x) > (width / 3))
1426
            gPageManager->onSwipeEvent(TPageManager::SW_LEFT);
1427
        else if (mTouchY < y && (y - mTouchY) > (height / 3))
1428
            gPageManager->onSwipeEvent(TPageManager::SW_DOWN);
1429
        else if (y < mTouchY && (mTouchY - y) > (height / 3))
1430
            gPageManager->onSwipeEvent(TPageManager::SW_UP);
1431
    }
1432
}
1433
 
1434
void MainWindow::mouseMoveEvent(QMouseEvent* event)
1435
{
1436
    DECL_TRACER("MainWindow::mouseMoveEvent(QMouseEvent* event)");
323 andreas 1437
 
1438
    Q_UNUSED(event);
320 andreas 1439
/*
319 andreas 1440
    QWidget *w = childAt(event->x(), event->y());
1441
 
1442
    if (w)
1443
    {
1444
        MSG_DEBUG("Object " << w->objectName().toStdString() << " is under mouse cursor.");
1445
        QObject *par = w->parent();
1446
 
1447
        if (par)
1448
        {
1449
            MSG_DEBUG("The parent is " << par->objectName().toStdString());
1450
 
1451
            if (par->objectName().startsWith("Item_"))
1452
            {
1453
                QObject *ppar = par->parent();
1454
 
1455
                if (ppar)
1456
                {
1457
                    MSG_DEBUG("The pparent is " << ppar->objectName().toStdString());
1458
 
1459
                    if (ppar->objectName().startsWith("View_"))
1460
                    {
1461
                        QMouseEvent *mev = new QMouseEvent(event->type(), event->localPos(), event->globalPos(), event->button(), event->buttons(), event->modifiers());
1462
                        QApplication::postEvent(ppar, mev);
1463
                        return;
1464
                    }
1465
                }
1466
            }
1467
        }
1468
    }
320 andreas 1469
*/
319 andreas 1470
}
1471
 
1472
void MainWindow::keyPressEvent(QKeyEvent *event)
1473
{
1474
    DECL_TRACER("MainWindow::keyPressEvent(QKeyEvent *event)");
1475
 
1476
    if (event && event->key() == Qt::Key_Back && !mToolbar)
1477
    {
1478
        QMessageBox msgBox(this);
1479
        msgBox.setText("Select what to do next:");
1480
        msgBox.addButton("Quit", QMessageBox::AcceptRole);
1481
        msgBox.addButton("Setup", QMessageBox::RejectRole);
1482
        msgBox.addButton("Cancel", QMessageBox::ResetRole);
1483
        int ret = msgBox.exec();
1484
 
1485
        if (ret == QMessageBox::Accepted)   // This is correct! QT seems to change here the buttons.
1486
        {
1487
            showSetup();
1488
            return;
1489
        }
1490
        else if (ret == QMessageBox::Rejected)  // This is correct! QT seems to change here the buttons.
1491
            close();
1492
    }
1493
}
1494
 
1495
void MainWindow::keyReleaseEvent(QKeyEvent *event)
1496
{
1497
    DECL_TRACER("MainWindow::keyReleaseEvent(QKeyEvent *event)");
1498
 
323 andreas 1499
    Q_UNUSED(event);
319 andreas 1500
}
1501
 
1502
/**
130 andreas 1503
 * @brief MainWindow::onScreenOrientationChanged sets invers or normal orientation.
1504
 * This method sets according to the actual set orientation the invers
1505
 * orientations or switches back to normal orientation.
1506
 * For example: When the orientation is set to portrait and the device is turned
1507
 * to top down, then the orientation is set to invers portrait.
1508
 * @param ori   The detected orientation
1509
 */
1510
void MainWindow::onScreenOrientationChanged(Qt::ScreenOrientation ori)
1511
{
1512
    DECL_TRACER("MainWindow::onScreenOrientationChanged(int ori)");
265 andreas 1513
#if defined(QT_DEBUG) && (defined(Q_OS_IOS) || defined(Q_OS_ANDROID))
298 andreas 1514
    MSG_DEBUG("Orientation changed to " << orientationToString(ori) << " (mOrientation: " << orientationToString(mOrientation) << ")");
263 andreas 1515
#endif
249 andreas 1516
    if (!gPageManager)
130 andreas 1517
        return;
1518
 
249 andreas 1519
    if (gPageManager->getSettings()->isPortrait())
1520
    {
263 andreas 1521
#ifdef Q_OS_IOS
1522
        if (!mHaveNotchPortrait)
1523
            setNotch();
1524
#endif
249 andreas 1525
        if (ori == Qt::PortraitOrientation || ori == Qt::InvertedPortraitOrientation)
1526
        {
264 andreas 1527
#ifdef Q_OS_IOS
1528
            if (mSensor)
1529
                mSensor->setCurrentOrientation(ori);
1530
#endif
249 andreas 1531
            if (mOrientation == ori)
1532
                return;
130 andreas 1533
 
249 andreas 1534
            mOrientation = ori;
1535
        }
1536
        else if (mOrientation != Qt::PortraitOrientation && mOrientation != Qt::InvertedPortraitOrientation)
1537
            mOrientation = Qt::PortraitOrientation;
1538
    }
1539
    else
1540
    {
263 andreas 1541
#ifdef Q_OS_IOS
1542
        if (!mHaveNotchLandscape)
1543
            setNotch();
1544
#endif
249 andreas 1545
        if (ori == Qt::LandscapeOrientation || ori == Qt::InvertedLandscapeOrientation)
1546
        {
264 andreas 1547
#ifdef Q_OS_IOS
1548
            if (mSensor)
1549
                mSensor->setCurrentOrientation(ori);
1550
#endif
249 andreas 1551
            if (mOrientation == ori)
1552
                return;
130 andreas 1553
 
249 andreas 1554
            mOrientation = ori;
1555
        }
1556
        else if (mOrientation != Qt::LandscapeOrientation && mOrientation != Qt::InvertedLandscapeOrientation)
1557
            mOrientation = Qt::LandscapeOrientation;
1558
    }
1559
 
130 andreas 1560
    J_ORIENTATION jori = O_UNDEFINED;
1561
 
249 andreas 1562
    switch(mOrientation)
130 andreas 1563
    {
1564
        case Qt::LandscapeOrientation:          jori = O_LANDSCAPE; break;
1565
        case Qt::InvertedLandscapeOrientation:  jori = O_REVERSE_LANDSCAPE; break;
1566
        case Qt::PortraitOrientation:           jori = O_PORTRAIT; break;
1567
        case Qt::InvertedPortraitOrientation:   jori = O_REVERSE_PORTRAIT; break;
1568
        default:
1569
            return;
1570
    }
1571
 
1572
    _setOrientation(jori);
249 andreas 1573
#ifdef Q_OS_IOS
252 andreas 1574
    setNotch();
1575
#endif
1576
}
386 andreas 1577
#ifdef Q_OS_IOS
252 andreas 1578
/**
1579
 * @brief MainWindow::onPositionUpdated
1580
 * This method is a callback function for the Qt framework. It is called
1581
 * whenever the geo position changes. The position information is never really
1582
 * used and is implemented only to keep the application on IOS running in the
1583
 * background.
1584
 *
1585
 * @param update    A structure containing the geo position information.
1586
 */
386 andreas 1587
 
252 andreas 1588
void MainWindow::onPositionUpdated(const QGeoPositionInfo &update)
1589
{
1590
    DECL_TRACER("MainWindow::onPositionUpdated(const QGeoPositionInfo &update)");
249 andreas 1591
 
252 andreas 1592
    QGeoCoordinate coord = update.coordinate();
1593
    MSG_DEBUG("Geo location: " << coord.toString().toStdString());
130 andreas 1594
}
1595
 
252 andreas 1596
void MainWindow::onErrorOccurred(QGeoPositionInfoSource::Error positioningError)
1597
{
1598
    DECL_TRACER("MainWindow::onErrorOccurred(QGeoPositionInfoSource::Error positioningError)");
1599
 
1600
    switch(positioningError)
1601
    {
386 andreas 1602
        case QGeoPositionInfoSource::AccessError:
1603
            MSG_ERROR("The connection setup to the remote positioning backend failed because the application lacked the required privileges.");
1604
            mGeoHavePermission = false;
1605
        break;
1606
 
252 andreas 1607
        case QGeoPositionInfoSource::ClosedError:   MSG_ERROR("The remote positioning backend closed the connection, which happens for example in case the user is switching location services to off. As soon as the location service is re-enabled regular updates will resume."); break;
1608
        case QGeoPositionInfoSource::UnknownSourceError: MSG_ERROR("An unidentified error occurred."); break;
264 andreas 1609
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
252 andreas 1610
        case QGeoPositionInfoSource::UpdateTimeoutError: MSG_ERROR("Current position could not be retrieved within the specified timeout."); break;
1611
#endif
1612
        default:
1613
            return;
1614
    }
1615
}
386 andreas 1616
#endif  // Q_OS_IOS
130 andreas 1617
/**
140 andreas 1618
 * @brief Displays or hides a phone dialog window.
1619
 * This method creates and displays a phone dialog window containing everything
1620
 * a simple phone needs. Depending on the parameter \p state the dialog is
383 andreas 1621
 * created or an existing dialog is closed.
140 andreas 1622
 * @param state     If TRUE the dialog is created or if it is not visible
1623
 * brought to front and is made visible.
1624
 * If this is FALSE an existing dialog window is destroid and disappears. If
1625
 * the window didn't exist nothing happens.
1626
 */
1627
void MainWindow::showPhoneDialog(bool state)
1628
{
1629
    DECL_TRACER("MainWindow::showPhoneDialog(bool state)");
1630
 
1631
    if (mPhoneDialog)
1632
    {
1633
        if (!state)
1634
        {
1635
            mPhoneDialog->close();
1636
            delete mPhoneDialog;
1637
            mPhoneDialog = nullptr;
1638
            return;
1639
        }
1640
 
1641
        if (!mPhoneDialog->isVisible())
1642
            mPhoneDialog->setVisible(true);
1643
 
1644
        return;
1645
    }
1646
 
1647
    if (!state)
1648
        return;
1649
 
1650
    mPhoneDialog = new TQtPhone(this);
243 andreas 1651
#if defined(Q_OS_ANDROID)
140 andreas 1652
    // On mobile devices we set the scale factor always because otherwise the
1653
    // dialog will be unusable.
1654
    mPhoneDialog->setScaleFactor(gScale);
1655
    mPhoneDialog->doResize();
1656
#endif
1657
    mPhoneDialog->open();
1658
}
1659
 
1660
/**
1661
 * Displays a phone number (can also be an URL) on a label in the phone dialog
1662
 * window.
1663
 * @param number    The string contains the phone number to display.
1664
 */
1665
void MainWindow::setPhoneNumber(const std::string& number)
1666
{
1667
    DECL_TRACER("MainWindow::setPhoneNumber(const std::string& number)");
1668
 
1669
    if (!mPhoneDialog)
1670
        return;
1671
 
1672
    mPhoneDialog->setPhoneNumber(number);
1673
}
1674
 
1675
/**
1676
 * Displays a message in the status line on the bottom of the phone dialog
1677
 * window.
1678
 * @param msg   The string conaining a message.
1679
 */
1680
void MainWindow::setPhoneStatus(const std::string& msg)
1681
{
1682
    DECL_TRACER("MainWindow::setPhoneStatus(const std::string& msg)");
1683
 
1684
    if (!mPhoneDialog)
1685
        return;
1686
 
1687
    mPhoneDialog->setPhoneStatus(msg);
1688
}
1689
 
1690
void MainWindow::setPhoneState(int state, int id)
1691
{
1692
    DECL_TRACER("MainWindow::setPhoneState(int state)");
1693
 
1694
    if (mPhoneDialog)
1695
        mPhoneDialog->setPhoneState(state, id);
1696
}
1697
 
1698
/**
39 andreas 1699
 * @brief MainWindow::createActions creates the toolbar on the right side.
21 andreas 1700
 */
2 andreas 1701
void MainWindow::createActions()
1702
{
5 andreas 1703
    DECL_TRACER("MainWindow::createActions()");
2 andreas 1704
 
151 andreas 1705
    // If the toolbar should not be visible at all we return here immediately.
1706
    if (TConfig::getToolbarSuppress())
1707
        return;
1708
 
88 andreas 1709
    // Add a mToolbar (on the right side)
1710
    mToolbar = new QToolBar(this);
300 andreas 1711
    QPalette palette(mToolbar->palette());
1712
    palette.setColor(QPalette::Window, QColorConstants::Svg::honeydew);
1713
    mToolbar->setPalette(palette);
58 andreas 1714
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
88 andreas 1715
    mToolbar->setAllowedAreas(Qt::RightToolBarArea);
1716
    mToolbar->setFloatable(false);
1717
    mToolbar->setMovable(false);
367 andreas 1718
#if defined(Q_OS_ANDROID) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
259 andreas 1719
    if (isScaled())
38 andreas 1720
    {
217 andreas 1721
        int width = (int)((double)gPageManager->getSettings()->getWidth() * gScale);
38 andreas 1722
        int tbWidth = (int)(48.0 * gScale);
1723
        int icWidth = (int)(40.0 * gScale);
1724
 
120 andreas 1725
        if ((gFullWidth - width) < tbWidth && !TConfig::getToolbarForce())
38 andreas 1726
        {
88 andreas 1727
            delete mToolbar;
1728
            mToolbar = nullptr;
38 andreas 1729
            return;
1730
        }
1731
 
262 andreas 1732
        MSG_DEBUG("Icon size: " << icWidth << "x" << icWidth << ", Toolbar width: " << tbWidth);
38 andreas 1733
        QSize iSize(icWidth, icWidth);
88 andreas 1734
        mToolbar->setIconSize(iSize);
38 andreas 1735
    }
367 andreas 1736
#endif  // QT_VERSION
1737
#if (defined(Q_OS_ANDROID) || defined(Q_OS_IOS)) && QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1738
    if (isScaled())
1739
    {
1740
        int panwidth = (int)((double)gPageManager->getSettings()->getWidth() * gScale);
1741
        int toolwidth = mToolbar->width();
1742
 
1743
        if ((gFullWidth - panwidth) < toolwidth && !TConfig::getToolbarForce())
1744
        {
1745
            delete mToolbar;
1746
            mToolbar = nullptr;
1747
            return;
1748
        }
1749
    }
1750
#endif
39 andreas 1751
#else
88 andreas 1752
    mToolbar->setFloatable(true);
1753
    mToolbar->setMovable(true);
1754
    mToolbar->setAllowedAreas(Qt::RightToolBarArea | Qt::BottomToolBarArea);
243 andreas 1755
#endif  // defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
32 andreas 1756
    QAction *arrowUpAct = new QAction(QIcon(":/images/arrow_up.png"), tr("Up"), this);
1757
    connect(arrowUpAct, &QAction::triggered, this, &MainWindow::arrowUp);
88 andreas 1758
    mToolbar->addAction(arrowUpAct);
31 andreas 1759
 
32 andreas 1760
    QAction *arrowLeftAct = new QAction(QIcon(":/images/arrow_left.png"), tr("Left"), this);
1761
    connect(arrowLeftAct, &QAction::triggered, this, &MainWindow::arrowLeft);
88 andreas 1762
    mToolbar->addAction(arrowLeftAct);
31 andreas 1763
 
32 andreas 1764
    QAction *arrowRightAct = new QAction(QIcon(":/images/arrow_right.png"), tr("Right"), this);
1765
    connect(arrowRightAct, &QAction::triggered, this, &MainWindow::arrowRight);
88 andreas 1766
    mToolbar->addAction(arrowRightAct);
31 andreas 1767
 
32 andreas 1768
    QAction *arrowDownAct = new QAction(QIcon(":/images/arrow_down.png"), tr("Down"), this);
1769
    connect(arrowDownAct, &QAction::triggered, this, &MainWindow::arrowDown);
88 andreas 1770
    mToolbar->addAction(arrowDownAct);
31 andreas 1771
 
32 andreas 1772
    QAction *selectOkAct = new QAction(QIcon(":/images/ok.png"), tr("Ok"), this);
1773
    connect(selectOkAct, &QAction::triggered, this, &MainWindow::selectOk);
88 andreas 1774
    mToolbar->addAction(selectOkAct);
31 andreas 1775
 
88 andreas 1776
    mToolbar->addSeparator();
31 andreas 1777
 
35 andreas 1778
    QToolButton *btVolUp = new QToolButton(this);
1779
    btVolUp->setIcon(QIcon(":/images/vol_up.png"));
1780
    connect(btVolUp, &QToolButton::pressed, this, &MainWindow::volumeUpPressed);
1781
    connect(btVolUp, &QToolButton::released, this, &MainWindow::volumeUpReleased);
88 andreas 1782
    mToolbar->addWidget(btVolUp);
40 andreas 1783
 
35 andreas 1784
    QToolButton *btVolDown = new QToolButton(this);
1785
    btVolDown->setIcon(QIcon(":/images/vol_down.png"));
1786
    connect(btVolDown, &QToolButton::pressed, this, &MainWindow::volumeDownPressed);
1787
    connect(btVolDown, &QToolButton::released, this, &MainWindow::volumeDownReleased);
88 andreas 1788
    mToolbar->addWidget(btVolDown);
38 andreas 1789
/*
33 andreas 1790
    QAction *volMute = new QAction(QIcon(":/images/vol_mute.png"), tr("X"), this);
1791
    connect(volMute, &QAction::triggered, this, &MainWindow::volumeMute);
88 andreas 1792
    mToolbar->addAction(volMute);
38 andreas 1793
*/
88 andreas 1794
    mToolbar->addSeparator();
36 andreas 1795
    const QIcon settingsIcon = QIcon::fromTheme("settings-configure", QIcon(":/images/settings.png"));
5 andreas 1796
    QAction *settingsAct = new QAction(settingsIcon, tr("&Settings..."), this);
1797
    settingsAct->setStatusTip(tr("Change the settings"));
1798
    connect(settingsAct, &QAction::triggered, this, &MainWindow::settings);
88 andreas 1799
    mToolbar->addAction(settingsAct);
250 andreas 1800
 
38 andreas 1801
    const QIcon aboutIcon = QIcon::fromTheme("help-about", QIcon(":/images/info.png"));
5 andreas 1802
    QAction *aboutAct = new QAction(aboutIcon, tr("&About..."), this);
1803
    aboutAct->setShortcuts(QKeySequence::Open);
1804
    aboutAct->setStatusTip(tr("About this program"));
1805
    connect(aboutAct, &QAction::triggered, this, &MainWindow::about);
88 andreas 1806
    mToolbar->addAction(aboutAct);
2 andreas 1807
 
33 andreas 1808
    const QIcon exitIcon = QIcon::fromTheme("application-exit", QIcon(":/images/off.png"));
88 andreas 1809
    QAction *exitAct = mToolbar->addAction(exitIcon, tr("E&xit"), this, &QWidget::close);
5 andreas 1810
    exitAct->setShortcuts(QKeySequence::Quit);
1811
    exitAct->setStatusTip(tr("Exit the application"));
31 andreas 1812
 
88 andreas 1813
    addToolBar(Qt::RightToolBarArea, mToolbar);
2 andreas 1814
}
1815
 
21 andreas 1816
/**
1817
 * @brief MainWindow::settings initiates the configuration dialog.
1818
 */
2 andreas 1819
void MainWindow::settings()
1820
{
5 andreas 1821
    DECL_TRACER("MainWindow::settings()");
251 andreas 1822
#if defined(Q_OS_IOS) || defined(Q_OS_ANDROID)
259 andreas 1823
#ifdef Q_OS_ANDROID
197 andreas 1824
    if (gPageManager)
1825
    {
1826
        gPageManager->showSetup();
1827
        return;
1828
    }
211 andreas 1829
    else    // This "else" should never be executed!
1830
        displayMessage("<b>Fatal error</b>: An internal mandatory class was not initialized!<br>Unable to show setup dialog!", "Fatal error");
1831
#else
259 andreas 1832
    mIOSSettingsActive = true;
250 andreas 1833
    QASettings::openSettings();
238 andreas 1834
#endif
1835
#else
90 andreas 1836
    // Save some old values to decide whether to start over or not.
1837
    string oldHost = TConfig::getController();
1838
    int oldPort = TConfig::getPort();
1839
    int oldChannelID = TConfig::getChannel();
118 andreas 1840
    string oldSurface = TConfig::getFtpSurface();
120 andreas 1841
    bool oldToolbar = TConfig::getToolbarForce();
151 andreas 1842
    bool oldToolbarSuppress = TConfig::getToolbarSuppress();
90 andreas 1843
    // Initialize and open the settings dialog.
5 andreas 1844
    TQtSettings *dlg_settings = new TQtSettings(this);
23 andreas 1845
    int ret = dlg_settings->exec();
118 andreas 1846
    bool rebootAnyway = false;
23 andreas 1847
 
179 andreas 1848
    if ((ret && dlg_settings->hasChanged()) || (ret && dlg_settings->downloadForce()))
89 andreas 1849
    {
23 andreas 1850
        writeSettings();
89 andreas 1851
 
151 andreas 1852
        if (!TConfig::getToolbarSuppress() && oldToolbar != TConfig::getToolbarForce())
120 andreas 1853
        {
122 andreas 1854
            QMessageBox msgBox(this);
120 andreas 1855
            msgBox.setText("The change for the visibility of the toolbar will be active on the next start of TPanel!");
1856
            msgBox.exec();
1857
        }
151 andreas 1858
        else if (oldToolbarSuppress != TConfig::getToolbarSuppress() && TConfig::getToolbarSuppress())
1859
        {
1860
            if (mToolbar)
1861
            {
1862
                mToolbar->close();
1863
                delete mToolbar;
1864
                mToolbar = nullptr;
1865
            }
1866
        }
120 andreas 1867
 
122 andreas 1868
        if (TConfig::getFtpSurface() != oldSurface || dlg_settings->downloadForce())
118 andreas 1869
        {
122 andreas 1870
            bool dlYes = true;
118 andreas 1871
 
179 andreas 1872
            MSG_DEBUG("Surface should be downloaded (Old: " << oldSurface << ", New: " << TConfig::getFtpSurface() << ")");
1873
 
122 andreas 1874
            if (!dlg_settings->downloadForce())
1875
            {
1876
                QMessageBox msgBox(this);
1877
                msgBox.setText(QString("Should the surface <b>") + TConfig::getFtpSurface().c_str() + "</b> be installed?");
1878
                msgBox.addButton(QMessageBox::Yes);
1879
                msgBox.addButton(QMessageBox::No);
1880
                int ret = msgBox.exec();
120 andreas 1881
 
122 andreas 1882
                if (ret == QMessageBox::No)
1883
                    dlYes = false;
1884
            }
119 andreas 1885
 
122 andreas 1886
            if (dlYes)
1887
            {
1888
                TTPInit tpinit;
1889
                tpinit.regCallbackProcessEvents(bind(&MainWindow::runEvents, this));
179 andreas 1890
                tpinit.regCallbackProgressBar(bind(&MainWindow::_onProgressChanged, this, std::placeholders::_1));
122 andreas 1891
                tpinit.setPath(TConfig::getProjectPath());
398 andreas 1892
                tpinit.setFileSize(static_cast<off64_t>(dlg_settings->getSelectedFtpFileSize()));
179 andreas 1893
                string msg = "Loading file <b>" + TConfig::getFtpSurface() + "</b>.";
1894
                MSG_DEBUG("Download of surface " << TConfig::getFtpSurface() << " was forced!");
122 andreas 1895
 
179 andreas 1896
                downloadBar(msg, this);
122 andreas 1897
 
1898
                if (tpinit.loadSurfaceFromController(true))
1899
                    rebootAnyway = true;
1900
 
179 andreas 1901
                mDownloadBar->close();
122 andreas 1902
                mBusy = false;
1903
            }
1904
            else
1905
            {
179 andreas 1906
                MSG_DEBUG("No change of surface. Old surface " << oldSurface << " was saved again.");
122 andreas 1907
                TConfig::saveFtpSurface(oldSurface);
1908
                writeSettings();
1909
            }
118 andreas 1910
        }
1911
 
90 andreas 1912
        if (TConfig::getController() != oldHost ||
1913
            TConfig::getChannel() != oldChannelID ||
118 andreas 1914
            TConfig::getPort() != oldPort || rebootAnyway)
89 andreas 1915
        {
90 andreas 1916
            // Start over by exiting this class
1917
            MSG_INFO("Program will start over!");
1918
            _restart_ = true;
1919
            prg_stopped = true;
1920
            killed = true;
1921
 
1922
            if (gAmxNet)
1923
                gAmxNet->stop();
1924
 
1925
            close();
89 andreas 1926
        }
1927
    }
23 andreas 1928
    else if (!ret && dlg_settings->hasChanged())
1929
    {
1930
        TConfig cf(TConfig::getConfigPath() + "/" + TConfig::getConfigFileName());
1931
    }
44 andreas 1932
 
1933
    delete dlg_settings;
251 andreas 1934
#endif  // defined(Q_OS_IOS) || defined(Q_OS_ANDROID)
2 andreas 1935
}
1936
 
21 andreas 1937
/**
1938
 * @brief MainWindow::writeSettings Writes the settings into the configuration file.
1939
 */
2 andreas 1940
void MainWindow::writeSettings()
1941
{
5 andreas 1942
    DECL_TRACER("MainWindow::writeSettings()");
23 andreas 1943
 
1944
    TConfig::saveSettings();
43 andreas 1945
    MSG_INFO("Wrote settings.");
2 andreas 1946
}
1947
 
21 andreas 1948
/**
1949
 * @brief MainWindow::about displays the _about_ dialog.
1950
 */
2 andreas 1951
void MainWindow::about()
1952
{
5 andreas 1953
    DECL_TRACER("MainWindow::about()");
2 andreas 1954
 
259 andreas 1955
#ifdef Q_OS_IOS
1956
    // On IOS the explicit about dialog is shown over the whole screen with
1957
    // the text in a small stripe on the left. This looks ugly and therefor
1958
    // we construct our own about dialog.
1959
    std::string msg = "About TPanel\n\n";
1960
    msg.append("Simulation of an AMX G4 panel\n");
1961
    msg.append("Version v").append(VERSION_STRING()).append("\n");
260 andreas 1962
    msg.append("(C) Copyright 2020 to 2023 by Andreas Theofilu (andreas@theosys.at)\n");
259 andreas 1963
 
1964
    QMessageBox about(this);
1965
    about.addButton(QMessageBox::Ok);
1966
    about.setWindowTitle(tr("About TPanel"));
1967
    about.setIconPixmap(QPixmap(":images/icon.png"));
1968
    about.setTextFormat(Qt::PlainText);
1969
    about.setText(tr(msg.c_str()));
1970
    about.setInformativeText(tr("This program is under the terms of GPL version 3!"));
1971
    about.exec();
1972
#else
82 andreas 1973
    std::string msg = "Simulation of an AMX G4 panel\n";
1974
    msg.append("Version v").append(VERSION_STRING()).append("\n");
259 andreas 1975
    msg.append("(C) Copyright 2020 to 2023 by Andreas Theofilu <andreas@theosys.at>\n");
1976
    msg.append("This program is under the terms of GPL version 3!");
1977
    QMessageBox::about(this, tr("About TPanel"), tr(msg.c_str()));
1978
#endif
2 andreas 1979
}
1980
 
32 andreas 1981
void MainWindow::arrowUp()
1982
{
1983
    DECL_TRACER("MainWindow::arrowUp()");
35 andreas 1984
 
1985
    extButtons_t btType = EXT_CURSOR_UP;
1986
 
1987
    if (TConfig::getPanelType().find("Android") != string::npos)
1988
        btType = EXT_GESTURE_UP;
1989
 
92 andreas 1990
    gPageManager->externalButton(btType, true);
1991
    gPageManager->externalButton(btType, false);
32 andreas 1992
}
14 andreas 1993
 
32 andreas 1994
void MainWindow::arrowLeft()
1995
{
1996
    DECL_TRACER("MainWindow::arrowLeft()");
35 andreas 1997
    extButtons_t btType = EXT_CURSOR_LEFT;
1998
 
1999
    if (TConfig::getPanelType().find("Android") != string::npos)
2000
        btType = EXT_GESTURE_LEFT;
2001
 
92 andreas 2002
    gPageManager->externalButton(btType, true);
2003
    gPageManager->externalButton(btType, false);
32 andreas 2004
}
2005
 
2006
void MainWindow::arrowRight()
2007
{
2008
    DECL_TRACER("MainWindow::arrowRight()");
35 andreas 2009
    extButtons_t btType = EXT_CURSOR_RIGHT;
2010
 
2011
    if (TConfig::getPanelType().find("Android") != string::npos)
2012
        btType = EXT_GESTURE_RIGHT;
2013
 
92 andreas 2014
    gPageManager->externalButton(btType, true);
2015
    gPageManager->externalButton(btType, false);
32 andreas 2016
}
2017
 
2018
void MainWindow::arrowDown()
2019
{
2020
    DECL_TRACER("MainWindow::arrowDown()");
35 andreas 2021
    extButtons_t btType = EXT_CURSOR_DOWN;
2022
 
2023
    if (TConfig::getPanelType().find("Android") != string::npos)
2024
        btType = EXT_GESTURE_DOWN;
2025
 
92 andreas 2026
    gPageManager->externalButton(btType, true);
2027
    gPageManager->externalButton(btType, false);
32 andreas 2028
}
2029
 
2030
void MainWindow::selectOk()
2031
{
2032
    DECL_TRACER("MainWindow::selectOk()");
35 andreas 2033
    extButtons_t btType = EXT_CURSOR_SELECT;
2034
 
2035
    if (TConfig::getPanelType().find("Android") != string::npos)
2036
        btType = EXT_GESTURE_DOUBLE_PRESS;
2037
 
92 andreas 2038
    gPageManager->externalButton(btType, true);
2039
    gPageManager->externalButton(btType, false);
32 andreas 2040
}
2041
 
33 andreas 2042
void MainWindow::volumeUpPressed()
2043
{
2044
    DECL_TRACER("MainWindow::volumeUpPressed()");
35 andreas 2045
    extButtons_t btType = EXT_CURSOR_ROTATE_RIGHT;
2046
 
2047
    if (TConfig::getPanelType().find("Android") != string::npos)
2048
        btType = EXT_GESTURE_ROTATE_RIGHT;
2049
 
92 andreas 2050
    gPageManager->externalButton(btType, true);
33 andreas 2051
}
2052
 
2053
void MainWindow::volumeUpReleased()
2054
{
2055
    DECL_TRACER("MainWindow::volumeUpReleased()");
35 andreas 2056
    extButtons_t btType = EXT_CURSOR_ROTATE_RIGHT;
2057
 
2058
    if (TConfig::getPanelType().find("Android") != string::npos)
2059
        btType = EXT_GESTURE_ROTATE_RIGHT;
2060
 
92 andreas 2061
    gPageManager->externalButton(btType, false);
33 andreas 2062
}
2063
 
2064
void MainWindow::volumeDownPressed()
2065
{
2066
    DECL_TRACER("MainWindow::volumeDownPressed()");
35 andreas 2067
    extButtons_t btType = EXT_CURSOR_ROTATE_LEFT;
2068
 
2069
    if (TConfig::getPanelType().find("Android") != string::npos)
2070
        btType = EXT_GESTURE_ROTATE_LEFT;
2071
 
92 andreas 2072
    gPageManager->externalButton(btType, true);
33 andreas 2073
}
2074
 
2075
void MainWindow::volumeDownReleased()
2076
{
2077
    DECL_TRACER("MainWindow::volumeDownReleased()");
35 andreas 2078
    extButtons_t btType = EXT_CURSOR_ROTATE_LEFT;
2079
 
2080
    if (TConfig::getPanelType().find("Android") != string::npos)
2081
        btType = EXT_GESTURE_ROTATE_LEFT;
2082
 
92 andreas 2083
    gPageManager->externalButton(btType, false);
33 andreas 2084
}
38 andreas 2085
/*
33 andreas 2086
void MainWindow::volumeMute()
2087
{
2088
    DECL_TRACER("MainWindow::volumeMute()");
92 andreas 2089
    gPageManager->externalButton(EXT_GENERAL, true);
2090
    gPageManager->externalButton(EXT_GENERAL, false);
33 andreas 2091
}
38 andreas 2092
*/
295 andreas 2093
 
2094
void MainWindow::animationInFinished()
2095
{
2096
    DECL_TRACER("MainWindow::animationInFinished()");
2097
 
350 andreas 2098
    if (mAnimObjects.empty())
2099
    {
2100
#if TESTMODE == 1
2101
        setScreenDone();
2102
#endif
2103
        return;
2104
    }
2105
 
369 andreas 2106
//    TLOCKER(anim_mutex);
296 andreas 2107
    map<ulong, OBJECT_t *>::iterator iter;
2108
 
2109
    for (iter = mAnimObjects.begin(); iter != mAnimObjects.end(); ++iter)
295 andreas 2110
    {
296 andreas 2111
        if (!iter->second->animation)
2112
            continue;
295 andreas 2113
 
297 andreas 2114
        if (!iter->second->invalid && iter->second->type == OBJ_SUBPAGE && iter->second->animation->state() == QAbstractAnimation::Stopped)
295 andreas 2115
        {
296 andreas 2116
            if (iter->second->object.widget)
2117
            {
2118
                iter->second->object.widget->lower();
2119
                iter->second->object.widget->show();
2120
                iter->second->object.widget->raise();
2121
            }
2122
 
2123
            disconnect(iter->second->animation, &QPropertyAnimation::finished, this, &MainWindow::animationInFinished);
2124
            delete iter->second->animation;
2125
            iter->second->animation = nullptr;
295 andreas 2126
        }
296 andreas 2127
    }
295 andreas 2128
 
296 andreas 2129
    // Delete all empty/finished animations
2130
    bool repeat = false;
2131
 
2132
    do
2133
    {
2134
        repeat = false;
2135
 
2136
        for (iter = mAnimObjects.begin(); iter != mAnimObjects.end(); ++iter)
2137
        {
2138
            if (!iter->second->remove && !iter->second->animation)
2139
            {
2140
                mAnimObjects.erase(iter);
2141
                repeat = true;
2142
                break;
2143
            }
2144
        }
295 andreas 2145
    }
296 andreas 2146
    while (repeat);
332 andreas 2147
#if TESTMODE == 1
2148
    __success = true;
334 andreas 2149
    setScreenDone();
332 andreas 2150
#endif
295 andreas 2151
}
2152
 
42 andreas 2153
void MainWindow::animationFinished()
2154
{
2155
    DECL_TRACER("MainWindow::animationFinished()");
43 andreas 2156
 
350 andreas 2157
    if (mAnimObjects.empty())
2158
    {
2159
#if TESTMODE == 1
2160
        setScreenDone();
2161
#endif
2162
        return;
2163
    }
2164
 
369 andreas 2165
//    TLOCKER(anim_mutex);
296 andreas 2166
    map<ulong, OBJECT_t *>::iterator iter;
43 andreas 2167
 
296 andreas 2168
    for (iter = mAnimObjects.begin(); iter != mAnimObjects.end(); ++iter)
42 andreas 2169
    {
297 andreas 2170
        OBJECT_t *obj = findObject(iter->first);
2171
 
2172
        if (obj && obj->remove && obj->animation && obj->animation->state() == QAbstractAnimation::Stopped)
296 andreas 2173
        {
2174
            MSG_DEBUG("Invalidating object " << handleToString(iter->first));
297 andreas 2175
            disconnect(obj->animation, &QPropertyAnimation::finished, this, &MainWindow::animationFinished);
2176
            delete obj->animation;
2177
            obj->animation = nullptr;
296 andreas 2178
            invalidateAllSubObjects(iter->first);
2179
            invalidateObject(iter->first);
43 andreas 2180
 
297 andreas 2181
            if (obj->type == OBJ_SUBPAGE && obj->object.widget)
2182
                obj->object.widget->hide();
296 andreas 2183
        }
42 andreas 2184
    }
296 andreas 2185
    // Delete all empty/finished animations
2186
    bool repeat = false;
43 andreas 2187
 
296 andreas 2188
    do
42 andreas 2189
    {
296 andreas 2190
        repeat = false;
101 andreas 2191
 
296 andreas 2192
        for (iter = mAnimObjects.begin(); iter != mAnimObjects.end(); ++iter)
2193
        {
2194
            if (iter->second->remove && !iter->second->animation)
2195
            {
2196
                mAnimObjects.erase(iter);
2197
                repeat = true;
2198
                break;
2199
            }
2200
        }
42 andreas 2201
    }
296 andreas 2202
    while (repeat);
332 andreas 2203
#if TESTMODE == 1
2204
    __success = true;
334 andreas 2205
    setScreenDone();
332 andreas 2206
#endif
42 andreas 2207
}
2208
 
142 andreas 2209
void MainWindow::repaintWindows()
2210
{
2211
    DECL_TRACER("MainWindow::repaintWindows()");
2212
 
2213
    if (mWasInactive)
148 andreas 2214
    {
2215
        MSG_INFO("Refreshing of visible popups will be requested.");
142 andreas 2216
        mDoRepaint = true;
148 andreas 2217
    }
142 andreas 2218
}
2219
 
151 andreas 2220
void MainWindow::toFront(ulong handle)
2221
{
2222
    DECL_TRACER("MainWindow::toFront(ulong handle)");
2223
 
277 andreas 2224
    TObject::OBJECT_t *obj = findObject(handle);
151 andreas 2225
 
2226
    if (!obj)
2227
    {
271 andreas 2228
        MSG_WARNING("Object with " << handleToString(handle) << " not found!");
332 andreas 2229
#if TESTMODE == 1
334 andreas 2230
        setScreenDone();
332 andreas 2231
#endif
151 andreas 2232
        return;
2233
    }
2234
 
2235
    if (obj->type == TObject::OBJ_SUBPAGE && obj->object.widget)
2236
        obj->object.widget->raise();
332 andreas 2237
#if TESTMODE == 1
2238
    __success = true;
334 andreas 2239
    setScreenDone();
332 andreas 2240
#endif
151 andreas 2241
}
2242
 
206 andreas 2243
void MainWindow::downloadSurface(const string &file, size_t size)
205 andreas 2244
{
206 andreas 2245
    DECL_TRACER("MainWindow::downloadSurface(const string &file, size_t size)");
205 andreas 2246
 
206 andreas 2247
    if (mBusy)
205 andreas 2248
        return;
2249
 
206 andreas 2250
    QMessageBox msgBox(this);
208 andreas 2251
    msgBox.setText(QString("Should the surface <b>") + file.c_str() + "</b> be installed?<br><i><u>Hint</u>: This will also save all current made settings.</i>");
206 andreas 2252
    msgBox.addButton(QMessageBox::Yes);
2253
    msgBox.addButton(QMessageBox::No);
2254
    int ret = msgBox.exec();
2255
 
2256
    if (ret == QMessageBox::Yes)
2257
    {
2258
        TTPInit tpinit;
2259
        tpinit.regCallbackProcessEvents(bind(&MainWindow::runEvents, this));
2260
        tpinit.regCallbackProgressBar(bind(&MainWindow::_onProgressChanged, this, std::placeholders::_1));
2261
        tpinit.setPath(TConfig::getProjectPath());
208 andreas 2262
 
2263
        if (size)
398 andreas 2264
            tpinit.setFileSize(static_cast<off64_t>(size));
208 andreas 2265
        else
2266
        {
398 andreas 2267
            size = static_cast<size_t>(tpinit.getFileSize(file));
208 andreas 2268
 
2269
            if (!size)
2270
            {
2271
                displayMessage("File <b>" + file + "</b> either doesn't exist on " + TConfig::getController() + " or the NetLinx is not reachable!", "Error");
2272
                return;
2273
            }
2274
 
398 andreas 2275
            tpinit.setFileSize(static_cast<off64_t>(size));
208 andreas 2276
        }
2277
 
206 andreas 2278
        string msg = "Loading file <b>" + file + "</b>.";
2279
 
2280
        downloadBar(msg, this);
2281
        bool reboot = false;
2282
 
2283
        if (tpinit.loadSurfaceFromController(true))
2284
            reboot = true;
2285
        else
2286
            displayMessage("Error downloading file <b>" + file + "</b>!", "Error");
2287
 
2288
        mDownloadBar->close();
208 andreas 2289
        TConfig::setTemporary(true);
2290
        TConfig::saveSettings();
206 andreas 2291
 
2292
        if (reboot)
2293
        {
2294
            // Start over by exiting this class
2295
            MSG_INFO("Program will start over!");
2296
            _restart_ = true;
2297
            prg_stopped = true;
2298
            killed = true;
2299
 
2300
            if (gAmxNet)
2301
                gAmxNet->stop();
2302
 
2303
            close();
2304
        }
2305
    }
2306
 
2307
    mBusy = false;
2308
}
2309
 
2310
void MainWindow::displayMessage(const string &msg, const string &title)
2311
{
2312
    DECL_TRACER("MainWindow::displayMessage(const string &msg, const string &title)");
2313
 
2314
    QMessageBox msgBox(this);
259 andreas 2315
    msgBox.setText(msg.c_str());
206 andreas 2316
 
2317
    if (!title.empty())
2318
        msgBox.setWindowTitle(title.c_str());
2319
 
259 andreas 2320
    msgBox.setWindowModality(Qt::WindowModality::ApplicationModal);
206 andreas 2321
    msgBox.addButton(QMessageBox::Ok);
2322
    msgBox.exec();
2323
}
2324
 
401 andreas 2325
void MainWindow::askPassword(ulong handle, const string msg, const string& title, int x, int y)
396 andreas 2326
{
401 andreas 2327
    DECL_TRACER("MainWindow::askPassword(const string msg, const string& title, int x, int y)");
396 andreas 2328
 
2329
    TQtInputLine *inputLine = new TQtInputLine(this);
2330
    inputLine->setMessage(msg);
2331
    inputLine->setWindowTitle(title.c_str());
2332
    inputLine->setWindowModality(Qt::WindowModality::ApplicationModal);
2333
    inputLine->setPassword(true);
2334
    int bt = inputLine->exec();
2335
 
2336
    if (bt == QDialog::Rejected)
2337
    {
2338
        if (gPageManager)
401 andreas 2339
            gPageManager->callSetPassword(handle, "", x, y);
396 andreas 2340
 
2341
        delete inputLine;
2342
        return;
2343
    }
2344
 
2345
    if (gPageManager)
401 andreas 2346
        gPageManager->callSetPassword(handle, inputLine->getText(), x, y);
396 andreas 2347
 
2348
    delete inputLine;
2349
}
2350
 
209 andreas 2351
void MainWindow::fileDialog(ulong handle, const string &path, const std::string& extension, const std::string& suffix)
2352
{
2353
    DECL_TRACER("MainWindow::fileDialog(ulong handle, const string &path, const std::string& extension, const std::string& suffix)");
2354
 
2355
    std::string pt = path;
2356
 
2357
    if (fs::exists(path) && fs::is_regular_file(path))
2358
    {
2359
        size_t pos = pt.find_last_of("/");
2360
 
2361
        if (pos != std::string::npos)
2362
            pt = pt.substr(0, pos);
2363
        else
2364
        {
2365
            char hv0[4096];
2366
            getcwd(hv0, sizeof(hv0));
2367
            pt = hv0;
2368
        }
2369
    }
2370
 
2371
    QString actPath(pt.c_str());
2372
    QFileDialog fdialog(this, tr("File"), actPath, tr(extension.c_str()));
2373
    fdialog.setAcceptMode(QFileDialog::AcceptSave);
2374
 
2375
    if (!suffix.empty())
2376
        fdialog.setDefaultSuffix(suffix.c_str());
2377
 
2378
    fdialog.setOption(QFileDialog::DontConfirmOverwrite);
2379
    QString fname;
2380
 
2381
    if (fdialog.exec())
2382
    {
2383
        QDir dir = fdialog.directory();
2384
        QStringList list = fdialog.selectedFiles();
2385
 
2386
        if (list.size() > 0)
2387
            fname = dir.absoluteFilePath(list.at(0));
2388
        else
2389
            return;
2390
    }
2391
    else
2392
        return;
2393
 
2394
#ifdef Q_OS_ANDROID
247 andreas 2395
    // In case of Android we get some kind of URL instead of a clear
209 andreas 2396
    // path. Because of this we must call some Java API functions to find the
2397
    // real path.
2398
    QString fileName = fname;
2399
 
2400
    if (fileName.contains("content://"))
2401
    {
264 andreas 2402
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
209 andreas 2403
        QAndroidJniObject uri = QAndroidJniObject::callStaticObjectMethod(
2404
            "android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;",
2405
            QAndroidJniObject::fromString(fileName).object<jstring>());
2406
 
2407
        fileName = QAndroidJniObject::callStaticObjectMethod(
2408
            "org/qtproject/theosys/UriToPath", "getFileName",
2409
            "(Landroid/net/Uri;Landroid/content/Context;)Ljava/lang/String;",
2410
            uri.object(), QtAndroid::androidContext().object()).toString();
2411
#else   // QT5_LINUX
2412
        // For QT6 the API has slightly changed. Especialy the class name to
2413
        // call Java objects.
2414
        QJniObject uri = QJniObject::callStaticObjectMethod(
2415
            "android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;",
2416
            QJniObject::fromString(fileName).object<jstring>());
2417
 
2418
        fileName = QJniObject::callStaticObjectMethod(
2419
            "org/qtproject/theosys/UriToPath", "getFileName",
2420
            "(Landroid/net/Uri;Landroid/content/Context;)Ljava/lang/String;",
2421
            uri.object(), QNativeInterface::QAndroidApplication::context()).toString();
2422
#endif  // QT5_LINUX
2423
        if (fileName.length() > 0)
2424
            fname = fileName;
2425
    }
2426
    else
2427
    {
2428
        MSG_WARNING("Not an Uri? (" << fname.toStdString() << ")");
2429
    }
2430
#endif  // Q_OS_ANDROID
2431
 
2432
    if (gPageManager)
2433
        gPageManager->setTextToButton(handle, fname.toStdString(), true);
2434
}
2435
 
213 andreas 2436
void MainWindow::onTListCallbackCurrentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
206 andreas 2437
{
332 andreas 2438
    DECL_TRACER("MainWindow::onTListCallbackCurrentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)");
206 andreas 2439
 
2440
    if (!current || current == previous)
2441
        return;
2442
 
205 andreas 2443
    QListWidget *w = current->listWidget();
277 andreas 2444
    TObject::OBJECT_t *objWindow = findFirstWindow();
205 andreas 2445
 
2446
    while(objWindow)
2447
    {
277 andreas 2448
        TObject::OBJECT_t *objItem = findFirstChild(objWindow->handle);
205 andreas 2449
 
206 andreas 2450
        while (objItem)
205 andreas 2451
        {
206 andreas 2452
            if (objItem->type == TObject::OBJ_LIST && objItem->object.list == w)
2453
            {
2454
                int row = objItem->object.list->currentRow();
2455
                gPageManager->setSelectedRow(objItem->handle, row + 1, current->text().toStdString());
2456
                return;
2457
            }
2458
 
277 andreas 2459
            objItem = findNextChild(objItem->handle);
205 andreas 2460
        }
206 andreas 2461
 
277 andreas 2462
        objWindow = findNextWindow(objWindow);
205 andreas 2463
    }
2464
}
2465
 
179 andreas 2466
void MainWindow::onProgressChanged(int percent)
2467
{
2468
    DECL_TRACER("MainWindow::onProgressChanged(int percent)");
2469
 
2470
    if (!mDownloadBar || !mBusy)
2471
        return;
2472
 
2473
    mDownloadBar->setProgress(percent);
2474
}
2475
 
260 andreas 2476
void MainWindow::startWait(const string& text)
2477
{
2478
    DECL_TRACER("MainWindow::startWait(const string& text)");
2479
 
2480
    if (mWaitBox)
2481
    {
2482
        mWaitBox->setText(text);
2483
        return;
2484
    }
2485
 
2486
    mWaitBox = new TQtWait(this, text);
2487
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
2488
    mWaitBox->setScaleFactor(mScaleFactor);
2489
    mWaitBox->doResize();
2490
    mWaitBox->start();
2491
#endif
2492
}
2493
 
2494
void MainWindow::stopWait()
2495
{
2496
    DECL_TRACER("MainWindow::stopWait()");
2497
 
2498
    if (!mWaitBox)
2499
        return;
2500
 
2501
    mWaitBox->end();
2502
    delete mWaitBox;
2503
    mWaitBox = nullptr;
2504
}
2505
 
273 andreas 2506
void MainWindow::pageFinished(ulong handle)
271 andreas 2507
{
2508
    DECL_TRACER("MainWindow::pageFinished(uint handle)");
2509
 
277 andreas 2510
    TObject::OBJECT_t *obj = findObject(handle);
273 andreas 2511
 
279 andreas 2512
    if (obj)
2513
    {
298 andreas 2514
        if (obj->type == TObject::OBJ_SUBPAGE && (obj->animate.showEffect == SE_NONE || obj->animate.showTime <= 0) && obj->object.widget)
295 andreas 2515
        {
297 andreas 2516
            if (!obj->object.widget->isEnabled())
2517
                obj->object.widget->setEnabled(true);
2518
 
295 andreas 2519
            obj->object.widget->lower();
279 andreas 2520
            obj->object.widget->show();
295 andreas 2521
            obj->object.widget->raise();
2522
        }
297 andreas 2523
 
295 andreas 2524
        if (obj->type == TObject::OBJ_SUBPAGE && obj->animate.showEffect != SE_NONE && obj->object.widget)
2525
        {
298 andreas 2526
            if (startAnimation(obj, obj->animate))
2527
                return;
295 andreas 2528
        }
279 andreas 2529
 
2530
        if ((obj->type == TObject::OBJ_PAGE || obj->type == TObject::OBJ_SUBPAGE) && obj->object.widget)
2531
        {
2532
            QObjectList list = obj->object.widget->children();
2533
            QObjectList::Iterator iter;
2534
 
2535
            for (iter = list.begin(); iter != list.end(); ++iter)
2536
            {
2537
                QObject *o = *iter;
297 andreas 2538
                ulong child = extractHandle(o->objectName().toStdString());
2539
                OBJECT_t *obj = nullptr;
279 andreas 2540
 
297 andreas 2541
                if (child && (obj = findObject(child)) != nullptr)
279 andreas 2542
                {
297 andreas 2543
                    if (obj->invalid && obj->type != OBJ_SUBPAGE)
2544
                        obj->invalid = false;
279 andreas 2545
 
297 andreas 2546
                    if (obj->remove)
2547
                        obj->remove = false;
2548
 
2549
                    switch (obj->type)
279 andreas 2550
                    {
297 andreas 2551
                        case OBJ_PAGE:
2552
                        case OBJ_SUBPAGE:
2553
                            if (obj->object.widget && !obj->invalid && obj->object.widget->isHidden())
2554
                            {
2555
                                if (!obj->object.widget->isEnabled())
2556
                                    obj->object.widget->setEnabled(true);
2557
 
298 andreas 2558
                                obj->object.widget->lower();
297 andreas 2559
                                obj->object.widget->show();
298 andreas 2560
                                obj->object.widget->raise();
297 andreas 2561
                            }
2562
                        break;
2563
 
2564
                        case OBJ_BUTTON:
2565
                            if (obj->object.label && obj->object.label->isHidden())
2566
                                obj->object.label->show();
2567
                        break;
2568
 
391 andreas 2569
                        case OBJ_MARQUEE:
2570
                            if (obj->object.marquee && obj->object.marquee->isHidden())
2571
                                obj->object.marquee->show();
2572
                        break;
2573
 
297 andreas 2574
                        case OBJ_INPUT:
2575
                        case OBJ_TEXT:
2576
                            if (obj->object.plaintext && obj->object.plaintext->isHidden())
2577
                                obj->object.plaintext->show();
2578
                        break;
2579
 
2580
                        case OBJ_LIST:
2581
                            if (obj->object.list && obj->object.list->isHidden())
2582
                                obj->object.list->show();
2583
                        break;
2584
 
2585
                        case OBJ_SUBVIEW:
2586
                            if (obj->object.area && obj->object.area->isHidden())
298 andreas 2587
                            {
2588
                                obj->object.area->lower();
297 andreas 2589
                                obj->object.area->show();
298 andreas 2590
                                obj->object.area->raise();
2591
                            }
297 andreas 2592
                        break;
2593
 
2594
                        case OBJ_VIDEO:
2595
                            if (obj->object.vwidget && obj->object.vwidget->isHidden())
2596
                                obj->object.vwidget->show();
2597
                        break;
2598
 
2599
                        default:
2600
                            MSG_WARNING("Object " << handleToString(child) << " is an invalid type!");
279 andreas 2601
                    }
2602
                }
297 andreas 2603
                else
2604
                {
2605
                    QString obName = o->objectName();
2606
 
2607
                    if (obName.startsWith("Label_"))
2608
                    {
2609
                        QLabel *l = dynamic_cast<QLabel *>(o);
2610
 
2611
                        if (l->isHidden())
2612
                            l->show();
2613
                    }
2614
                }
279 andreas 2615
            }
2616
        }
284 andreas 2617
 
296 andreas 2618
        if (obj->type == OBJ_SUBVIEW && obj->object.area)
285 andreas 2619
            obj->object.area->show();
332 andreas 2620
#if TESTMODE == 1
2621
        __success = true;
2622
#endif
279 andreas 2623
    }
297 andreas 2624
#ifdef QT_DEBUG
2625
    else
2626
    {
2627
        MSG_WARNING("Object " << handleToString(handle) << " not found!");
2628
    }
2629
#endif
332 andreas 2630
#if TESTMODE == 1
334 andreas 2631
    setScreenDone();
332 andreas 2632
#endif
271 andreas 2633
}
2634
 
61 andreas 2635
/**
2636
 * @brief MainWindow::appStateChanged - Is called whenever the state of the app changes.
2637
 * This callback method is called whenever the state of the application
2638
 * changes. This is mostly usefull on mobile devices. Whenever the main window
2639
 * looses the focus (screen closed, application is put into background, ...)
2640
 * this method is called and updates a flag. If the application is not able
2641
 * to draw to the screen (suspended) all events are cached. At the moment the
2642
 * application becomes active, all queued messages are applied.
2643
 * @param state     The new state of the application.
2644
 */
213 andreas 2645
void MainWindow::onAppStateChanged(Qt::ApplicationState state)
31 andreas 2646
{
265 andreas 2647
    DECL_TRACER("MainWindow::onAppStateChanged(Qt::ApplicationState state)");
31 andreas 2648
 
2649
    switch (state)
2650
    {
61 andreas 2651
        case Qt::ApplicationSuspended:              // Should not occure on a normal desktop
36 andreas 2652
            MSG_INFO("Switched to mode SUSPEND");
31 andreas 2653
            mHasFocus = false;
131 andreas 2654
#ifdef Q_OS_ANDROID
264 andreas 2655
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
131 andreas 2656
            QAndroidJniObject::callStaticMethod<void>("org/qtproject/theosys/Orientation", "pauseOrientationListener", "()V");
182 andreas 2657
#else
2658
            QJniObject::callStaticMethod<void>("org/qtproject/theosys/Orientation", "pauseOrientationListener", "()V");
2659
#endif
183 andreas 2660
#endif
31 andreas 2661
        break;
61 andreas 2662
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)      // On a normal desktop we can ignore this signals
31 andreas 2663
        case Qt::ApplicationInactive:
36 andreas 2664
            MSG_INFO("Switched to mode INACTIVE");
31 andreas 2665
            mHasFocus = false;
142 andreas 2666
            mWasInactive = true;
235 andreas 2667
#ifdef Q_OS_ANDROID
264 andreas 2668
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
131 andreas 2669
            QAndroidJniObject::callStaticMethod<void>("org/qtproject/theosys/Orientation", "pauseOrientationListener", "()V");
182 andreas 2670
#else
2671
            QJniObject::callStaticMethod<void>("org/qtproject/theosys/Orientation", "pauseOrientationListener", "()V");
2672
#endif
235 andreas 2673
#endif
31 andreas 2674
        break;
2675
 
2676
        case Qt::ApplicationHidden:
36 andreas 2677
            MSG_INFO("Switched to mode HIDDEN");
31 andreas 2678
            mHasFocus = false;
235 andreas 2679
#ifdef Q_OS_ANDROID
264 andreas 2680
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
131 andreas 2681
            QAndroidJniObject::callStaticMethod<void>("org/qtproject/theosys/Orientation", "pauseOrientationListener", "()V");
182 andreas 2682
#else
2683
            QJniObject::callStaticMethod<void>("org/qtproject/theosys/Orientation", "pauseOrientationListener", "()V");
2684
#endif
235 andreas 2685
#endif
31 andreas 2686
        break;
61 andreas 2687
#endif
31 andreas 2688
        case Qt::ApplicationActive:
36 andreas 2689
            MSG_INFO("Switched to mode ACTIVE");
31 andreas 2690
            mHasFocus = true;
387 andreas 2691
#ifdef Q_OS_IOS
386 andreas 2692
            initGeoLocation();
387 andreas 2693
#endif
92 andreas 2694
            if (!isRunning && gPageManager)
38 andreas 2695
            {
2696
                // Start the core application
92 andreas 2697
                gPageManager->startUp();
2698
                gPageManager->run();
38 andreas 2699
                isRunning = true;
142 andreas 2700
                mWasInactive = false;
252 andreas 2701
#ifdef Q_OS_IOS
386 andreas 2702
                // To get the battery level periodicaly we setup a timer.
2703
                if (!mIosBattery)
392 andreas 2704
                    mIosBattery = new TIOSBattery;
252 andreas 2705
 
386 andreas 2706
                mIosBattery->update();
252 andreas 2707
 
386 andreas 2708
                int left = mIosBattery->getBatteryLeft();
392 andreas 2709
                int stat = mIosBattery->getBatteryState();
2710
                MSG_DEBUG("iOS battery state: " << left << "%, State: " << stat);
386 andreas 2711
                // At this point no buttons are registered and therefore the battery
2712
                // state will not be visible. To have the state at the moment a button
2713
                // is registered, we tell the page manager to store the values.
392 andreas 2714
                gPageManager->setBattery(left, stat);
2715
                gPageManager->informBatteryStatus(left, stat);
386 andreas 2716
 
252 andreas 2717
                if (mSensor)
2718
                {
263 andreas 2719
                    if (mIosRotate && mOrientation == Qt::PrimaryOrientation) // Unknown?
2720
                    {
2721
                        switch(mIosRotate->getCurrentOrientation())
2722
                        {
2723
                            case O_PORTRAIT:            mOrientation = Qt::PortraitOrientation; break;
2724
                            case O_REVERSE_PORTRAIT:    mOrientation = Qt::InvertedPortraitOrientation; break;
2725
                            case O_REVERSE_LANDSCAPE:   mOrientation = Qt::InvertedLandscapeOrientation; break;
2726
                            case O_LANDSCAPE:           mOrientation = Qt::LandscapeOrientation; break;
2727
                        }
2728
                    }
399 andreas 2729
#if defined(QT_DEBUG) && (defined(Q_OS_IOS) || defined(Q_OS_ANDROID))
263 andreas 2730
                    MSG_DEBUG("Orientation after activate: " << orientationToString(mOrientation));
399 andreas 2731
#endif
386 andreas 2732
                    if (gPageManager && mIosRotate)
264 andreas 2733
                    {
386 andreas 2734
                        if (gPageManager->getSettings()->isPortrait() && mOrientation != Qt::PortraitOrientation)
2735
                        {
2736
                            mIosRotate->rotate(O_PORTRAIT);
2737
                            mOrientation = Qt::PortraitOrientation;
2738
                        }
2739
                        else if (mOrientation != Qt::LandscapeOrientation)
2740
                        {
2741
                            mIosRotate->rotate(O_LANDSCAPE);
2742
                            mOrientation = Qt::LandscapeOrientation;
2743
                        }
264 andreas 2744
                    }
263 andreas 2745
 
2746
                    setNotch();
252 andreas 2747
                }
2748
#endif
38 andreas 2749
            }
2750
            else
142 andreas 2751
            {
264 andreas 2752
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) && defined(Q_OS_ANDROID)
217 andreas 2753
                _freezeWorkaround();
2754
#endif
383 andreas 2755
                if (mDoRepaint || mWasInactive)
2756
                    repaintObjects();
142 andreas 2757
 
2758
                mDoRepaint = false;
2759
                mWasInactive = false;
2760
            }
131 andreas 2761
#ifdef Q_OS_ANDROID
264 andreas 2762
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
271 andreas 2763
            QAndroidJniObject activity = QtAndroid::androidActivity();
2764
            QAndroidJniObject::callStaticMethod<void>("org/qtproject/theosys/HideToolbar", "hide", "(Landroid/app/Activity;Z)V", activity.object(), true);
131 andreas 2765
            QAndroidJniObject::callStaticMethod<void>("org/qtproject/theosys/Orientation", "resumeOrientationListener", "()V");
182 andreas 2766
#else
271 andreas 2767
            QJniObject activity = QNativeInterface::QAndroidApplication::context();
369 andreas 2768
//            QJniObject::callStaticMethod<void>("org/qtproject/theosys/HideToolbar", "hide", "(Landroid/app/Activity;Z)V", activity.object(), true);
182 andreas 2769
            QJniObject::callStaticMethod<void>("org/qtproject/theosys/Orientation", "resumeOrientationListener", "()V");
131 andreas 2770
#endif
182 andreas 2771
#endif
249 andreas 2772
#ifdef Q_OS_IOS
392 andreas 2773
            // We do this to make sure the battery state is up to date after the
2774
            // screen was reactivated.
2775
            int left = mIosBattery->getBatteryLeft();
2776
            int stat = mIosBattery->getBatteryState();
2777
            gPageManager->informBatteryStatus(left, stat);
2778
 
259 andreas 2779
            if (mIOSSettingsActive)
2780
            {
2781
                mIOSSettingsActive = false;
2782
                MSG_DEBUG("Activating settings");
2783
                activateSettings(QASettings::getOldNetlinx(),
2784
                                  QASettings::getOldPort(),
2785
                                  QASettings::getOoldChannelID(),
2786
                                  QASettings::getOldSurface(),
2787
                                  QASettings::getOldToolbarSuppress(),
2788
                                  QASettings::getOldToolbarForce());
2789
            }
249 andreas 2790
#endif
326 andreas 2791
#if TESTMODE == 1
330 andreas 2792
            if (_gTestMode)
2793
                _gTestMode->run();
2794
 
2795
            _run_test_ready = true;
326 andreas 2796
#endif
31 andreas 2797
        break;
264 andreas 2798
#if not defined(Q_OS_IOS) && not defined(Q_OS_ANDROID)
61 andreas 2799
        default:
2800
            mHasFocus = true;
2801
#endif
31 andreas 2802
    }
235 andreas 2803
#if defined(Q_OS_ANDROID)
92 andreas 2804
    if (mHasFocus && gPageManager)
38 andreas 2805
    {
92 andreas 2806
        gPageManager->initNetworkState();
2807
        gPageManager->initBatteryState();
38 andreas 2808
    }
92 andreas 2809
    else if (gPageManager)
38 andreas 2810
    {
92 andreas 2811
        gPageManager->stopNetworkState();
2812
        gPageManager->stopBatteryState();
38 andreas 2813
    }
37 andreas 2814
#endif
31 andreas 2815
}
2816
 
64 andreas 2817
void MainWindow::_shutdown()
2818
{
2819
    DECL_TRACER("MainWindow::_shutdown()")
2820
 
2821
    close();
2822
}
2823
 
32 andreas 2824
/******************* Signal handling *************************/
2825
 
44 andreas 2826
void MainWindow::_resetSurface()
2827
{
2828
    DECL_TRACER("MainWindow::_resetSurface()");
2829
 
90 andreas 2830
    // Start over by exiting this class
2831
    MSG_INFO("Program will start over!");
2832
    _restart_ = true;
2833
    prg_stopped = true;
2834
    killed = true;
88 andreas 2835
 
90 andreas 2836
    if (gAmxNet)
2837
        gAmxNet->stop();
88 andreas 2838
 
90 andreas 2839
    close();
44 andreas 2840
}
2841
 
391 andreas 2842
void MainWindow::_displayButton(ulong handle, ulong parent, TBitmap buffer, int width, int height, int left, int top, bool passthrough, int marqtype, int marq)
4 andreas 2843
{
391 andreas 2844
    DECL_TRACER("MainWindow::_displayButton(ulong handle, ulong parent, TBitmap buffer, int width, int height, int left, int top, bool passthrough, int marqtype, int marq)");
14 andreas 2845
 
383 andreas 2846
    if (prg_stopped)
21 andreas 2847
        return;
383 andreas 2848
 
2849
    if (!mHasFocus)
2850
    {
2851
        markDirty(handle);
2852
        return;
2853
    }
2854
 
391 andreas 2855
    emit sigDisplayButton(handle, parent, buffer, width, height, left, top, passthrough, marqtype, marq);
14 andreas 2856
}
2857
 
391 andreas 2858
void MainWindow::_setMarqueeText(Button::TButton* button)
2859
{
2860
    DECL_TRACER("MainWindow::_setMarqueeText(Button::TButton* button)");
2861
 
2862
    if (prg_stopped)
2863
        return;
2864
 
2865
    emit sigSetMarqueeText(button);
2866
}
2867
 
289 andreas 2868
void MainWindow::_displayViewButton(ulong handle, ulong parent, bool vertical, TBitmap buffer, int width, int height, int left, int top, int space, TColor::COLOR_T fillColor)
279 andreas 2869
{
289 andreas 2870
    DECL_TRACER("MainWindow::_displayViewButton(ulong handle, ulong parent, TBitmap buffer, int width, int height, int left, int top)");
279 andreas 2871
 
383 andreas 2872
    if (prg_stopped)
279 andreas 2873
        return;
383 andreas 2874
 
2875
    if (!mHasFocus)
2876
    {
2877
        markDirty(handle);
2878
        return;
2879
    }
2880
 
289 andreas 2881
    emit sigDisplayViewButton(handle, parent, vertical, buffer, width, height, left, top, space, fillColor);
279 andreas 2882
}
2883
 
285 andreas 2884
void MainWindow::_addViewButtonItems(ulong parent, vector<PGSUBVIEWITEM_T> items)
279 andreas 2885
{
285 andreas 2886
    DECL_TRACER("MainWindow::_addViewButtonItems(ulong parent, vector<PGSUBVIEWITEM_T> items)");
279 andreas 2887
 
383 andreas 2888
    if (prg_stopped)
279 andreas 2889
        return;
2890
 
369 andreas 2891
    emit sigAddViewButtonItems(parent, items);
280 andreas 2892
}
2893
 
300 andreas 2894
void MainWindow::_updateViewButton(ulong handle, ulong parent, TBitmap buffer, TColor::COLOR_T fillColor)
2895
{
2896
    DECL_TRACER("MainWindow::_updateViewButton(ulong handle, ulong parent, TBitmap buffer, TColor::COLOR_T fillColor)");
2897
 
369 andreas 2898
    if (prg_stopped || !mHasFocus)
300 andreas 2899
        return;
2900
 
383 andreas 2901
    if (!mHasFocus)
2902
    {
2903
        markDirty(handle);
2904
        return;
2905
    }
2906
 
2907
    emit sigUpdateViewButton(handle, parent, buffer, fillColor);
300 andreas 2908
}
2909
 
2910
void MainWindow::_updateViewButtonItem(PGSUBVIEWITEM_T& item, ulong parent)
2911
{
2912
    DECL_TRACER("MainWindow::_updateViewButtonItem(PGSUBVIEWITEM_T& item, ulong parent)");
2913
 
369 andreas 2914
    if (prg_stopped || !mHasFocus)
300 andreas 2915
        return;
2916
 
383 andreas 2917
    emit sigUpdateViewButtonItem(item, parent);
300 andreas 2918
}
2919
 
2920
void MainWindow::_showViewButtonItem(ulong handle, ulong parent, int position, int timer)
2921
{
2922
    DECL_TRACER("MainWindow::_showViewButtonItem(ulong handle, ulong parent, int position, int timer)");
2923
 
383 andreas 2924
    if (prg_stopped)
300 andreas 2925
        return;
2926
 
383 andreas 2927
    if (!mHasFocus)
2928
    {
2929
        markDirty(handle);
2930
        return;
2931
    }
2932
 
2933
    emit sigShowViewButtonItem(handle, parent, position, timer);
300 andreas 2934
}
2935
 
318 andreas 2936
void MainWindow::_hideAllViewItems(ulong handle)
2937
{
2938
    DECL_TRACER("MainWindow::_hideAllViewItems(ulong handle)");
2939
 
369 andreas 2940
    if (prg_stopped || !mHasFocus)
318 andreas 2941
        return;
2942
 
2943
    emit sigHideAllViewItems(handle);
2944
}
2945
 
2946
void MainWindow::_toggleViewButtonItem(ulong handle, ulong parent, int position, int timer)
2947
{
2948
    DECL_TRACER("MainWindow::_toggleViewButtonItem(ulong handle, ulong parent, int position, int timer)");
2949
 
383 andreas 2950
    if (prg_stopped)
318 andreas 2951
        return;
2952
 
383 andreas 2953
    if (!mHasFocus)
2954
    {
2955
        markDirty(handle);
2956
        return;
2957
    }
2958
 
318 andreas 2959
    emit sigToggleViewButtonItem(handle, parent, position, timer);
2960
}
2961
 
2962
void MainWindow::_hideViewItem(ulong handle, ulong parent)
2963
{
2964
    DECL_TRACER("MainWindow::_hideViewItem(ulong handle, ulong parent)");
2965
 
369 andreas 2966
    if (prg_stopped || !mHasFocus)
318 andreas 2967
        return;
2968
 
2969
    emit sigHideViewItem(handle, parent);
2970
}
2971
 
98 andreas 2972
void MainWindow::_setVisible(ulong handle, bool state)
2973
{
2974
    DECL_TRACER("MainWindow::_setVisible(ulong handle, bool state)");
2975
 
369 andreas 2976
    if (prg_stopped || !mHasFocus)
98 andreas 2977
        return;
2978
 
2979
    emit sigSetVisible(handle, state);
2980
}
2981
 
318 andreas 2982
void MainWindow::_setSubViewPadding(ulong handle, int padding)
2983
{
2984
    DECL_TRACER("MainWindow::_setSubViewPadding(ulong handle, int padding)");
2985
 
369 andreas 2986
    if (prg_stopped || !mHasFocus)
318 andreas 2987
        return;
2988
 
2989
    emit sigSetSubViewPadding(handle, padding);
2990
}
2991
 
14 andreas 2992
void MainWindow::_setPage(ulong handle, int width, int height)
2993
{
2994
    DECL_TRACER("MainWindow::_setPage(ulong handle, int width, int height)");
2995
 
369 andreas 2996
    if (prg_stopped || !mHasFocus)
21 andreas 2997
        return;
386 andreas 2998
 
14 andreas 2999
    emit sigSetPage(handle, width, height);
3000
}
3001
 
217 andreas 3002
void MainWindow::_setSubPage(ulong handle, ulong parent, int left, int top, int width, int height, ANIMATION_t animate)
14 andreas 3003
{
217 andreas 3004
    DECL_TRACER("MainWindow::_setSubPage(ulong handle, ulong parent, int left, int top, int width, int height)");
14 andreas 3005
 
369 andreas 3006
    if (prg_stopped || !mHasFocus)
21 andreas 3007
        return;
386 andreas 3008
 
217 andreas 3009
    emit sigSetSubPage(handle, parent, left, top, width, height, animate);
14 andreas 3010
}
3011
 
262 andreas 3012
#ifdef _OPAQUE_SKIA_
289 andreas 3013
void MainWindow::_setBackground(ulong handle, TBitmap image, int width, int height, ulong color)
262 andreas 3014
#else
289 andreas 3015
void MainWindow::_setBackground(ulong handle, TBitmap image, int width, int height, ulong color, int opacity)
262 andreas 3016
#endif
14 andreas 3017
{
289 andreas 3018
    DECL_TRACER("MainWindow::_setBackground(ulong handle, TBitmap image, int width, int height, ulong color [, int opacity])");
14 andreas 3019
 
383 andreas 3020
    if (prg_stopped)
21 andreas 3021
        return;
383 andreas 3022
 
3023
    if (!mHasFocus)
3024
    {
3025
        markDirty(handle);
3026
        return;
3027
    }
3028
 
262 andreas 3029
#ifdef _OPAQUE_SKIA_
289 andreas 3030
    emit sigSetBackground(handle, image, width, height, color);
262 andreas 3031
#else
289 andreas 3032
    emit sigSetBackground(handle, image, width, height, color, opacity);
57 andreas 3033
#endif
14 andreas 3034
}
3035
 
3036
void MainWindow::_dropPage(ulong handle)
3037
{
3038
    DECL_TRACER("MainWindow::_dropPage(ulong handle)");
3039
 
369 andreas 3040
    if (!mHasFocus)
3041
        return;
3042
 
70 andreas 3043
    doReleaseButton();
386 andreas 3044
 
61 andreas 3045
    if (!mHasFocus)
3046
    {
386 andreas 3047
        markDroped(handle);
61 andreas 3048
        return;
3049
    }
386 andreas 3050
 
14 andreas 3051
    emit sigDropPage(handle);
3052
}
3053
 
350 andreas 3054
void MainWindow::_dropSubPage(ulong handle, ulong parent)
14 andreas 3055
{
350 andreas 3056
    DECL_TRACER("MainWindow::_dropSubPage(ulong handle, ulong parent)");
14 andreas 3057
 
369 andreas 3058
    if (!mHasFocus)
3059
        return;
3060
 
70 andreas 3061
    doReleaseButton();
386 andreas 3062
 
61 andreas 3063
    if (!mHasFocus)
3064
    {
386 andreas 3065
        markDroped(handle);
61 andreas 3066
        return;
3067
    }
386 andreas 3068
 
350 andreas 3069
    emit sigDropSubPage(handle, parent);
14 andreas 3070
}
3071
 
98 andreas 3072
void MainWindow::_dropButton(ulong handle)
3073
{
3074
    DECL_TRACER("MainWindow::_dropButton(ulong handle)");
383 andreas 3075
 
98 andreas 3076
    if (!mHasFocus)
3077
    {
386 andreas 3078
        markDroped(handle);
98 andreas 3079
        return;
3080
    }
383 andreas 3081
 
3082
    emit sigDropButton(handle);
98 andreas 3083
}
3084
 
21 andreas 3085
void MainWindow::_playVideo(ulong handle, ulong parent, int left, int top, int width, int height, const string& url, const string& user, const string& pw)
3086
{
3087
    DECL_TRACER("MainWindow::_playVideo(ulong handle, const string& url)");
3088
 
369 andreas 3089
    if (prg_stopped || !mHasFocus)
21 andreas 3090
        return;
386 andreas 3091
 
21 andreas 3092
    emit sigPlayVideo(handle, parent, left, top, width, height, url, user, pw);
3093
}
3094
 
291 andreas 3095
void MainWindow::_inputText(Button::TButton *button, Button::BITMAP_t& bm, int frame)
50 andreas 3096
{
291 andreas 3097
    DECL_TRACER("MainWindow::_inputText(Button::TButton *button, Button::BITMAP_t& bm, int frame)");
50 andreas 3098
 
369 andreas 3099
    if (prg_stopped || !button || !mHasFocus)
50 andreas 3100
        return;
386 andreas 3101
 
52 andreas 3102
    QByteArray buf;
3103
 
3104
    if (bm.buffer && bm.rowBytes > 0)
3105
    {
398 andreas 3106
        size_t size = static_cast<size_t>(bm.width) * static_cast<size_t>(bm.height) * static_cast<size_t>(bm.rowBytes / static_cast<size_t>(bm.width));
3107
        buf.insert(0, (const char *)bm.buffer, static_cast<qsizetype>(size));
52 andreas 3108
    }
57 andreas 3109
 
192 andreas 3110
    emit sigInputText(button, buf, bm.width, bm.height, frame, bm.rowBytes);
50 andreas 3111
}
3112
 
291 andreas 3113
void MainWindow::_listBox(Button::TButton *button, Button::BITMAP_t& bm, int frame)
200 andreas 3114
{
279 andreas 3115
    DECL_TRACER("MainWindow::_listBox(Button::TButton& button, Button::BITMAP_t& bm, int frame)");
200 andreas 3116
 
369 andreas 3117
    if (prg_stopped || !mHasFocus)
200 andreas 3118
        return;
386 andreas 3119
 
200 andreas 3120
    QByteArray buf;
3121
 
3122
    if (bm.buffer && bm.rowBytes > 0)
3123
    {
398 andreas 3124
        size_t size = static_cast<size_t>(bm.width) * static_cast<size_t>(bm.height) * static_cast<size_t>(bm.rowBytes / static_cast<size_t>(bm.width));
3125
        buf.insert(0, (const char *)bm.buffer, static_cast<qsizetype>(size));
200 andreas 3126
    }
3127
 
3128
    emit sigListBox(button, buf, bm.width, bm.height, frame, bm.rowBytes);
3129
}
3130
 
63 andreas 3131
void MainWindow::_showKeyboard(const std::string& init, const std::string& prompt, bool priv)
62 andreas 3132
{
63 andreas 3133
    DECL_TRACER("MainWindow::_showKeyboard(std::string &init, std::string &prompt, bool priv)");
62 andreas 3134
 
369 andreas 3135
    if (prg_stopped || !mHasFocus)
62 andreas 3136
        return;
3137
 
70 andreas 3138
    doReleaseButton();
63 andreas 3139
    emit sigKeyboard(init, prompt, priv);
62 andreas 3140
}
3141
 
63 andreas 3142
void MainWindow::_showKeypad(const std::string& init, const std::string& prompt, bool priv)
62 andreas 3143
{
63 andreas 3144
    DECL_TRACER("MainWindow::_showKeypad(std::string &init, std::string &prompt, bool priv)");
62 andreas 3145
 
383 andreas 3146
    if (prg_stopped || !mHasFocus)
62 andreas 3147
        return;
3148
 
70 andreas 3149
    doReleaseButton();
63 andreas 3150
    emit sigKeypad(init, prompt, priv);
62 andreas 3151
}
3152
 
63 andreas 3153
void MainWindow::_resetKeyboard()
3154
{
3155
    DECL_TRACER("MainWindow::_resetKeyboard()");
3156
 
369 andreas 3157
    if (mHasFocus)
3158
        emit sigResetKeyboard();
63 andreas 3159
}
3160
 
64 andreas 3161
void MainWindow::_showSetup()
3162
{
3163
    DECL_TRACER("MainWindow::_showSetup()");
3164
 
369 andreas 3165
    if (mHasFocus)
3166
        emit sigShowSetup();
64 andreas 3167
}
3168
 
71 andreas 3169
void MainWindow::_playSound(const string& file)
3170
{
3171
    DECL_TRACER("MainWindow::_playSound(const string& file)");
3172
 
369 andreas 3173
    if (mHasFocus)
3174
        emit sigPlaySound(file);
71 andreas 3175
}
3176
 
141 andreas 3177
void MainWindow::_stopSound()
3178
{
3179
    DECL_TRACER("MainWindow::_stopSound()");
3180
 
369 andreas 3181
    if (mHasFocus)
3182
        emit sigStopSound();
141 andreas 3183
}
3184
 
3185
void MainWindow::_muteSound(bool state)
3186
{
3187
    DECL_TRACER("MainWindow::_muteSound(bool state)");
3188
 
369 andreas 3189
    if (mHasFocus)
3190
        emit sigMuteSound(state);
141 andreas 3191
}
3192
 
335 andreas 3193
void MainWindow::_setVolume(int volume)
3194
{
3195
    DECL_TRACER("MainWindow::_setVolume(int volume)");
3196
 
369 andreas 3197
    if (mHasFocus)
3198
        emit sigSetVolume(volume);
335 andreas 3199
}
3200
 
88 andreas 3201
void MainWindow::_setOrientation(J_ORIENTATION ori)
3202
{
182 andreas 3203
#ifdef Q_OS_ANDROID
88 andreas 3204
    DECL_TRACER("MainWindow::_setOriantation(J_ORIENTATION ori)");
3205
 
134 andreas 3206
    if (ori == O_FACE_UP || ori == O_FACE_DOWN)
3207
        return;
264 andreas 3208
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
88 andreas 3209
    QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
182 andreas 3210
#else
183 andreas 3211
    QJniObject activity = QJniObject::callStaticObjectMethod("org/qtproject/qt/android/QtNative", "activity", "()Landroid/app/Activity;");
182 andreas 3212
#endif
88 andreas 3213
    if ( activity.isValid() )
3214
    {
3215
        activity.callMethod<void>
3216
                ("setRequestedOrientation"  // method name
3217
                 , "(I)V"                   // signature
3218
                 , ori);
131 andreas 3219
 
3220
        switch(ori)
3221
        {
3222
            case O_LANDSCAPE:           mOrientation = Qt::LandscapeOrientation; break;
3223
            case O_PORTRAIT:            mOrientation = Qt::PortraitOrientation; break;
3224
            case O_REVERSE_LANDSCAPE:   mOrientation = Qt::InvertedLandscapeOrientation; break;
3225
            case O_REVERSE_PORTRAIT:    mOrientation = Qt::InvertedPortraitOrientation; break;
3226
            default:
3227
                MSG_WARNING("Orientation is undefined!");
3228
                mOrientation = Qt::PrimaryOrientation;
3229
        }
88 andreas 3230
    }
243 andreas 3231
#elif defined(Q_OS_IOS)
252 andreas 3232
    if (mIosRotate)
264 andreas 3233
    {
252 andreas 3234
        mIosRotate->rotate(ori);
264 andreas 3235
#ifdef QT_DEBUG
3236
        string msg;
3237
 
3238
        switch(ori)
3239
        {
3240
            case O_LANDSCAPE:           msg = "LANDSCAPE"; break;
3241
            case O_PORTRAIT:            msg = "PORTRAIT"; break;
3242
            case O_REVERSE_PORTRAIT:    msg = "INVERTED PORTRAIT"; break;
3243
            case O_REVERSE_LANDSCAPE:   msg = "INVERTED LANDSCAPE"; break;
3244
            default:
3245
                msg = "unknown";
3246
        }
3247
 
3248
        MSG_DEBUG("Rotated to " << msg);
3249
#endif
3250
    }
237 andreas 3251
#else
3252
    Q_UNUSED(ori);
88 andreas 3253
#endif
3254
}
3255
 
111 andreas 3256
void MainWindow::_sendVirtualKeys(const string& str)
3257
{
3258
    DECL_TRACER("MainWindow::_sendVirtualKeys(const string& str)");
3259
 
369 andreas 3260
    if (mHasFocus)
3261
        emit sigSendVirtualKeys(str);
111 andreas 3262
}
3263
 
140 andreas 3264
void MainWindow::_showPhoneDialog(bool state)
3265
{
3266
    DECL_TRACER("MainWindow::_showPhoneDialog(bool state)");
3267
 
369 andreas 3268
    if (mHasFocus)
3269
        emit sigShowPhoneDialog(state);
140 andreas 3270
}
3271
 
3272
void MainWindow::_setPhoneNumber(const std::string& number)
3273
{
3274
    DECL_TRACER("MainWindow::_setPhoneNumber(const std::string& number)");
3275
 
369 andreas 3276
    if (mHasFocus)
3277
        emit sigSetPhoneNumber(number);
140 andreas 3278
}
3279
 
3280
void MainWindow::_setPhoneStatus(const std::string& msg)
3281
{
3282
    DECL_TRACER("MainWindow::_setPhoneStatus(const std::string& msg)");
3283
 
369 andreas 3284
    if (mHasFocus)
3285
        emit sigSetPhoneStatus(msg);
140 andreas 3286
}
3287
 
141 andreas 3288
void MainWindow::_setPhoneState(int state, int id)
3289
{
3290
    DECL_TRACER("MainWindow::_setPhoneState(int state, int id)");
3291
 
369 andreas 3292
    if (mHasFocus)
3293
        emit sigSetPhoneState(state, id);
141 andreas 3294
}
3295
 
179 andreas 3296
void MainWindow::_onProgressChanged(int percent)
3297
{
3298
    DECL_TRACER("MainWindow::_onProgressChanged(int percent)");
3299
 
369 andreas 3300
    if (mHasFocus)
3301
        emit sigOnProgressChanged(percent);
179 andreas 3302
}
3303
 
206 andreas 3304
void MainWindow::_displayMessage(const string &msg, const string &title)
3305
{
3306
    DECL_TRACER("MainWindow::_displayMessage(const string &msg, const string &title)");
3307
 
369 andreas 3308
    if (mHasFocus)
3309
        emit sigDisplayMessage(msg, title);
206 andreas 3310
}
3311
 
401 andreas 3312
void MainWindow::_askPassword(ulong handle, const string& msg, const string& title, int x, int y)
396 andreas 3313
{
401 andreas 3314
    DECL_TRACER("MainWindow::_askPassword(ulong handle, const string& msg, const string& title, int x int y)");
396 andreas 3315
 
3316
    if (mHasFocus)
401 andreas 3317
        emit sigAskPassword(handle, msg, title, x, y);
396 andreas 3318
}
3319
 
209 andreas 3320
void MainWindow::_fileDialog(ulong handle, const string &path, const std::string& extension, const std::string& suffix)
3321
{
3322
    DECL_TRACER("MainWindow::_fileDialog(ulong handle, const string &path, const std::string& extension, const std::string& suffix)");
3323
 
3324
    if (!handle || path.empty())
3325
    {
3326
        MSG_WARNING("Invalid parameter handle or no path!");
3327
        return;
3328
    }
3329
 
3330
    emit sigFileDialog(handle, path, extension, suffix);
3331
}
252 andreas 3332
 
197 andreas 3333
void MainWindow::_setSizeMainWindow(int width, int height)
3334
{
252 andreas 3335
#if !defined (Q_OS_ANDROID) && !defined(Q_OS_IOS)
197 andreas 3336
    DECL_TRACER("MainWindow::_setSizeMainWindow(int width, int height)");
3337
 
3338
    emit sigSetSizeMainWindow(width, height);
252 andreas 3339
#else
3340
    Q_UNUSED(width);
3341
    Q_UNUSED(height);
3342
#endif
197 andreas 3343
}
252 andreas 3344
 
279 andreas 3345
void MainWindow::_listViewArea(ulong handle, ulong parent, Button::TButton& button, SUBVIEWLIST_T& list)
3346
{
3347
    DECL_TRACER("MainWindow::_listViewArea(ulong handle, ulong parent, Button::TButton *button, SUBVIEWLIST_T& list)");
3348
 
3349
    if (!handle || !parent || list.id <= 0)
3350
    {
3351
        MSG_WARNING("Invalid parameters for scroll area!");
3352
        return;
3353
    }
3354
 
383 andreas 3355
    if (!mHasFocus)
3356
    {
3357
        markDirty(handle);
3358
        return;
3359
    }
3360
 
3361
    emit sigListViewArea(handle, parent, button, list);
279 andreas 3362
}
3363
 
70 andreas 3364
void MainWindow::doReleaseButton()
3365
{
3366
    DECL_TRACER("MainWindow::doReleaseButton()");
3367
 
369 andreas 3368
    if (mLastPressX >= 0 && mLastPressY >= 0 && gPageManager)
70 andreas 3369
    {
3370
        MSG_DEBUG("Sending outstanding mouse release event for coordinates x" << mLastPressX << ", y" << mLastPressY);
3371
        int x = mLastPressX;
3372
        int y = mLastPressY;
3373
 
3374
        if (isScaled())
3375
        {
398 andreas 3376
            x = static_cast<int>(static_cast<double>(x) / mScaleFactor);
3377
            y = static_cast<int>(static_cast<double>(y) / mScaleFactor);
70 andreas 3378
        }
3379
 
92 andreas 3380
        gPageManager->mouseEvent(x, y, false);
334 andreas 3381
        mLastPressX = mLastPressY = -1;
70 andreas 3382
    }
3383
}
3384
 
142 andreas 3385
/**
3386
 * @brief MainWindow::repaintObjects
383 andreas 3387
 * If the application was suspended, which is only on mobile devices possible,
3388
 * the surface can't be drawn. If there was a change on a visible object it
3389
 * was marked "dirty". This methos searches for all dirty marked objects and
3390
 * asks the TPageManager to resend the last drawn graphic of the object. If the
3391
 * object was a page or subpage, the whole page or subpage is redrawn. Otherwise
3392
 * only the changed object.
142 andreas 3393
 */
3394
void MainWindow::repaintObjects()
3395
{
3396
    DECL_TRACER("MainWindow::repaintObjects()");
3397
 
383 andreas 3398
    TObject::OBJECT_t *obj = getFirstDirty();
142 andreas 3399
 
3400
    while (obj)
3401
    {
383 andreas 3402
        if (!obj->remove && !obj->invalid && obj->dirty)
148 andreas 3403
        {
271 andreas 3404
            MSG_PROTOCOL("Refreshing widget " << handleToString (obj->handle));
383 andreas 3405
 
3406
            if (gPageManager)
3407
                gPageManager->redrawObject(obj->handle);
3408
 
3409
            obj->dirty = false;
148 andreas 3410
        }
142 andreas 3411
 
383 andreas 3412
        obj = getNextDirty(obj);
142 andreas 3413
    }
3414
}
3415
 
297 andreas 3416
void MainWindow::refresh(ulong handle)
3417
{
3418
    DECL_TRACER("MainWindow::refresh(ulong handle)");
3419
 
3420
    if (!handle)
3421
        return;
3422
 
3423
    OBJECT_t *obj = findFirstChild(handle);
3424
 
3425
    while (obj)
3426
    {
3427
        MSG_DEBUG("Object " << handleToString(obj->handle) << " of type " << objectToString(obj->type) << ". Invalid: " << (obj->invalid ? "YES" : "NO") << ", Pointer: " << (obj->object.widget ? "YES" : "NO"));
3428
 
3429
        if (obj->type == OBJ_SUBVIEW && !obj->invalid && obj->object.area)
3430
        {
3431
            obj->object.area->setHidden(true);
3432
            obj->object.area->setHidden(false);
3433
            obj->object.area->setEnabled(true);
3434
            MSG_DEBUG("Subview refreshed");
3435
        }
3436
        else if (obj->type == OBJ_LIST && !obj->invalid && obj->object.list)
3437
        {
3438
            if (!obj->object.list->isEnabled())
3439
                obj->object.list->setEnabled(true);
3440
        }
3441
        else if (obj->type == OBJ_BUTTON && !obj->invalid && obj->object.label)
3442
        {
3443
            if (!obj->object.label->isEnabled())
3444
                obj->object.label->setEnabled(true);
3445
        }
391 andreas 3446
        else if (obj->type == OBJ_MARQUEE && !obj->invalid && obj->object.marquee)
3447
        {
3448
            if (!obj->object.marquee->isEnabled())
3449
                obj->object.marquee->setEnabled(true);
3450
        }
297 andreas 3451
        else if ((obj->type == OBJ_SUBPAGE || obj->type == OBJ_PAGE) && !obj->invalid && obj->object.widget)
3452
        {
3453
            if (!obj->object.widget->isEnabled())
3454
                obj->object.widget->setEnabled(true);
3455
        }
3456
 
3457
        obj = findNextChild(obj->handle);
3458
    }
3459
}
3460
 
383 andreas 3461
void MainWindow::markDirty(ulong handle)
3462
{
3463
    DECL_TRACER("MainWindow::markDirty(ulong handle)");
366 andreas 3464
 
383 andreas 3465
    OBJECT_t *obj = findObject(handle);
3466
 
3467
    if (!obj)
3468
        return;
3469
 
3470
    MSG_DEBUG("Object " << handleToString(handle) << " marked dirty.");
3471
    obj->dirty = true;
3472
}
3473
 
366 andreas 3474
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
141 andreas 3475
int MainWindow::calcVolume(int value)
366 andreas 3476
#else
3477
double MainWindow::calcVolume(int value)
3478
#endif
141 andreas 3479
{
366 andreas 3480
    DECL_TRACER("MainWindow::calcVolume(int value)");
141 andreas 3481
 
3482
    // volumeSliderValue is in the range [0..100]
366 andreas 3483
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
141 andreas 3484
    qreal linearVolume = QAudio::convertVolume(value / qreal(100.0),
3485
                                               QAudio::LogarithmicVolumeScale,
3486
                                               QAudio::LinearVolumeScale);
3487
 
3488
    return qRound(linearVolume * 100);
366 andreas 3489
#else
398 andreas 3490
    return static_cast<double>(value) / 100.0;
366 andreas 3491
#endif
141 andreas 3492
}
197 andreas 3493
 
395 andreas 3494
QFont MainWindow::loadFont(int number, const FONT_T& f, const FONT_STYLE style)
3495
{
3496
    DECL_TRACER("MainWindow::loadFont(int number, const FONT_t& f, const FONT_STYLE style)");
3497
 
3498
    QString path;
3499
    string prjPath= TConfig::getProjectPath();
3500
 
3501
    if (number < 32)    // System font?
3502
    {
398 andreas 3503
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
395 andreas 3504
        path.append(prjPath).append("/__system/graphics/fonts/").append(f.file);
398 andreas 3505
#else
3506
        path.append(prjPath.c_str()).append("/__system/graphics/fonts/").append(f.file.c_str());
3507
#endif
395 andreas 3508
 
3509
        if (!fs::is_regular_file(path.toStdString()))
3510
        {
3511
            MSG_WARNING("Seem to miss system fonts ...");
3512
            path.clear();
398 andreas 3513
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
395 andreas 3514
            path.append(prjPath).append("/fonts/").append(f.file);
398 andreas 3515
#else
3516
            path.append(prjPath.c_str()).append("/fonts/").append(f.file.c_str());
3517
#endif
395 andreas 3518
        }
3519
    }
3520
    else
3521
    {
398 andreas 3522
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
395 andreas 3523
        path.append(prjPath).append("/fonts/").append(f.file);
398 andreas 3524
#else
3525
        path.append(prjPath.c_str()).append("/fonts/").append(f.file.c_str());
3526
#endif
395 andreas 3527
        if (!fs::exists(path.toStdString()))
3528
        {
3529
            string pth = prjPath + "/__system/fonts/" + f.file;
3530
 
3531
            if (fs::exists(pth))
398 andreas 3532
            {
3533
#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
395 andreas 3534
                path.assign(pth);
398 andreas 3535
#else
3536
                path = pth.c_str();
3537
#endif
3538
            }
395 andreas 3539
        }
3540
    }
3541
 
3542
    const QStringList ffamilies = QFontDatabase::families();
3543
    bool haveFont = false;
3544
 
3545
    for (const QString &family : ffamilies)
3546
    {
3547
        if (family.compare(f.name.c_str()) == 0)
3548
        {
3549
            haveFont = true;
3550
            break;
3551
        }
3552
    }
3553
 
3554
    QFont font;
3555
    // Scale the font size
3556
    int pix = f.size;
3557
 
3558
    if (mScaleFactor > 0.0 && mScaleFactor != 1.0)
398 andreas 3559
        pix = static_cast<int>(static_cast<double>(f.size) / mScaleFactor);
395 andreas 3560
 
3561
    QString qstyle;
3562
 
3563
    switch (style)
3564
    {
398 andreas 3565
#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
395 andreas 3566
        case FONT_BOLD:         qstyle.assign("Bold"); break;
3567
        case FONT_ITALIC:       qstyle.assign("Italic"); break;
3568
        case FONT_BOLD_ITALIC:  qstyle.assign("Bold Italic"); break;
3569
 
3570
        default:
3571
            qstyle.assign("Normal");
398 andreas 3572
#else
3573
    case FONT_BOLD:         qstyle = "Bold"; break;
3574
    case FONT_ITALIC:       qstyle = "Italic"; break;
3575
    case FONT_BOLD_ITALIC:  qstyle = "Bold Italic"; break;
3576
 
3577
    default:
3578
        qstyle = "Normal";
3579
#endif
395 andreas 3580
    }
3581
 
3582
    if (!haveFont)  // Did we found the font?
3583
    {               // No, then load it
3584
        QFontDatabase::addApplicationFont(path);
3585
        font = QFontDatabase::font(f.name.c_str(), qstyle, pix);
3586
        MSG_DEBUG("Font \"" << path.toStdString() << "\" was loaded");
3587
    }
3588
    else
3589
    {
3590
        font.setFamily(f.name.c_str());
3591
        font.setPointSize(pix);
3592
        font.setStyleName(qstyle);
3593
    }
3594
 
3595
    string family = font.family().toStdString();
3596
 
3597
    if (!font.exactMatch() && (family != f.name || font.styleName() != qstyle || font.pointSize() != pix))
3598
    {
3599
        MSG_WARNING("Using font "
3600
                    << family << "|" << font.styleName().toStdString() << "|" << font.pointSize()
3601
                    << " but requested font "
3602
                    << f.name << "|" << qstyle.toStdString() << "|" << pix << "!");
3603
    }
3604
    else
3605
    {
3606
        MSG_DEBUG("Font was set to " << f.name << "|" << qstyle.toStdString() << "|" << pix << "! " << (font.exactMatch() ? "[original]" : "[replacement]"));
3607
    }
3608
 
3609
    return font;
3610
}
3611
 
263 andreas 3612
/**
3613
 * @brief MainWindow::convertMask
3614
 * Converts the AMX mask for input lines into Qt mask sympols for input lines.
3615
 *
3616
 * @param mask  A string containing the AMX mask symbols.
3617
 *
3618
 * @return The converted mask string for Qt input lines.
3619
 */
224 andreas 3620
string MainWindow::convertMask(const string& mask)
3621
{
3622
    DECL_TRACER("MainWindow::convertMask(const string& mask)");
3623
 
3624
    string qMask;
3625
 
3626
    for (size_t i = 0; i < mask.length(); ++i)
3627
    {
3628
        switch (mask[i])
3629
        {
3630
            case '0': qMask += "9"; break;
3631
            case '9': qMask += "0"; break;
3632
            case 'A': qMask += "N"; break;
3633
            case 'a': qMask += "n"; break;
3634
            case 'L': qMask += "X"; break;
3635
            case '?': qMask += "x"; break;
3636
            case '&': qMask += "A"; break;
3637
            case 'C': qMask += "a"; break;
3638
            case '^': qMask += ";"; break;
3639
 
3640
            default:
3641
                qMask += mask[i];
3642
        }
3643
    }
3644
 
3645
    return qMask;
3646
}
3647
 
266 andreas 3648
#ifdef Q_OS_ANDROID
3649
void MainWindow::hideAndroidBars()
3650
{
3651
    DECL_TRACER("MainWindow::hideAndroidBars()");
3652
}
3653
#endif
252 andreas 3654
#ifdef Q_OS_IOS
3655
void MainWindow::setNotch()
3656
{
3657
    DECL_TRACER("MainWindow::setNotch()");
3658
 
264 andreas 3659
    Qt::ScreenOrientation so = getRealOrientation();
3660
 
3661
    if (so == Qt::PrimaryOrientation)
263 andreas 3662
        return;
3663
 
3664
    QMargins margins;
3665
 
264 andreas 3666
    if (mHaveNotchPortrait && (so == Qt::PortraitOrientation || so == Qt::InvertedPortraitOrientation))
263 andreas 3667
        margins = mNotchPortrait;
264 andreas 3668
    else if (mHaveNotchLandscape && (so == Qt::LandscapeOrientation || so == Qt::InvertedLandscapeOrientation))
263 andreas 3669
        margins = mNotchLandscape;
3670
    else
252 andreas 3671
    {
263 andreas 3672
        margins = QASettings::getNotchSize();
3673
 
3674
        if (gPageManager && gPageManager->getSettings()->isPortrait())
3675
        {
264 andreas 3676
            if (so == Qt::LandscapeOrientation)
263 andreas 3677
            {
3678
                int left = margins.left();
3679
                int top = margins.top();
3680
                margins.setTop(margins.right());
3681
                margins.setLeft(top);
3682
                margins.setRight(margins.bottom());
3683
                margins.setBottom(left);
3684
            }
264 andreas 3685
            else if (so == Qt::InvertedLandscapeOrientation)
263 andreas 3686
            {
3687
                int right = margins.right();
3688
                int top = margins.top();
3689
                margins.setTop(margins.left());
3690
                margins.setLeft(top);
3691
                margins.setRight(margins.bottom());
3692
                margins.setBottom(right);
3693
            }
3694
        }
264 andreas 3695
        else if (gPageManager && gPageManager->getSettings()->isLandscape())
263 andreas 3696
        {
264 andreas 3697
            if (so == Qt::PortraitOrientation)
3698
            {
3699
                int top = margins.top();
3700
                int right = margins.right();
3701
                margins.setTop(margins.left());
3702
                margins.setLeft(top);
3703
                margins.setRight(margins.bottom());
3704
                margins.setBottom(right);
3705
            }
3706
            else if (so == Qt::InvertedPortraitOrientation)
3707
            {
3708
                int top = margins.top();
3709
                int left = margins.left();
3710
                margins.setTop(margins.right());
3711
                margins.setLeft(margins.bottom());
3712
                margins.setRight(top);
3713
                margins.setBottom(left);
3714
            }
263 andreas 3715
        }
252 andreas 3716
    }
399 andreas 3717
#if defined(QT_DEBUG) && (defined(Q_OS_IOS) || defined(Q_OS_ANDROID))
264 andreas 3718
    MSG_DEBUG("Notch top: " << margins.top() << ", bottom: " << margins.bottom() << ", left: " << margins.left() << ", right: " << margins.right() << ", Orientation real: " << orientationToString(so) << ", estimated: " << orientationToString(mOrientation));
263 andreas 3719
#endif
3720
    if (gPageManager)
252 andreas 3721
    {
264 andreas 3722
        // If the real orientation "so" differs from "mOrientation" then
3723
        // "mOrientation" contains the wanted orientation and not the real one!
263 andreas 3724
        if (gPageManager->getSettings()->isPortrait() &&
3725
            (mOrientation == Qt::PortraitOrientation || mOrientation == Qt::InvertedPortraitOrientation))
3726
        {
3727
            mNotchPortrait = margins;
3728
            mHaveNotchPortrait = true;
3729
        }
3730
        else if (gPageManager->getSettings()->isLandscape() &&
3731
            (mOrientation == Qt::LandscapeOrientation || mOrientation == Qt::InvertedLandscapeOrientation))
3732
        {
3733
            mNotchLandscape = margins;
3734
            mHaveNotchLandscape = true;
3735
        }
252 andreas 3736
    }
3737
}
3738
 
3739
/**
3740
 * @brief MainWindow::initGeoLocation
3741
 * This method is only used on IOS to let the application run in the background.
3742
 * It is necessary because it is the only way to let an application run in
3743
 * the background.
3744
 * The method initializes the geo position module of Qt. If the app doesn't
3745
 * have the permissions to retrieve the geo positions, it will not run in the
3746
 * background. It stops at the moment the app is not in front or the display is
3747
 * closed. This makes it stop communicate with the NetLinx and looses the
3748
 * network connection. When the app gets the focus again, it must reconnect to
3749
 * the NetLinx.
3750
 */
3751
void MainWindow::initGeoLocation()
3752
{
3753
    DECL_TRACER("MainWindow::initGeoLocation()");
3754
 
386 andreas 3755
    if (mSource && mGeoHavePermission)
252 andreas 3756
        return;
3757
 
386 andreas 3758
    if (!mSource)
3759
    {
3760
        mGeoHavePermission = true;
3761
        mSource = QGeoPositionInfoSource::createDefaultSource(this);
252 andreas 3762
 
386 andreas 3763
        if (!mSource)
3764
        {
3765
            MSG_WARNING("Error creating geo positioning source!");
3766
            mGeoHavePermission = false;
3767
            return;
3768
        }
3769
 
3770
        mSource->setPreferredPositioningMethods(QGeoPositionInfoSource::AllPositioningMethods);
3771
        mSource->setUpdateInterval(800);    // milli seconds
3772
        // Connecting some callbacks to the class
252 andreas 3773
        connect(mSource, &QGeoPositionInfoSource::positionUpdated, this, &MainWindow::onPositionUpdated);
3774
        connect(mSource, &QGeoPositionInfoSource::errorOccurred, this, &MainWindow::onErrorOccurred);
386 andreas 3775
#ifdef Q_OS_IOS
3776
        QLocationPermission perm;
3777
        perm.setAccuracy(QLocationPermission::Approximate);
3778
        perm.setAvailability(QLocationPermission::Always);
3779
        mGeoHavePermission = false;
3780
 
3781
        switch (qApp->checkPermission(perm))
3782
        {
3783
            case Qt::PermissionStatus::Undetermined:
3784
                qApp->requestPermission(perm, [this] (const QPermission& permission)
3785
                {
3786
                    if (permission.status() == Qt::PermissionStatus::Granted)
3787
                    {
3788
                        mGeoHavePermission = true;
3789
                        mSource->startUpdates();
3790
                    }
3791
                    else
3792
                        onErrorOccurred(QGeoPositionInfoSource::AccessError);
3793
                });
3794
            break;
3795
 
3796
            case Qt::PermissionStatus::Denied:
3797
                MSG_WARNING("Location permission is denied");
3798
                onErrorOccurred(QGeoPositionInfoSource::AccessError);
3799
            break;
3800
 
3801
            case Qt::PermissionStatus::Granted:
3802
                mSource->startUpdates();
3803
                mGeoHavePermission = true;
3804
            break;
3805
        }
3806
#endif
252 andreas 3807
    }
3808
}
263 andreas 3809
 
264 andreas 3810
Qt::ScreenOrientation MainWindow::getRealOrientation()
3811
{
3812
    DECL_TRACER("MainWindow::getRealOrientation()");
3813
 
3814
    QScreen *screen = QGuiApplication::primaryScreen();
3815
 
3816
    if (!screen)
3817
    {
3818
        MSG_ERROR("Couldn't determine the primary screen!")
3819
        return Qt::PrimaryOrientation;
3820
    }
3821
 
3822
    QRect rect = screen->availableGeometry();
3823
 
3824
    if (rect.width() > rect.height())
3825
        return Qt::LandscapeOrientation;
3826
 
3827
    return Qt::PortraitOrientation;
3828
}
395 andreas 3829
#endif  // Q_OS_IOS
3830
#if defined(QT_DEBUG) && (defined(Q_OS_IOS) || defined(Q_OS_ANDROID))
264 andreas 3831
string MainWindow::orientationToString(Qt::ScreenOrientation ori)
263 andreas 3832
{
3833
    string sori;
3834
 
3835
    switch(ori)
3836
    {
3837
        case Qt::PortraitOrientation:           sori = "PORTRAIT"; break;
3838
        case Qt::InvertedPortraitOrientation:   sori = "INVERTED PORTRAIT"; break;
3839
        case Qt::LandscapeOrientation:          sori = "LANDSCAPE"; break;
3840
        case Qt::InvertedLandscapeOrientation:  sori = "INVERTED LANDSCAPE"; break;
3841
        default:
3842
            sori = "Unknown: ";
3843
            sori.append(intToString(ori));
3844
    }
3845
 
3846
    return sori;
3847
}
395 andreas 3848
#endif
252 andreas 3849
 
14 andreas 3850
/******************* Draw elements *************************/
3851
 
217 andreas 3852
/**
3853
 * @brief Displays an image.
3854
 * The method is a callback function and is called whenever an image should be
3855
 * displayed. It defines a label, set it to the (scaled) \b width and \b height
3856
 * and moves it to the (scaled) position \b left and \b top.
3857
 *
3858
 * @param handle    The unique handle of the object
3859
 * @param parent    The unique handle of the parent object.
3860
 * @param buffer    A byte array containing the image.
3861
 * @param width     The width of the object
3862
 * @param height    The height of the object
3863
 * @param pixline   The number of pixels in one line of the image.
3864
 * @param left      The prosition from the left.
3865
 * @param top       The position from the top.
391 andreas 3866
 * @param marqtype  The type of marquee line
3867
 * @param marq      Enabled/disabled marquee
217 andreas 3868
 */
391 andreas 3869
void MainWindow::displayButton(ulong handle, ulong parent, TBitmap buffer, int width, int height, int left, int top, bool passthrough, int marqtype, int marq)
14 andreas 3870
{
391 andreas 3871
    DECL_TRACER("MainWindow::displayButton(ulong handle, TBitmap buffer, size_t size, int width, int height, int left, int top, bool passthrough, int marqtype, int marq)");
4 andreas 3872
 
277 andreas 3873
    TObject::OBJECT_t *obj = findObject(handle);
3874
    TObject::OBJECT_t *par = findObject(parent);
271 andreas 3875
    MSG_TRACE("Processing button " << handleToString(handle) << " from parent " << handleToString(parent));
5 andreas 3876
 
6 andreas 3877
    if (!par)
3878
    {
59 andreas 3879
        if (TStreamError::checkFilter(HLOG_DEBUG))
271 andreas 3880
            MSG_WARNING("Button " << handleToString(handle) << " has no parent (" << handleToString(parent) << ")! Ignoring it.");
332 andreas 3881
#if TESTMODE == 1
334 andreas 3882
        setScreenDone();
332 andreas 3883
#endif
6 andreas 3884
        return;
3885
    }
3886
 
107 andreas 3887
    if (par->animation && !par->aniDirection)
3888
    {
3889
        if (par->animation->state() == QAbstractAnimation::Running)
3890
        {
271 andreas 3891
            MSG_WARNING("Object " << handleToString(parent) << " is busy with an animation!");
107 andreas 3892
            par->animation->stop();
3893
        }
3894
        else
3895
        {
271 andreas 3896
            MSG_WARNING("Object " << handleToString(parent) << " has not finished the animation!");
107 andreas 3897
        }
3898
 
332 andreas 3899
#if TESTMODE == 1
334 andreas 3900
        setScreenDone();
332 andreas 3901
#endif
107 andreas 3902
        return;
3903
    }
3904
    else if (par->remove)
3905
    {
271 andreas 3906
        MSG_WARNING("Object " << handleToString(parent) << " is marked for remove. Will not draw image!");
332 andreas 3907
#if TESTMODE == 1
334 andreas 3908
        setScreenDone();
332 andreas 3909
#endif
107 andreas 3910
        return;
3911
    }
3912
 
5 andreas 3913
    if (!obj)
3914
    {
351 andreas 3915
        if (!par->object.widget)
3916
        {
3917
            MSG_ERROR("Object " << handleToString(parent) << " has no valid widget!");
3918
#if TESTMODE == 1
3919
            setScreenDone();
3920
#endif
3921
            return;
3922
        }
3923
 
271 andreas 3924
        MSG_DEBUG("Adding new object " << handleToString(handle) << " ...");
296 andreas 3925
        OBJECT_t nobj;
5 andreas 3926
 
391 andreas 3927
        if (marqtype > 0 && marq)
3928
            nobj.type = OBJ_MARQUEE;
3929
        else
3930
            nobj.type = OBJ_BUTTON;
3931
 
296 andreas 3932
        nobj.handle = handle;
5 andreas 3933
 
198 andreas 3934
        if (gPageManager->isSetupActive())
3935
        {
296 andreas 3936
            nobj.width = scaleSetup(width);
3937
            nobj.height = scaleSetup(height);
3938
            nobj.left = scaleSetup(left);
3939
            nobj.top = scaleSetup(top);
198 andreas 3940
        }
3941
        else
3942
        {
296 andreas 3943
            nobj.width = scale(width);
3944
            nobj.height = scale(height);
3945
            nobj.left = scale(left);
3946
            nobj.top = scale(top);
198 andreas 3947
        }
3948
 
391 andreas 3949
        if (nobj.type == OBJ_MARQUEE)
3950
        {
398 andreas 3951
            nobj.object.marquee = new TQMarquee(par->object.widget, 1, static_cast<TQMarquee::MQ_TYPES>(marqtype), marq);
391 andreas 3952
            nobj.object.marquee->setObjectName(QString("Marquee_") + handleToString(handle).c_str());
323 andreas 3953
 
391 andreas 3954
            if (mGestureFilter)
3955
            {
3956
                nobj.object.marquee->installEventFilter(mGestureFilter);
3957
                nobj.object.marquee->grabGesture(Qt::PinchGesture);
3958
                nobj.object.marquee->grabGesture(Qt::SwipeGesture);
3959
            }
3960
 
3961
            nobj.object.marquee->setGeometry(nobj.left, nobj.top, nobj.width, nobj.height);
3962
 
3963
            if (passthrough)
3964
                nobj.object.marquee->setAttribute(Qt::WA_TransparentForMouseEvents);
3965
        }
3966
        else
323 andreas 3967
        {
391 andreas 3968
            nobj.object.label = new QLabel(par->object.widget);
3969
            nobj.object.label->setObjectName(QString("Label_") + handleToString(handle).c_str());
323 andreas 3970
 
391 andreas 3971
            if (mGestureFilter)
3972
            {
3973
                nobj.object.label->installEventFilter(mGestureFilter);
3974
                nobj.object.label->grabGesture(Qt::PinchGesture);
3975
                nobj.object.label->grabGesture(Qt::SwipeGesture);
3976
            }
296 andreas 3977
 
391 andreas 3978
            nobj.object.label->setGeometry(nobj.left, nobj.top, nobj.width, nobj.height);
298 andreas 3979
 
391 andreas 3980
            if (passthrough)
3981
                nobj.object.label->setAttribute(Qt::WA_TransparentForMouseEvents);
3982
        }
3983
 
296 andreas 3984
        if (!addObject(nobj))
3985
        {
3986
            MSG_ERROR("Unable to add the new object " << handleToString(handle) << "!");
334 andreas 3987
#if TESTMODE == 1
3988
            setScreenDone();
3989
#endif
296 andreas 3990
            return;
3991
        }
3992
 
3993
        obj = findObject(handle);
6 andreas 3994
    }
14 andreas 3995
    else
297 andreas 3996
    {
271 andreas 3997
        MSG_DEBUG("Object " << handleToString(handle) << " of type " << TObject::objectToString(obj->type) << " found!");
5 andreas 3998
 
298 andreas 3999
        if (passthrough && obj->object.label)
391 andreas 4000
        {
4001
            if (obj->type == OBJ_BUTTON)
4002
                obj->object.label->setAttribute(Qt::WA_TransparentForMouseEvents);
4003
            else
4004
                obj->object.marquee->setAttribute(Qt::WA_TransparentForMouseEvents);
4005
        }
298 andreas 4006
 
297 andreas 4007
        if (!enableObject(handle))
4008
        {
4009
            MSG_ERROR("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " couldn't be enabled!");
332 andreas 4010
#if TESTMODE == 1
334 andreas 4011
            setScreenDone();
332 andreas 4012
#endif
297 andreas 4013
            return;
4014
        }
334 andreas 4015
 
4016
        // In case the dimensions or position has changed we calculate the
4017
        // position and size again.
4018
        int lt, tp, wt, ht;
4019
 
4020
        if (gPageManager->isSetupActive())
4021
        {
4022
            wt = scaleSetup(width);
4023
            ht = scaleSetup(height);
4024
            lt = scaleSetup(left);
4025
            tp = scaleSetup(top);
4026
        }
4027
        else
4028
        {
4029
            wt = scale(width);
4030
            ht = scale(height);
4031
            lt = scale(left);
4032
            tp = scale(top);
4033
        }
4034
 
4035
        if (obj->type != OBJ_INPUT && (wt != obj->width || ht != obj->height || lt != obj->left || tp != obj->top))
4036
        {
4037
            MSG_DEBUG("Scaled button with new size: lt: " << obj->left << ", tp: " << obj->top << ", wt: " << obj->width << ", ht: " << obj->height);
4038
 
391 andreas 4039
            if (obj->type == OBJ_MARQUEE)
4040
                obj->object.marquee->setGeometry(lt, tp, wt, ht);
4041
            else
344 andreas 4042
                obj->object.label->setGeometry(lt, tp, wt, ht);
334 andreas 4043
 
4044
            obj->left = lt;
4045
            obj->top = tp;
4046
            obj->width = wt;
4047
            obj->height = ht;
4048
        }
297 andreas 4049
    }
4050
 
334 andreas 4051
    if (obj->type != OBJ_INPUT)
6 andreas 4052
    {
187 andreas 4053
        try
75 andreas 4054
        {
289 andreas 4055
            if (buffer.getSize() > 0 && buffer.getPixline() > 0)
107 andreas 4056
            {
271 andreas 4057
                MSG_DEBUG("Setting image for " << handleToString(handle) << " ...");
398 andreas 4058
                QPixmap pixmap = scaleImage(static_cast<unsigned char *>(buffer.getBitmap()), buffer.getWidth(), buffer.getHeight(), buffer.getPixline());
107 andreas 4059
 
391 andreas 4060
                if (obj->type == OBJ_MARQUEE && obj->object.marquee)
332 andreas 4061
                {
391 andreas 4062
                    obj->object.marquee->setBackground(pixmap);
4063
#if TESTMODE == 1
4064
                    __success = true;
4065
#endif
4066
                }
4067
                else if (obj->object.label)
4068
                {
187 andreas 4069
                    obj->object.label->setPixmap(pixmap);
332 andreas 4070
#if TESTMODE == 1
4071
                    __success = true;
4072
#endif
4073
                }
187 andreas 4074
                else
4075
                {
271 andreas 4076
                    MSG_WARNING("Object " << handleToString(handle) << " does not exist any more!");
187 andreas 4077
                }
107 andreas 4078
            }
75 andreas 4079
        }
187 andreas 4080
        catch(std::exception& e)
4081
        {
271 andreas 4082
            MSG_ERROR("Error drawing button " << handleToString(handle) << ": " << e.what());
187 andreas 4083
        }
4084
        catch(...)
4085
        {
4086
            MSG_ERROR("Unexpected exception occured [MainWindow::displayButton()]");
4087
        }
5 andreas 4088
    }
334 andreas 4089
#if TESTMODE == 1
4090
    setScreenDone();
4091
#endif
4 andreas 4092
}
4093
 
391 andreas 4094
void MainWindow::setMarqueeText(Button::TButton* button)
4095
{
4096
    DECL_TRACER("MainWindow::setMarqueeText(Button::TButton* button)");
4097
 
4098
    ulong handle = button->getHandle();
4099
    TObject::OBJECT_t *obj = findObject(handle);
4100
 
4101
    if (!obj)
4102
    {
4103
        MSG_WARNING("No object " << handleToString(handle) << " found!");
4104
        return;
4105
    }
4106
 
4107
    if (obj->type != OBJ_MARQUEE || !obj->object.marquee)
4108
    {
4109
        MSG_WARNING("Object " << handleToString(handle) << " is not a Marquee type or does not exist!");
4110
        return;
4111
    }
4112
 
4113
    TQMarquee *marquee = obj->object.marquee;
4114
    marquee->setText(button->getText().c_str());
395 andreas 4115
    marquee->setSpeed(button->getMarqueeSpeed(button->getActiveInstance()));
4116
    int frameSize = scale(button->getBorderSize(button->getBorderStyle(button->getActiveInstance())));
391 andreas 4117
    marquee->setFrame(frameSize, frameSize, frameSize, frameSize);
395 andreas 4118
    QFont font = loadFont(button->getFontIndex(button->getActiveInstance()), button->getFont(), button->getFontStyle());
391 andreas 4119
    marquee->setFont(font);
4120
}
4121
 
289 andreas 4122
void MainWindow::displayViewButton(ulong handle, ulong parent, bool vertical, TBitmap buffer, int width, int height, int left, int top, int space, TColor::COLOR_T fillColor)
279 andreas 4123
{
289 andreas 4124
    DECL_TRACER("MainWindow::displayViewButton(ulong handle, TBitmap buffer, size_t size, int width, int height, int left, int top)");
279 andreas 4125
 
343 andreas 4126
//    TLOCKER(draw_mutex);
279 andreas 4127
 
4128
    TObject::OBJECT_t *obj = findObject(handle);
4129
    TObject::OBJECT_t *par = findObject(parent);
4130
    MSG_TRACE("Processing button " << handleToString(handle) << " from parent " << handleToString(parent));
4131
 
4132
    if (!par)
4133
    {
4134
        if (TStreamError::checkFilter(HLOG_DEBUG))
4135
            MSG_WARNING("Button " << handleToString(handle) << " has no parent (" << handleToString(parent) << ")! Ignoring it.");
4136
 
332 andreas 4137
#if TESTMODE == 1
334 andreas 4138
        setScreenDone();
332 andreas 4139
#endif
279 andreas 4140
        return;
4141
    }
4142
 
4143
    if (par->animation && !par->aniDirection)
4144
    {
4145
        if (par->animation->state() == QAbstractAnimation::Running)
4146
        {
4147
            MSG_WARNING("Object " << handleToString(parent) << " is busy with an animation!");
4148
            par->animation->stop();
4149
        }
4150
        else
4151
        {
4152
            MSG_WARNING("Object " << handleToString(parent) << " has not finished the animation!");
4153
        }
4154
 
332 andreas 4155
#if TESTMODE == 1
334 andreas 4156
        setScreenDone();
332 andreas 4157
#endif
279 andreas 4158
        return;
4159
    }
4160
    else if (par->remove)
4161
    {
4162
        MSG_WARNING("Object " << handleToString(parent) << " is marked for remove. Will not draw image!");
332 andreas 4163
#if TESTMODE == 1
334 andreas 4164
        setScreenDone();
332 andreas 4165
#endif
279 andreas 4166
        return;
4167
    }
4168
 
4169
    if (!obj)
4170
    {
351 andreas 4171
        if (!par->object.widget)
4172
        {
4173
#if TESTMODE == 1
4174
            MSG_ERROR("Object " << handleToString(parent) << " has no valid object!");
4175
#endif
4176
            return;
4177
        }
4178
 
279 andreas 4179
        MSG_DEBUG("Adding new object " << handleToString(handle) << " ...");
296 andreas 4180
        OBJECT_t nobj;
279 andreas 4181
 
296 andreas 4182
        nobj.type = OBJ_SUBVIEW;
4183
        nobj.handle = handle;
4184
 
4185
        nobj.width = scale(width);
4186
        nobj.height = scale(height);
4187
        nobj.left = scale(left);
4188
        nobj.top = scale(top);
4189
 
4190
        nobj.object.area = new TQScrollArea(par->object.widget, nobj.width, nobj.height, vertical);
4191
        nobj.object.area->setObjectName(QString("View_") + handleToString(handle).c_str());
4192
        nobj.object.area->setScaleFactor(mScaleFactor);
4193
        nobj.object.area->setSpace(space);
4194
        nobj.object.area->move(nobj.left, nobj.top);
321 andreas 4195
        nobj.connected = true;
296 andreas 4196
        connect(nobj.object.area, &TQScrollArea::objectClicked, this, &MainWindow::onSubViewItemClicked);
4197
 
4198
        if (!addObject(nobj))
279 andreas 4199
        {
296 andreas 4200
            MSG_ERROR("Couldn't add the object " << handleToString(handle) << "!");
332 andreas 4201
#if TESTMODE == 1
334 andreas 4202
            setScreenDone();
332 andreas 4203
#endif
279 andreas 4204
            return;
4205
        }
4206
 
296 andreas 4207
        obj = findObject(handle);
279 andreas 4208
    }
4209
    else if (obj->type != OBJ_SUBVIEW)
4210
    {
4211
        MSG_ERROR("Object " << handleToString(handle) << " is of wrong type " << objectToString(obj->type) << "!");
332 andreas 4212
#if TESTMODE == 1
334 andreas 4213
        setScreenDone();
332 andreas 4214
#endif
279 andreas 4215
        return;
4216
    }
4217
    else
297 andreas 4218
    {
279 andreas 4219
        MSG_DEBUG("Object " << handleToString(handle) << " of type " << TObject::objectToString(obj->type) << " found!");
4220
 
321 andreas 4221
        if (obj->object.area && !obj->connected)
297 andreas 4222
            reconnectArea(obj->object.area);
4223
    }
4224
 
279 andreas 4225
    try
4226
    {
289 andreas 4227
        // Set background color
286 andreas 4228
        if (obj->object.area)
289 andreas 4229
        {
297 andreas 4230
            QColor color;
4231
 
4232
            if (fillColor.alpha == 0)
4233
                color = Qt::transparent;
4234
            else
4235
                color = qRgba(fillColor.red, fillColor.green, fillColor.blue, fillColor.alpha);
4236
 
289 andreas 4237
            obj->object.area->setBackGroundColor(color);
4238
        }
286 andreas 4239
 
289 andreas 4240
        if (buffer.getSize() > 0 && buffer.getPixline() > 0)
279 andreas 4241
        {
4242
            MSG_DEBUG("Setting image for " << handleToString(handle) << " ...");
398 andreas 4243
            QPixmap pixmap = scaleImage(static_cast<unsigned char *>(buffer.getBitmap()), buffer.getWidth(), buffer.getHeight(), buffer.getPixline());
279 andreas 4244
 
285 andreas 4245
            if (pixmap.isNull())
279 andreas 4246
            {
4247
                MSG_ERROR("Unable to create a pixmap out of an image!");
332 andreas 4248
#if TESTMODE == 1
334 andreas 4249
                setScreenDone();
332 andreas 4250
#endif
279 andreas 4251
                return;
4252
            }
4253
 
285 andreas 4254
            if (obj->object.area)
279 andreas 4255
            {
285 andreas 4256
                obj->object.area->setBackgroundImage(pixmap);
279 andreas 4257
            }
4258
            else
4259
            {
4260
                MSG_WARNING("Object " << handleToString(handle) << " does not exist any more!");
4261
            }
4262
        }
4263
    }
4264
    catch(std::exception& e)
4265
    {
4266
        MSG_ERROR("Error drawing button " << handleToString(handle) << ": " << e.what());
4267
    }
4268
    catch(...)
4269
    {
4270
        MSG_ERROR("Unexpected exception occured [MainWindow::displayViewButton()]");
4271
    }
4272
}
4273
 
285 andreas 4274
void MainWindow::addViewButtonItems(ulong parent, vector<PGSUBVIEWITEM_T> items)
279 andreas 4275
{
285 andreas 4276
    DECL_TRACER("MainWindow::addViewButtonItems(ulong parent, vector<PGSUBVIEWITEM_T> items)");
279 andreas 4277
 
285 andreas 4278
    if (items.empty())
4279
        return;
279 andreas 4280
 
285 andreas 4281
    OBJECT_t *par = findObject(parent);
279 andreas 4282
 
285 andreas 4283
    if (!par || par->type != OBJ_SUBVIEW || !par->object.area)
279 andreas 4284
    {
285 andreas 4285
        MSG_ERROR("No object with handle " << handleToString(parent) << " found or object is not a subview list!");
279 andreas 4286
        return;
4287
    }
4288
 
297 andreas 4289
    if (par->invalid)
4290
    {
4291
        if (!enableObject(parent))
4292
        {
4293
            MSG_ERROR("Object " << handleToString(parent) << " of type " << objectToString(par->type) << " couldn't be enabled!");
332 andreas 4294
#if TESTMODE == 1
334 andreas 4295
            setScreenDone();
332 andreas 4296
#endif
297 andreas 4297
            return;
4298
        }
4299
    }
4300
 
300 andreas 4301
    if (!items.empty())
4302
    {
4303
        par->object.area->setScrollbar(items[0].scrollbar);
4304
        par->object.area->setScrollbarOffset(items[0].scrollbarOffset);
4305
        par->object.area->setAnchor(items[0].position);
4306
    }
4307
 
285 andreas 4308
    par->object.area->addItems(items);
280 andreas 4309
}
4310
 
300 andreas 4311
void MainWindow::updateViewButton(ulong handle, ulong parent, TBitmap buffer, TColor::COLOR_T fillColor)
4312
{
4313
    DECL_TRACER("MainWindow::updateViewButton(ulong handle, ulong parent, TBitmap buffer, TColor::COLOR_T fillColor)");
4314
 
4315
    OBJECT_t *par = findObject(parent);
4316
 
4317
    if (!par || par->type != OBJ_SUBVIEW || !par->object.area)
4318
    {
4319
        MSG_ERROR("No object with handle " << handleToString(parent) << " found for update or object is not a subview list!");
332 andreas 4320
#if TESTMODE == 1
334 andreas 4321
        setScreenDone();
332 andreas 4322
#endif
300 andreas 4323
        return;
4324
    }
4325
 
4326
    PGSUBVIEWITEM_T item;
4327
    item.handle = handle;
4328
    item.parent = parent;
4329
    item.image = buffer;
4330
    item.bgcolor = fillColor;
4331
    par->object.area->updateItem(item);
4332
}
4333
 
4334
void MainWindow::updateViewButtonItem(PGSUBVIEWITEM_T& item, ulong parent)
4335
{
4336
    DECL_TRACER("MainWindow::updateViewButtonItem(PGSUBVIEWITEM_T& item, ulong parent)");
4337
 
4338
    OBJECT_t *par = findObject(parent);
4339
 
4340
    if (!par || par->type != OBJ_SUBVIEW || !par->object.area)
4341
    {
4342
        MSG_ERROR("No object with handle " << handleToString(parent) << " found for update or object is not a subview list!");
332 andreas 4343
#if TESTMODE == 1
334 andreas 4344
        setScreenDone();
332 andreas 4345
#endif
300 andreas 4346
        return;
4347
    }
4348
 
4349
    par->object.area->updateItem(item);
4350
}
4351
 
4352
void MainWindow::showViewButtonItem(ulong handle, ulong parent, int position, int timer)
4353
{
4354
    DECL_TRACER("MainWindow::showViewButtonItem(ulong handle, ulong parent, int position, int timer)");
4355
 
4356
    Q_UNUSED(timer);
4357
 
4358
    OBJECT_t *par = findObject(parent);
4359
 
4360
    if (!par || par->type != OBJ_SUBVIEW || !par->object.area)
4361
    {
4362
        MSG_ERROR("No object with handle " << handleToString(parent) << " found for update or object is not a subview list!");
332 andreas 4363
#if TESTMODE == 1
334 andreas 4364
        setScreenDone();
332 andreas 4365
#endif
300 andreas 4366
        return;
4367
    }
4368
 
4369
    par->object.area->showItem(handle, position);
4370
}
4371
 
318 andreas 4372
void MainWindow::toggleViewButtonItem(ulong handle, ulong parent, int position, int timer)
4373
{
4374
    DECL_TRACER("MainWindow::toggleViewButtonItem(ulong handle, ulong parent, int position, int timer)");
4375
 
4376
    Q_UNUSED(timer);
4377
 
4378
    OBJECT_t *par = findObject(parent);
4379
 
4380
    if (!par || par->type != OBJ_SUBVIEW || !par->object.area)
4381
    {
4382
        MSG_ERROR("No object with handle " << handleToString(parent) << " found for update or object is not a subview list!");
332 andreas 4383
#if TESTMODE == 1
334 andreas 4384
        setScreenDone();
332 andreas 4385
#endif
318 andreas 4386
        return;
4387
    }
4388
 
4389
    par->object.area->showItem(handle, position);
4390
}
4391
 
4392
void MainWindow::hideAllViewItems(ulong handle)
4393
{
4394
    DECL_TRACER("MainWindow::hideAllViewItems(ulong handle)");
4395
 
4396
    OBJECT_t *obj = findObject(handle);
4397
 
4398
    if (!obj || obj->type != OBJ_SUBVIEW || !obj->object.area)
332 andreas 4399
    {
4400
#if TESTMODE == 1
334 andreas 4401
        setScreenDone();
332 andreas 4402
#endif
318 andreas 4403
        return;
332 andreas 4404
    }
318 andreas 4405
 
4406
    obj->object.area->hideAllItems();
4407
}
4408
 
4409
void MainWindow::hideViewItem(ulong handle, ulong parent)
4410
{
4411
    DECL_TRACER("MainWindow::hideViewItem(ulong handle, ulong parent)");
4412
 
4413
    OBJECT_t *obj = findObject(parent);
4414
 
4415
    if (!obj || obj->type != OBJ_SUBVIEW || !obj->object.area)
332 andreas 4416
    {
4417
#if TESTMODE == 1
334 andreas 4418
        setScreenDone();
332 andreas 4419
#endif
318 andreas 4420
        return;
332 andreas 4421
    }
318 andreas 4422
 
4423
    obj->object.area->hideItem(handle);
4424
}
4425
 
98 andreas 4426
void MainWindow::SetVisible(ulong handle, bool state)
4427
{
4428
    DECL_TRACER("MainWindow::SetVisible(ulong handle, bool state)");
4429
 
318 andreas 4430
    OBJECT_t *obj = findObject(handle);
98 andreas 4431
 
4432
    if (!obj)
4433
    {
271 andreas 4434
        MSG_ERROR("Object " << handleToString(handle) << " not found!");
332 andreas 4435
#if TESTMODE == 1
334 andreas 4436
        setScreenDone();
332 andreas 4437
#endif
98 andreas 4438
        return;
4439
    }
4440
 
318 andreas 4441
    if (obj->type == OBJ_BUTTON && obj->object.label)
99 andreas 4442
    {
98 andreas 4443
        obj->object.label->setVisible(state);
297 andreas 4444
        obj->invalid = false;
4445
        obj->remove = false;
99 andreas 4446
    }
391 andreas 4447
    else if (obj->type == OBJ_MARQUEE && obj->object.marquee)
4448
    {
4449
        obj->object.marquee->setVisible(state);
4450
        obj->invalid = false;
4451
        obj->remove = false;
4452
    }
318 andreas 4453
    else if (obj->type == OBJ_SUBVIEW && obj->object.area)
4454
    {
4455
        obj->object.area->setVisible(state);
4456
        obj->invalid = false;
4457
        obj->remove = false;
4458
    }
99 andreas 4459
    else
4460
    {
271 andreas 4461
        MSG_DEBUG("Ignoring non button object " << handleToString(handle));
99 andreas 4462
    }
98 andreas 4463
}
4464
 
318 andreas 4465
void MainWindow::setSubViewPadding(ulong handle, int padding)
4466
{
4467
    DECL_TRACER("MainWindow::setSubViewPadding(ulong handle, int padding)");
4468
 
4469
    OBJECT_t *obj = findObject(handle);
4470
 
4471
    if (!obj)
4472
    {
4473
        MSG_ERROR("Object " << handleToString(handle) << " not found!");
332 andreas 4474
#if TESTMODE == 1
334 andreas 4475
        setScreenDone();
332 andreas 4476
#endif
318 andreas 4477
        return;
4478
    }
4479
 
4480
    if (obj->type != OBJ_SUBVIEW || !obj->object.area)
332 andreas 4481
    {
4482
#if TESTMODE == 1
334 andreas 4483
        setScreenDone();
332 andreas 4484
#endif
318 andreas 4485
        return;
332 andreas 4486
    }
318 andreas 4487
 
4488
    obj->object.area->setSpace(padding);
4489
}
4490
 
215 andreas 4491
/**
217 andreas 4492
 * @brief Prepares a new object.
215 andreas 4493
 * The method first checks whether there exists a background widget or not. If
4494
 * not it creates a background widget with a black background. On Android this
4495
 * image is the size of the whole screen while on a desktop it is only the size
4496
 * of a page plus the task bar, if any.
217 andreas 4497
 * If the background image (centralWidget()) already exists, it set's only the
4498
 * credentials of the object.
4499
 * It makes sure that all child objects of the central widget are destroyed.
215 andreas 4500
 *
4501
 * @param handle    The handle of the new widget
4502
 * @param width     The original width of the page
4503
 * @param heoght    The original height of the page
4504
 */
5 andreas 4505
void MainWindow::setPage(ulong handle, int width, int height)
4506
{
4507
    DECL_TRACER("MainWindow::setPage(ulong handle, int width, int height)");
4 andreas 4508
 
277 andreas 4509
    if (handle == mActualPageHandle)
332 andreas 4510
    {
4511
#if TESTMODE == 1
334 andreas 4512
        setScreenDone();
332 andreas 4513
#endif
277 andreas 4514
        return;
332 andreas 4515
    }
277 andreas 4516
 
369 andreas 4517
//    TLOCKER(draw_mutex);
277 andreas 4518
    QWidget *wBackground = centralWidget();
4519
 
4520
    if (!wBackground)
107 andreas 4521
    {
277 andreas 4522
        MSG_ERROR("No central widget!");
332 andreas 4523
#if TESTMODE == 1
334 andreas 4524
        setScreenDone();
332 andreas 4525
#endif
107 andreas 4526
        return;
4527
    }
4528
 
277 andreas 4529
    if (!mCentralWidget)
4530
    {
4531
        MSG_ERROR("Stack for pages not initialized!");
332 andreas 4532
#if TESTMODE == 1
334 andreas 4533
        setScreenDone();
332 andreas 4534
#endif
215 andreas 4535
        return;
277 andreas 4536
    }
215 andreas 4537
 
4538
    // The following should be true only for the first time this method is called.
277 andreas 4539
    if (!mCentralInitialized)
215 andreas 4540
    {
4541
        QSize qs = menuBar()->sizeHint();
198 andreas 4542
 
215 andreas 4543
        if (gPageManager && gPageManager->isSetupActive())
4544
            setMinimumSize(scaleSetup(width), scaleSetup(height) + qs.height());
4545
        else
4546
            setMinimumSize(scale(width), scale(height) + qs.height());
265 andreas 4547
 
4548
        mCentralInitialized = true;
215 andreas 4549
    }
198 andreas 4550
 
296 andreas 4551
    OBJECT_t *obj = findObject(handle);
5 andreas 4552
 
4553
    if (!obj)
4554
    {
271 andreas 4555
        MSG_DEBUG("Adding new object " << handleToString(handle));
296 andreas 4556
        OBJECT_t nobj;
5 andreas 4557
 
296 andreas 4558
        nobj.handle = handle;
4559
        nobj.type = OBJ_PAGE;
4560
        nobj.object.widget = nullptr;
5 andreas 4561
 
217 andreas 4562
        if (gPageManager && gPageManager->isSetupActive())
4563
        {
296 andreas 4564
            nobj.height = scaleSetup(height);
4565
            nobj.width = scaleSetup(width);
217 andreas 4566
        }
4567
        else
4568
        {
296 andreas 4569
            nobj.height = scale(height);
4570
            nobj.width = scale(width);
217 andreas 4571
        }
296 andreas 4572
 
4573
        if (!addObject(nobj))
4574
        {
4575
            MSG_ERROR("Error crating an object for handle " << handleToString(handle));
332 andreas 4576
#if TESTMODE == 1
334 andreas 4577
            setScreenDone();
332 andreas 4578
#endif
296 andreas 4579
            return;
4580
        }
4581
 
4582
        obj = findObject(handle);
5 andreas 4583
    }
296 andreas 4584
    else
271 andreas 4585
    {
296 andreas 4586
        if (obj->type != OBJ_PAGE)
4587
        {
4588
            MSG_WARNING("Object " << handleToString(handle) << " is not a page! Will not reuse it as a page.");
332 andreas 4589
#if TESTMODE == 1
334 andreas 4590
            setScreenDone();
332 andreas 4591
#endif
296 andreas 4592
            return;
4593
        }
4594
 
4595
        if (obj->object.widget && obj->object.widget->isHidden() && mCentralWidget->indexOf(obj->object.widget) >= 0)
271 andreas 4596
            obj->object.widget->setParent(wBackground);
220 andreas 4597
 
277 andreas 4598
        obj->invalid = false;
296 andreas 4599
        obj->remove = false;
277 andreas 4600
        MSG_DEBUG("Hidden object " << handleToString(handle) << " was reactivated.");
217 andreas 4601
    }
227 andreas 4602
 
277 andreas 4603
    if (!obj->object.widget)
264 andreas 4604
    {
277 andreas 4605
        obj->object.widget = new QWidget;
271 andreas 4606
        obj->object.widget->setObjectName(QString("Page_") + handleToString(handle).c_str());
323 andreas 4607
 
4608
        if (mGestureFilter)
4609
        {
4610
            obj->object.widget->installEventFilter(mGestureFilter);
4611
            obj->object.widget->grabGesture(Qt::PinchGesture);
4612
            obj->object.widget->grabGesture(Qt::SwipeGesture);
4613
        }
4614
 
277 andreas 4615
        obj->object.widget->setAutoFillBackground(true);
271 andreas 4616
        obj->invalid = false;
275 andreas 4617
        obj->object.widget->move(0, 0);
266 andreas 4618
#if defined(Q_OS_IOS) || defined(Q_OS_ANDROID)
275 andreas 4619
        obj->object.widget->setFixedSize(obj->width, obj->height);
266 andreas 4620
#else
4621
        obj->object.widget->setGeometry(geometry());
4622
#endif
277 andreas 4623
        mCentralWidget->addWidget(obj->object.widget);
264 andreas 4624
    }
4625
 
213 andreas 4626
    mActualPageHandle = handle;
271 andreas 4627
    MSG_PROTOCOL("Current page: " << handleToString(handle));
5 andreas 4628
}
4629
 
217 andreas 4630
void MainWindow::setSubPage(ulong handle, ulong parent, int left, int top, int width, int height, ANIMATION_t animate)
5 andreas 4631
{
4632
    DECL_TRACER("MainWindow::setSubPage(ulong handle, int left, int top, int width, int height)");
38 andreas 4633
 
406 andreas 4634
    Q_UNUSED(height);
296 andreas 4635
    OBJECT_t *par = findObject(parent);
107 andreas 4636
 
296 andreas 4637
    if (!par || par->type != OBJ_PAGE)
38 andreas 4638
    {
264 andreas 4639
        if (!par)
4640
        {
271 andreas 4641
            MSG_ERROR("Subpage " << handleToString(handle) << " has no parent! Ignoring it.");
264 andreas 4642
        }
4643
        else
4644
        {
271 andreas 4645
            MSG_ERROR("Subpage " << handleToString(handle) << " has invalid parent " << handleToString(parent) << " which is no page! Ignoring it.");
264 andreas 4646
        }
332 andreas 4647
#if TESTMODE == 1
334 andreas 4648
        setScreenDone();
332 andreas 4649
#endif
217 andreas 4650
        return;
38 andreas 4651
    }
4652
 
278 andreas 4653
    if (!par->object.widget)
4654
    {
297 andreas 4655
        MSG_ERROR("Parent page " << handleToString(parent) << " has no widget defined!");
332 andreas 4656
#if TESTMODE == 1
334 andreas 4657
        setScreenDone();
332 andreas 4658
#endif
278 andreas 4659
        return;
4660
    }
4661
 
4662
    if (mCentralWidget && mCentralWidget->currentWidget() != par->object.widget)
4663
    {
4664
        MSG_WARNING("The parent page " << handleToString(parent) << " is not the current page " << handleToString(handle) << "!");
332 andreas 4665
#if TESTMODE == 1
334 andreas 4666
        setScreenDone();
332 andreas 4667
#endif
278 andreas 4668
        return;
4669
    }
4670
 
296 andreas 4671
    OBJECT_t *obj = findObject(handle);
4672
    OBJECT_t nobj;
4673
    bool shouldAdd = false;
272 andreas 4674
 
296 andreas 4675
    if (obj && obj->type != OBJ_SUBPAGE)
271 andreas 4676
    {
4677
        MSG_WARNING("Object " << handleToString(handle) << " exists but is not a subpage! Refusing to create a new page with this handle.");
332 andreas 4678
#if TESTMODE == 1
334 andreas 4679
        setScreenDone();
332 andreas 4680
#endif
271 andreas 4681
        return;
4682
    }
4683
    else if (!obj)
5 andreas 4684
    {
296 andreas 4685
        obj = &nobj;
4686
        shouldAdd = true;
5 andreas 4687
    }
297 andreas 4688
    else
4689
    {
4690
        obj->invalid = false;
4691
        obj->remove = false;
4692
    }
5 andreas 4693
 
296 andreas 4694
    int scLeft = 0;
4695
    int scTop = 0;
4696
    int scWidth = 0;
4697
    int scHeight = 0;
38 andreas 4698
 
198 andreas 4699
    if (gPageManager && gPageManager->isSetupActive())
4700
    {
4701
        scLeft = scaleSetup(left);
4702
        scTop = scaleSetup(top);
4703
        scWidth = scaleSetup(width);
4704
        scHeight = scaleSetup(height);
4705
    }
4706
    else
4707
    {
4708
        scLeft = scale(left);
4709
        scTop = scale(top);
4710
        scWidth = scale(width);
4711
        scHeight = scale(height);
4712
    }
4713
 
296 andreas 4714
    obj->type = OBJ_SUBPAGE;
5 andreas 4715
    obj->handle = handle;
271 andreas 4716
 
4717
    if (!obj->object.widget)
278 andreas 4718
    {
4719
        obj->object.widget = new QWidget(par->object.widget);
4720
        obj->object.widget->setObjectName(QString("Subpage_%1").arg(handleToString(handle).c_str()));
4721
    }
271 andreas 4722
    else
278 andreas 4723
        obj->object.widget->setParent(par->object.widget);
271 andreas 4724
 
6 andreas 4725
    obj->object.widget->setAutoFillBackground(true);
275 andreas 4726
    obj->object.widget->move(scLeft, scTop);
38 andreas 4727
    obj->object.widget->setFixedSize(scWidth, scHeight);
4728
    obj->left = scLeft;
4729
    obj->top = scTop;
4730
    obj->width = scWidth;
4731
    obj->height = scHeight;
271 andreas 4732
    obj->invalid = false;
296 andreas 4733
    obj->remove = false;
15 andreas 4734
    // filter move event
323 andreas 4735
    if (mGestureFilter)
4736
    {
4737
        obj->object.widget->installEventFilter(mGestureFilter);
4738
        obj->object.widget->grabGesture(Qt::PinchGesture);
4739
        obj->object.widget->grabGesture(Qt::SwipeGesture);
4740
    }
4741
 
107 andreas 4742
    obj->aniDirection = true;
277 andreas 4743
    obj->animate = animate;
296 andreas 4744
 
4745
    if (shouldAdd)
4746
    {
4747
        if (!addObject(nobj))
4748
        {
4749
            MSG_ERROR("Couldn't add the object " << handleToString(handle) << "!");
4750
            nobj.object.widget->close();
332 andreas 4751
#if TESTMODE == 1
334 andreas 4752
            setScreenDone();
332 andreas 4753
#endif
296 andreas 4754
        }
4755
    }
5 andreas 4756
}
4757
 
265 andreas 4758
#ifdef _OPAQUE_SKIA_
289 andreas 4759
void MainWindow::setBackground(ulong handle, TBitmap image, int width, int height, ulong color)
262 andreas 4760
#else
289 andreas 4761
void MainWindow::setBackground(ulong handle, TBitmap image, int width, int height, ulong color, int opacity)
262 andreas 4762
#endif
5 andreas 4763
{
369 andreas 4764
//    TLOCKER(draw_mutex);
289 andreas 4765
    DECL_TRACER("MainWindow::setBackground(ulong handle, TBitmap image, ulong color [, int opacity])");
5 andreas 4766
 
277 andreas 4767
    if (!mCentralWidget)
107 andreas 4768
    {
277 andreas 4769
        MSG_ERROR("The internal page stack is not initialized!");
332 andreas 4770
#if TESTMODE == 1
334 andreas 4771
        setScreenDone();
332 andreas 4772
#endif
107 andreas 4773
        return;
4774
    }
5 andreas 4775
 
296 andreas 4776
    OBJECT_t *obj = findObject(handle);
107 andreas 4777
 
296 andreas 4778
    if (!obj || obj->remove)
5 andreas 4779
    {
271 andreas 4780
#ifdef QT_DEBUG
349 andreas 4781
        if (obj)
4782
        {
4783
            MSG_WARNING("No object " << handleToString(handle) << " found! (Flag remove: " << (obj->remove ? "TRUE" : "FALSE") << ")");
4784
        }
4785
        else
4786
        {
4787
            MSG_WARNING("No object " << handleToString(handle) << " found!");
4788
        }
271 andreas 4789
#else
4790
        MSG_WARNING("No object " << handleToString(handle) << " found!");
4791
#endif
332 andreas 4792
#if TESTMODE == 1
334 andreas 4793
        setScreenDone();
332 andreas 4794
#endif
5 andreas 4795
        return;
4796
    }
296 andreas 4797
    else if (obj->invalid)
297 andreas 4798
    {
4799
        if (!enableObject(handle))
4800
        {
4801
            MSG_ERROR("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " couldn't be anabled!");
332 andreas 4802
#if TESTMODE == 1
334 andreas 4803
            setScreenDone();
332 andreas 4804
#endif
297 andreas 4805
            return;
4806
        }
4807
    }
5 andreas 4808
 
297 andreas 4809
    if (obj->type != OBJ_SUBPAGE && obj->type != OBJ_BUTTON && obj->type != OBJ_PAGE)
4810
    {
4811
        MSG_ERROR("Method does not support object type " << objectToString(obj->type) << " for object " << handleToString(handle) << "!");
332 andreas 4812
#if TESTMODE == 1
334 andreas 4813
        setScreenDone();
332 andreas 4814
#endif
297 andreas 4815
        return;
4816
    }
4817
 
277 andreas 4818
    MSG_DEBUG("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " found!");
5 andreas 4819
 
296 andreas 4820
    if (obj->type == OBJ_BUTTON || obj->type == OBJ_SUBPAGE)
5 andreas 4821
    {
277 andreas 4822
        MSG_DEBUG("Processing object " << objectToString(obj->type));
198 andreas 4823
 
391 andreas 4824
        if ((obj->type == OBJ_BUTTON || obj->type == OBJ_MARQUEE) && !obj->object.label)
198 andreas 4825
        {
271 andreas 4826
            MSG_ERROR("The label of the object " << handleToString(handle) << " was not initialized!");
332 andreas 4827
#if TESTMODE == 1
334 andreas 4828
            setScreenDone();
332 andreas 4829
#endif
198 andreas 4830
            return;
4831
        }
296 andreas 4832
        else if (obj->type == OBJ_SUBPAGE && !obj->object.widget)
198 andreas 4833
        {
271 andreas 4834
            MSG_ERROR("The widget of the object " << handleToString(handle) << " was not initialized!");
332 andreas 4835
#if TESTMODE == 1
334 andreas 4836
            setScreenDone();
332 andreas 4837
#endif
198 andreas 4838
            return;
4839
        }
4840
 
6 andreas 4841
        QPixmap pix(obj->width, obj->height);
5 andreas 4842
 
291 andreas 4843
        if (TColor::getAlpha(color) == 0)
4844
            pix.fill(Qt::transparent);
4845
        else
4846
            pix.fill(QColor::fromRgba(qRgba(TColor::getRed(color),TColor::getGreen(color),TColor::getBlue(color),TColor::getAlpha(color))));
4847
 
289 andreas 4848
        if (image.isValid() > 0)
5 andreas 4849
        {
289 andreas 4850
            MSG_DEBUG("Setting image of size " << image.getSize() << " (" << image.getWidth() << " x " << image.getHeight() << ")");
4851
            QImage img(image.getBitmap(), image.getWidth(), image.getHeight(), image.getPixline(), QImage::Format_ARGB32);
38 andreas 4852
 
198 andreas 4853
            if (isScaled() || (gPageManager && gPageManager->isSetupActive()))
38 andreas 4854
            {
4855
                QSize size(obj->width, obj->height);
4856
                pix.convertFromImage(img.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
4857
            }
4858
            else
4859
                pix.convertFromImage(img);
6 andreas 4860
        }
4861
 
391 andreas 4862
        if (obj->type == OBJ_BUTTON)
5 andreas 4863
            obj->object.label->setPixmap(pix);
391 andreas 4864
        else if (obj->type == OBJ_MARQUEE)
4865
            obj->object.marquee->setBackground(pix);
6 andreas 4866
        else
5 andreas 4867
        {
271 andreas 4868
            MSG_DEBUG("Setting image as background for subpage " << handleToString(handle));
296 andreas 4869
            QPalette palette(obj->object.widget->palette());
262 andreas 4870
#ifndef _OPAQUE_SKIA_
4871
            qreal oo;
4872
 
4873
            if (opacity < 0)
4874
                oo = 0.0;
4875
            else if (opacity > 255)
4876
                oo = 1.0;
4877
            else
4878
                oo = 1.0 / 255.0 * (qreal)opacity;
4879
 
4880
            if (oo < 1.0)
4881
            {
272 andreas 4882
                QPixmap image(pix.size());      //Image with given size and format.
4883
                image.fill(Qt::transparent);    //fills with transparent
262 andreas 4884
                QPainter p(&image);
272 andreas 4885
                p.setOpacity(oo);               // set opacity from 0.0 to 1.0, where 0.0 is fully transparent and 1.0 is fully opaque.
4886
                p.drawPixmap(0, 0, pix);        // given pixmap into the paint device.
278 andreas 4887
                p.end();
277 andreas 4888
                palette.setBrush(QPalette::Window, QBrush(image));
262 andreas 4889
                MSG_DEBUG("Opacity was set to " << oo);
4890
            }
277 andreas 4891
            else
4892
                palette.setBrush(QPalette::Window, QBrush(pix));
4893
#else
4894
            palette.setBrush(QPalette::Window, QBrush(pix));
262 andreas 4895
#endif
198 andreas 4896
            obj->object.widget->setPalette(palette);
5 andreas 4897
        }
4898
    }
107 andreas 4899
    else if (obj->type == TObject::OBJ_PAGE)
5 andreas 4900
    {
297 andreas 4901
        MSG_DEBUG("Processing object of type PAGE ...");
277 andreas 4902
        QWidget *central = obj->object.widget;
222 andreas 4903
 
265 andreas 4904
        if (!central)
5 andreas 4905
        {
271 andreas 4906
            MSG_ERROR("There is no page widget initialized for page " << handleToString(handle));
332 andreas 4907
#if TESTMODE == 1
334 andreas 4908
            setScreenDone();
332 andreas 4909
#endif
215 andreas 4910
            displayMessage("Can't set a background without an active page!", "Internal error");
4911
            return;
5 andreas 4912
        }
264 andreas 4913
 
277 andreas 4914
        QWidget *current = mCentralWidget->currentWidget();
272 andreas 4915
        int index = -1;
4916
 
4917
        if (current && central != current)
264 andreas 4918
        {
272 andreas 4919
            if ((index = mCentralWidget->indexOf(central)) < 0)
4920
            {
277 andreas 4921
                QString obName = QString("Page_%1").arg(handleToString(handle).c_str());
4922
 
4923
                for (int i = 0; i < mCentralWidget->count(); ++i)
4924
                {
4925
                    QWidget *w = mCentralWidget->widget(i);
4926
                    MSG_DEBUG("Checking widget " << w->objectName().toStdString());
4927
 
4928
                    if (w->objectName() == obName)
4929
                    {
4930
                        index = i;
4931
                        break;
4932
                    }
4933
                }
4934
 
4935
                if (index < 0)
4936
                {
291 andreas 4937
                    MSG_WARNING("Missing page " << handleToString(handle) << " on stack! Will add it to the stack.");
277 andreas 4938
                    index = mCentralWidget->addWidget(central);
4939
                    MSG_DEBUG("Number pages on stack: " << mCentralWidget->count());
4940
                    QRect geomMain = geometry();
4941
                    QRect geomCent = mCentralWidget->geometry();
4942
                    MSG_DEBUG("Geometry MainWindow: left: " << geomMain.left() << ", right: " << geomMain.right() << ", top: " << geomMain.top() << ", bottom: " << geomMain.bottom());
4943
                    MSG_DEBUG("Geometry CentWindow: left: " << geomCent.left() << ", right: " << geomCent.right() << ", top: " << geomCent.top() << ", bottom: " << geomCent.bottom());
4944
                }
272 andreas 4945
            }
264 andreas 4946
        }
277 andreas 4947
        else
272 andreas 4948
            index = mCentralWidget->indexOf(central);
4949
 
6 andreas 4950
        QPixmap pix(obj->width, obj->height);
291 andreas 4951
        QColor backgroundColor;
4952
 
4953
        if (TColor::getAlpha(color) == 0)
4954
            backgroundColor = Qt::transparent;
4955
        else
4956
            backgroundColor = QColor::fromRgba(qRgba(TColor::getRed(color),TColor::getGreen(color),TColor::getBlue(color),TColor::getAlpha(color)));
4957
 
221 andreas 4958
        pix.fill(backgroundColor);
265 andreas 4959
        MSG_DEBUG("Filled background of size " << pix.width() << "x" << pix.height() << " with color #" << std::setfill('0') << std::setw(8) << std::hex << color);
6 andreas 4960
 
289 andreas 4961
        if (width > 0 && image.isValid())
5 andreas 4962
        {
289 andreas 4963
            QImage img(image.getBitmap(), image.getWidth(), image.getHeight(), image.getPixline(), QImage::Format_ARGB32);
221 andreas 4964
            bool valid = false;
38 andreas 4965
 
222 andreas 4966
            if (!img.isNull())
4967
            {
4968
                if (isScaled())
4969
                {
296 andreas 4970
                    QImage bgImage = img.scaled(obj->width, obj->height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
223 andreas 4971
                    valid = pix.convertFromImage(bgImage);
277 andreas 4972
                    MSG_DEBUG("Scaled image from " << width << "x" << height << " to " << obj->width << "x" << obj->height);
222 andreas 4973
                }
4974
                else
4975
                {
4976
                    valid = pix.convertFromImage(img);
277 andreas 4977
                    MSG_DEBUG("Converted image to pixmap.");
222 andreas 4978
                }
4979
            }
221 andreas 4980
 
4981
            if (!valid || pix.isNull())
4982
            {
222 andreas 4983
                if (pix.isNull())
4984
                    pix = QPixmap(obj->width, obj->height);
4985
 
221 andreas 4986
                pix.fill(backgroundColor);
289 andreas 4987
                MSG_WARNING("Error converting an image! Size raw data: " << image.getSize() << ", Width: " << image.getWidth() << ", Height: " << image.getHeight() << ", Bytes per row: " << image.getPixline());
221 andreas 4988
            }
6 andreas 4989
        }
5 andreas 4990
 
223 andreas 4991
        QPalette palette(central->palette());
222 andreas 4992
        palette.setBrush(QPalette::Window, QBrush(pix));
4993
        central->setPalette(palette);
6 andreas 4994
 
272 andreas 4995
        if (index >= 0)
4996
            mCentralWidget->setCurrentIndex(index);
275 andreas 4997
        else if (mCentralWidget)
4998
        {
4999
            index = mCentralWidget->addWidget(central);
5000
            mCentralWidget->setCurrentIndex(index);
5001
            MSG_DEBUG("Page widget " << handleToString(handle) << " was added at index " << index);
5002
        }
272 andreas 5003
 
6 andreas 5004
        MSG_DEBUG("Background set");
5 andreas 5005
    }
5006
}
5007
 
296 andreas 5008
void MainWindow::disconnectArea(TQScrollArea* area)
5009
{
5010
    DECL_TRACER("MainWindow::disconnectArea(TQScrollArea* area)");
5011
 
297 andreas 5012
    if (!area)
5013
        return;
5014
 
296 andreas 5015
    disconnect(area, &TQScrollArea::objectClicked, this, &MainWindow::onSubViewItemClicked);
5016
}
5017
 
5018
void MainWindow::disconnectList(QListWidget* list)
5019
{
5020
    DECL_TRACER("MainWindow::disconnectList(QListWidget* list)");
5021
 
297 andreas 5022
    if (!list)
5023
        return;
5024
 
296 andreas 5025
    disconnect(list, &QListWidget::currentItemChanged, this, &MainWindow::onTListCallbackCurrentItemChanged);
5026
}
5027
 
297 andreas 5028
void MainWindow::reconnectArea(TQScrollArea * area)
5029
{
5030
    DECL_TRACER("MainWindow::reconnectArea(TQScrollArea * area)");
5031
 
5032
    if (!area)
5033
        return;
5034
 
5035
    connect(area, &TQScrollArea::objectClicked, this, &MainWindow::onSubViewItemClicked);
5036
}
5037
 
5038
void MainWindow::reconnectList(QListWidget *list)
5039
{
5040
    DECL_TRACER("MainWindow::reconnectList(QListWidget *list)");
5041
 
5042
    if (!list)
5043
        return;
5044
 
5045
    connect(list, &QListWidget::currentItemChanged, this, &MainWindow::onTListCallbackCurrentItemChanged);
5046
}
5047
 
296 andreas 5048
/**
5049
 * @brief MainWindow::dropPage - Marks a page invalid
5050
 * This method marks a page and all the object on the page as invalid. They are
5051
 * not deleted. Instead the page, a QWidget representing a page, is set hidden.
5052
 * With it all childs of the QWidget are also hidden. So the page can be
5053
 * displayed later when it is used again.
5054
 *
5055
 * @param handle    The handle of the page.
5056
 */
11 andreas 5057
void MainWindow::dropPage(ulong handle)
5058
{
343 andreas 5059
//    TLOCKER(draw_mutex);
11 andreas 5060
    DECL_TRACER("MainWindow::dropPage(ulong handle)");
7 andreas 5061
 
271 andreas 5062
    MSG_PROTOCOL("Dropping page " << handleToString(handle));
265 andreas 5063
 
294 andreas 5064
    OBJECT_t *obj = findObject(handle);
264 andreas 5065
 
296 andreas 5066
    if (!obj)
5067
    {
5068
        MSG_WARNING("Object " << handleToString(handle) << " (Page) does not exist. Ignoring!");
348 andreas 5069
#if TESTMODE == 1
5070
        setScreenDone();
5071
#endif
296 andreas 5072
        return;
5073
    }
271 andreas 5074
 
296 andreas 5075
    if (obj->type != OBJ_PAGE)
271 andreas 5076
    {
296 andreas 5077
        MSG_WARNING("Object " << handleToString(handle) << " is not a page!");
348 andreas 5078
#if TESTMODE == 1
5079
        setScreenDone();
5080
#endif
296 andreas 5081
        return;
271 andreas 5082
    }
296 andreas 5083
 
5084
    MSG_DEBUG("Dropping page " << handleToString(handle));
5085
    invalidateAllSubObjects(handle);
5086
 
297 andreas 5087
    if (obj->object.widget)
348 andreas 5088
    {
296 andreas 5089
        obj->object.widget->setHidden(true);
348 andreas 5090
#if TESTMODE == 1
5091
        __success = true;
5092
#endif
5093
    }
5094
#if TESTMODE == 1
5095
    setScreenDone();
5096
#endif
11 andreas 5097
}
5098
 
350 andreas 5099
void MainWindow::dropSubPage(ulong handle, ulong parent)
11 andreas 5100
{
350 andreas 5101
    DECL_TRACER("MainWindow::dropSubPage(ulong handle, ulong parent)");
11 andreas 5102
 
294 andreas 5103
    OBJECT_t *obj = findObject(handle);
350 andreas 5104
    OBJECT_t *par = findObject(parent);
11 andreas 5105
 
5106
    if (!obj)
5107
    {
296 andreas 5108
        MSG_WARNING("Object " << handleToString(handle) << " (SubPage) does not exist. Ignoring!");
335 andreas 5109
#if TESTMODE == 1
5110
        setScreenDone();
5111
#endif
11 andreas 5112
        return;
5113
    }
5114
 
350 andreas 5115
    if (!par)
5116
    {
5117
        MSG_DEBUG("Parent object " << handleToString(parent) << " not found!");
5118
#if TESTMODE == 1
5119
        setScreenDone();
5120
#endif
5121
        return;
5122
    }
5123
 
297 andreas 5124
    if (obj->type != OBJ_SUBPAGE)
296 andreas 5125
    {
5126
        MSG_WARNING("Object " << handleToString(handle) << " is not a SubPage!");
335 andreas 5127
#if TESTMODE == 1
5128
        setScreenDone();
5129
#endif
217 andreas 5130
        return;
296 andreas 5131
    }
217 andreas 5132
 
350 andreas 5133
    QWidget *w = par->object.widget->findChild<QWidget *>(QString("Subpage_%1").arg(handleToString(handle).c_str()));
5134
 
5135
    if (!w)
5136
    {
5137
        MSG_DEBUG("Parent object " << handleToString(parent) << " has no child " << handleToString(handle) << "!");
5138
        obj->object.widget = nullptr;
5139
        obj->remove = true;
5140
        obj->invalid = true;
5141
#if TESTMODE == 1
5142
        setScreenDone();
5143
#endif
5144
        return;
5145
    }
5146
 
296 andreas 5147
    MSG_DEBUG("Dropping subpage " << handleToString(handle));
5148
    invalidateAllSubObjects(handle);
107 andreas 5149
    obj->aniDirection = false;
217 andreas 5150
 
5151
    if (gPageManager && gPageManager->isSetupActive())
5152
        obj->animate.hideEffect = SE_NONE;
5153
 
298 andreas 5154
    bool ret = startAnimation(obj, obj->animate, false);
43 andreas 5155
 
298 andreas 5156
    if (obj->animate.hideEffect == SE_NONE || !ret || !mLastObject)
42 andreas 5157
    {
297 andreas 5158
        obj->invalid = true;
5159
        obj->remove = false;
296 andreas 5160
 
5161
        if (obj->object.widget)
335 andreas 5162
        {
297 andreas 5163
            obj->object.widget->hide();
335 andreas 5164
#if TESTMODE == 1
5165
            __success = true;
5166
#endif
5167
        }
42 andreas 5168
    }
348 andreas 5169
#if TESTMODE == 1
5170
    setScreenDone();
5171
#endif
11 andreas 5172
}
5173
 
98 andreas 5174
void MainWindow::dropButton(ulong handle)
5175
{
343 andreas 5176
//    TLOCKER(draw_mutex);
98 andreas 5177
    DECL_TRACER("MainWindow::dropButton(ulong handle)");
5178
 
294 andreas 5179
    OBJECT_t *obj = findObject(handle);
98 andreas 5180
 
5181
    if (!obj)
5182
    {
271 andreas 5183
        MSG_WARNING("Object " << handleToString(handle) << " does not exist. Ignoring!");
98 andreas 5184
        return;
5185
    }
5186
 
294 andreas 5187
    if (obj->type == OBJ_PAGE || obj->type == OBJ_SUBPAGE)
217 andreas 5188
        return;
5189
 
296 andreas 5190
    invalidateObject(handle);
98 andreas 5191
}
252 andreas 5192
 
197 andreas 5193
void MainWindow::setSizeMainWindow(int width, int height)
5194
{
252 andreas 5195
#if !defined (Q_OS_ANDROID) && !defined(Q_OS_IOS)
197 andreas 5196
    DECL_TRACER("MainWindow::setSizeMainWindow(int width, int height)");
5197
 
198 andreas 5198
    QRect geo = geometry();
5199
    setGeometry(geo.x(), geo.y(), width, height + menuBar()->height());
252 andreas 5200
#else
5201
    Q_UNUSED(width);
5202
    Q_UNUSED(height);
5203
#endif
197 andreas 5204
}
252 andreas 5205
 
21 andreas 5206
void MainWindow::playVideo(ulong handle, ulong parent, int left, int top, int width, int height, const string& url, const string& user, const string& pw)
5207
{
343 andreas 5208
//    TLOCKER(draw_mutex);
21 andreas 5209
    DECL_TRACER("MainWindow::playVideo(ulong handle, const string& url, const string& user, const string& pw))");
5210
 
277 andreas 5211
    TObject::OBJECT_t *obj = findObject(handle);
5212
    TObject::OBJECT_t *par = findObject(parent);
271 andreas 5213
    MSG_TRACE("Processing button " << handleToString(handle) << " from parent " << handleToString(parent));
107 andreas 5214
 
21 andreas 5215
    if (!par)
5216
    {
5217
        MSG_WARNING("Button has no parent! Ignoring it.");
5218
        return;
5219
    }
5220
 
5221
    if (!obj)
5222
    {
5223
        MSG_DEBUG("Adding new video object ...");
296 andreas 5224
        OBJECT_t nobj;
21 andreas 5225
 
296 andreas 5226
        nobj.type = TObject::OBJ_VIDEO;
5227
        nobj.handle = handle;
21 andreas 5228
 
198 andreas 5229
        if (gPageManager && gPageManager->isSetupActive())
5230
        {
296 andreas 5231
            nobj.width = scaleSetup(width);
5232
            nobj.height = scaleSetup(height);
5233
            nobj.left = scaleSetup(left);
5234
            nobj.top = scaleSetup(top);
198 andreas 5235
        }
5236
        else
5237
        {
296 andreas 5238
            nobj.width = scale(width);
5239
            nobj.height = scale(height);
5240
            nobj.left = scale(left);
5241
            nobj.top = scale(top);
198 andreas 5242
        }
5243
 
296 andreas 5244
        nobj.object.vwidget = new QVideoWidget(par->object.widget);
5245
        nobj.object.vwidget->installEventFilter(this);
5246
 
5247
        if (!addObject(nobj))
5248
        {
5249
            MSG_ERROR("Error creating a video object!");
5250
            return;
5251
        }
5252
 
5253
        obj = findObject(handle);
21 andreas 5254
    }
5255
    else
277 andreas 5256
        MSG_DEBUG("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " found!");
21 andreas 5257
 
264 andreas 5258
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
21 andreas 5259
    QMediaPlaylist *playlist = new QMediaPlaylist;
181 andreas 5260
#endif
21 andreas 5261
    QUrl qurl(url.c_str());
5262
 
5263
    if (!user.empty())
5264
        qurl.setUserName(user.c_str());
5265
 
5266
    if (!pw.empty())
5267
        qurl.setPassword(pw.c_str());
5268
 
264 andreas 5269
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
21 andreas 5270
    playlist->addMedia(qurl);
181 andreas 5271
#endif
21 andreas 5272
    obj->player = new QMediaPlayer;
264 andreas 5273
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
21 andreas 5274
    obj->player->setPlaylist(playlist);
181 andreas 5275
#else
5276
    obj->player->setSource(qurl);
5277
#endif
21 andreas 5278
    obj->player->setVideoOutput(obj->object.vwidget);
31 andreas 5279
 
107 andreas 5280
    obj->object.vwidget->show();
5281
    obj->player->play();
21 andreas 5282
}
5283
 
291 andreas 5284
void MainWindow::inputText(Button::TButton *button, QByteArray buf, int width, int height, int frame, size_t pixline)
50 andreas 5285
{
279 andreas 5286
    DECL_TRACER("MainWindow::inputText(Button::TButton& button, QByteArray buf, int width, int height, int frame, size_t pixline)");
50 andreas 5287
 
310 andreas 5288
    if (!button)
5289
    {
5290
        MSG_WARNING("Method was called with no button!");
5291
        return;
5292
    }
5293
 
343 andreas 5294
//    TLOCKER(draw_mutex);
291 andreas 5295
    ulong handle = button->getHandle();
5296
    ulong parent = button->getParent();
277 andreas 5297
    TObject::OBJECT_t *obj = findObject(handle);
5298
    TObject::OBJECT_t *par = findObject(parent);
271 andreas 5299
    MSG_TRACE("Processing button " << handleToString(handle) << " from parent " << handleToString(parent) << " with frame width " << frame);
50 andreas 5300
 
5301
    if (!par)
5302
    {
5303
        MSG_WARNING("Button has no parent! Ignoring it.");
5304
        return;
5305
    }
5306
 
310 andreas 5307
    int instance = button->getActiveInstance();
5308
    MSG_DEBUG("Instance: " << instance);
5309
 
50 andreas 5310
    if (!obj)
5311
    {
5312
        MSG_DEBUG("Adding new input object ...");
296 andreas 5313
        OBJECT_t nobj;
50 andreas 5314
 
296 andreas 5315
        nobj.type = TObject::OBJ_INPUT;
5316
        nobj.handle = handle;
50 andreas 5317
 
198 andreas 5318
        if (gPageManager && gPageManager->isSetupActive())
5319
        {
296 andreas 5320
            nobj.width = scaleSetup(width);
5321
            nobj.height = scaleSetup(height);
5322
            nobj.left = scaleSetup(button->getLeftPosition());
5323
            nobj.top = scaleSetup(button->getTopPosition());
198 andreas 5324
        }
5325
        else
5326
        {
296 andreas 5327
            nobj.width = scale(width);
5328
            nobj.height = scale(height);
5329
            nobj.left = scale(button->getLeftPosition());
5330
            nobj.top = scale(button->getTopPosition());
198 andreas 5331
        }
5332
 
310 andreas 5333
        string text = button->getText(instance);
291 andreas 5334
        string mask = button->getInputMask();
191 andreas 5335
 
296 andreas 5336
        nobj.object.plaintext = new TQEditLine(text, par->object.widget, button->isMultiLine());
5337
        nobj.object.plaintext->setObjectName(string("EditLine_") + handleToString(handle));
5338
        nobj.object.plaintext->setHandle(handle);
5339
        nobj.object.plaintext->move(nobj.left, nobj.top);
5340
        nobj.object.plaintext->setFixedSize(nobj.width, nobj.height);
5341
        nobj.object.plaintext->setPadding(frame, frame, frame, frame);
5342
        nobj.object.plaintext->setWordWrapMode(button->getTextWordWrap());
5343
        nobj.object.plaintext->setPasswordChar(button->getPasswordChar());
5344
        nobj.wid = nobj.object.plaintext->winId();
192 andreas 5345
 
213 andreas 5346
        if (gPageManager->isSetupActive())
5347
        {
5348
            int ch = 0;
5349
 
291 andreas 5350
            if (button->getAddressPort() == 0 && button->getAddressChannel() > 0)
5351
                ch = button->getAddressChannel();
5352
            else if (button->getChannelPort() == 0 && button->getChannelNumber() > 0)
5353
                ch = button->getChannelNumber();
213 andreas 5354
 
5355
            switch(ch)
5356
            {
5357
                case SYSTEM_ITEM_SIPPORT:
5358
                case SYSTEM_ITEM_NETLINX_PORT:
296 andreas 5359
                    nobj.object.plaintext->setInputMask("000000");
5360
                    nobj.object.plaintext->setNumericInput();
213 andreas 5361
                break;
5362
 
5363
                case SYSTEM_ITEM_NETLINX_CHANNEL:
296 andreas 5364
                    nobj.object.plaintext->setInputMask("99999");
5365
                    nobj.object.plaintext->setNumericInput();
213 andreas 5366
                break;
5367
            }
5368
        }
224 andreas 5369
        else if (!mask.empty())
296 andreas 5370
            nobj.object.plaintext->setInputMask(convertMask(mask));
213 andreas 5371
 
52 andreas 5372
        if (!buf.size() || pixline == 0)
51 andreas 5373
        {
5374
            MSG_ERROR("No image!");
5375
            TError::setError();
5376
            return;
5377
        }
5378
 
52 andreas 5379
        MSG_DEBUG("Background image size: " << width << " x " << height << ", rowBytes: " << pixline);
5380
        QPixmap pix(width, height);
5381
        QImage img((uchar *)buf.data(), width, height, QImage::Format_ARGB32);
50 andreas 5382
 
198 andreas 5383
        if (gPageManager && gPageManager->isSetupActive())
5384
            pix.convertFromImage(img.scaled(scaleSetup(width), scaleSetup(height), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
5385
        else if (isScaled())
52 andreas 5386
            pix.convertFromImage(img.scaled(scale(width), scale(height), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
50 andreas 5387
        else
5388
            pix.convertFromImage(img);
5389
 
5390
        // Load the font
291 andreas 5391
        FONT_T font = button->getFont();
51 andreas 5392
        vector<string> fontList = TFont::getFontPathList();
5393
        vector<string>::iterator iter;
5394
        string ffile;
50 andreas 5395
 
51 andreas 5396
        for (iter = fontList.begin(); iter != fontList.end(); ++iter)
50 andreas 5397
        {
51 andreas 5398
            TValidateFile vf;
50 andreas 5399
 
51 andreas 5400
            if (!vf.isValidFile(*iter + "/" + font.file))
5401
                continue;
5402
 
5403
            ffile = *iter + "/" + font.file;
5404
            break;
50 andreas 5405
        }
5406
 
51 andreas 5407
        if (ffile.empty())
5408
        {
5409
            MSG_ERROR("Font " << font.file << " doesn't exists!");
5410
            return;
5411
        }
5412
 
213 andreas 5413
        if (QFontDatabase::addApplicationFont(ffile.c_str()) == -1)
50 andreas 5414
        {
5415
            MSG_ERROR("Font " << ffile << " could not be loaded!");
5416
            TError::setError();
5417
            return;
5418
        }
5419
 
5420
        QFont ft;
5421
        ft.setFamily(font.name.c_str());
198 andreas 5422
 
5423
        if (gPageManager && gPageManager->isSetupActive())
303 andreas 5424
        {
398 andreas 5425
            int eighty = static_cast<int>(static_cast<double>(button->getHeight()) / 100.0 * 85.0);
213 andreas 5426
            ft.setPixelSize(scaleSetup(eighty - frame * 2));
303 andreas 5427
        }
198 andreas 5428
        else
303 andreas 5429
            ft.setPixelSize(scale(font.size));
198 andreas 5430
 
213 andreas 5431
        MSG_DEBUG("Using font \"" << font.name << "\" with size " << font.size << "px.");
50 andreas 5432
 
291 andreas 5433
        switch (button->getFontStyle())
50 andreas 5434
        {
5435
            case FONT_BOLD:     ft.setBold(true); break;
5436
            case FONT_ITALIC:   ft.setItalic(true); break;
5437
            case FONT_BOLD_ITALIC:
5438
                ft.setBold(true);
5439
                ft.setItalic(true);
5440
                break;
5441
 
5442
            default:
5443
                ft.setBold(false);
5444
                ft.setItalic(false);
5445
        }
5446
 
303 andreas 5447
        QPalette palette(this->palette());
310 andreas 5448
        TColor::COLOR_T textColor = TColor::getAMXColor(button->getTextColor(instance));
5449
        TColor::COLOR_T fillColor = TColor::getAMXColor(button->getFillColor(instance));
51 andreas 5450
        QColor txcolor(QColor::fromRgba(qRgba(textColor.red, textColor.green, textColor.blue, textColor.alpha)));
52 andreas 5451
        QColor cfcolor(QColor::fromRgba(qRgba(fillColor.red, fillColor.green, fillColor.blue, fillColor.alpha)));
303 andreas 5452
        palette.setColor(QPalette::Window, cfcolor);
52 andreas 5453
        palette.setColor(QPalette::Base, cfcolor);
51 andreas 5454
        palette.setColor(QPalette::Text, txcolor);
303 andreas 5455
        palette.setBrush(QPalette::Window, QBrush(pix));
188 andreas 5456
 
296 andreas 5457
        nobj.object.plaintext->setFont(ft);
5458
        nobj.object.plaintext->setPalette(palette);
310 andreas 5459
        nobj.object.plaintext->setTextColor(txcolor);
296 andreas 5460
 
5461
        if (!addObject(nobj))
5462
        {
5463
            MSG_ERROR("Error creating an input object!");
5464
            return;
5465
        }
303 andreas 5466
 
5467
        connect(nobj.object.plaintext, &TQEditLine::inputChanged, this, &MainWindow::onInputChanged);
309 andreas 5468
        connect(nobj.object.plaintext, &TQEditLine::cursorPositionChanged, this, &MainWindow::onCursorChanged);
5469
        connect(nobj.object.plaintext, &TQEditLine::focusChanged, this, &MainWindow::onFocusChanged);
50 andreas 5470
    }
5471
    else
206 andreas 5472
    {
277 andreas 5473
        MSG_DEBUG("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " found!");
206 andreas 5474
 
310 andreas 5475
        string text = button->getText(instance);
291 andreas 5476
        string mask = button->getInputMask();
206 andreas 5477
        obj->object.plaintext->setText(text);
224 andreas 5478
 
5479
        if (!mask.empty())
5480
            obj->object.plaintext->setInputMask(convertMask(mask));
5481
 
310 andreas 5482
        QPixmap pix(obj->width, obj->height);
5483
        QImage img((uchar *)buf.data(), width, height, QImage::Format_ARGB32);
5484
 
5485
        if (isScaled())
5486
            pix.convertFromImage(img.scaled(obj->width, obj->height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
5487
        else
5488
            pix.convertFromImage(img);
5489
 
5490
        QPalette palette(this->palette());
5491
        TColor::COLOR_T textColor = TColor::getAMXColor(button->getTextColor(instance));
5492
        TColor::COLOR_T fillColor = TColor::getAMXColor(button->getFillColor(instance));
5493
        QColor txcolor(QColor::fromRgba(qRgba(textColor.red, textColor.green, textColor.blue, textColor.alpha)));
5494
        QColor cfcolor(QColor::fromRgba(qRgba(fillColor.red, fillColor.green, fillColor.blue, fillColor.alpha)));
5495
        palette.setColor(QPalette::Window, cfcolor);
5496
        palette.setColor(QPalette::Base, cfcolor);
5497
        palette.setColor(QPalette::Text, txcolor);
5498
        palette.setBrush(QPalette::Window, QBrush(pix));
5499
 
5500
        obj->object.plaintext->setPalette(palette);
5501
        obj->object.plaintext->setTextColor(txcolor);
206 andreas 5502
    }
50 andreas 5503
}
62 andreas 5504
 
291 andreas 5505
void MainWindow::listBox(Button::TButton *button, QByteArray buffer, int width, int height, int frame, size_t pixline)
200 andreas 5506
{
279 andreas 5507
    DECL_TRACER("MainWindow::listBox(Button::TButton& button, QByteArray buffer, int width, int height, int frame, size_t pixline)");
200 andreas 5508
 
291 andreas 5509
    ulong handle = button->getHandle();
5510
    ulong parent = button->getParent();
277 andreas 5511
    TObject::OBJECT_t *obj = findObject(handle);
5512
    TObject::OBJECT_t *par = findObject(parent);
271 andreas 5513
    MSG_TRACE("Processing list " << handleToString(handle) << " from parent " << handleToString(parent) << " with frame width " << frame);
200 andreas 5514
 
5515
    if (!par)
5516
    {
5517
        MSG_WARNING("List has no parent! Ignoring it.");
5518
        return;
5519
    }
5520
 
5521
    if (!obj)
5522
    {
5523
        MSG_DEBUG("Adding new list object ...");
296 andreas 5524
        OBJECT_t nobj;
200 andreas 5525
 
296 andreas 5526
        nobj.type = TObject::OBJ_LIST;
5527
        nobj.handle = handle;
5528
        nobj.rows = button->getListNumRows();
5529
        nobj.cols = button->getListNumCols();
200 andreas 5530
 
5531
        if (gPageManager && gPageManager->isSetupActive())
5532
        {
296 andreas 5533
            nobj.width = scaleSetup(width);
5534
            nobj.height = scaleSetup(height);
5535
            nobj.left = scaleSetup(button->getLeftPosition());
5536
            nobj.top = scaleSetup(button->getTopPosition());
200 andreas 5537
        }
5538
        else
5539
        {
296 andreas 5540
            nobj.width = scale(width);
5541
            nobj.height = scale(height);
5542
            nobj.left = scale(button->getLeftPosition());
5543
            nobj.top = scale(button->getTopPosition());
200 andreas 5544
        }
5545
 
291 andreas 5546
        vector<string> listContent = button->getListContent();
200 andreas 5547
 
217 andreas 5548
        if (par->type == TObject::OBJ_PAGE)
296 andreas 5549
            nobj.object.list = new QListWidget(par->object.widget ? par->object.widget : centralWidget());
217 andreas 5550
        else
296 andreas 5551
            nobj.object.list = new QListWidget(par->object.widget);
200 andreas 5552
 
296 andreas 5553
        nobj.object.list->move(nobj.left, nobj.top);
5554
        nobj.object.list->setFixedSize(nobj.width, nobj.height);
5555
        connect(nobj.object.list, &QListWidget::currentItemChanged, this, &MainWindow::onTListCallbackCurrentItemChanged);
200 andreas 5556
 
5557
        if (!buffer.size() || pixline == 0)
5558
        {
5559
            MSG_ERROR("No image!");
5560
            TError::setError();
5561
            return;
5562
        }
5563
 
5564
        MSG_DEBUG("Background image size: " << width << " x " << height << ", rowBytes: " << pixline);
5565
        QPixmap pix(width, height);
5566
        QImage img((uchar *)buffer.data(), width, height, QImage::Format_ARGB32);
5567
 
5568
        if (gPageManager && gPageManager->isSetupActive())
5569
            pix.convertFromImage(img.scaled(scaleSetup(width), scaleSetup(height), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
5570
        else if (isScaled())
5571
            pix.convertFromImage(img.scaled(scale(width), scale(height), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
5572
        else
5573
            pix.convertFromImage(img);
5574
 
5575
        // Load the font
291 andreas 5576
        FONT_T font = button->getFont();
200 andreas 5577
        vector<string> fontList = TFont::getFontPathList();
5578
        vector<string>::iterator iter;
5579
        string ffile;
5580
 
5581
        for (iter = fontList.begin(); iter != fontList.end(); ++iter)
5582
        {
5583
            TValidateFile vf;
5584
 
5585
            if (!vf.isValidFile(*iter + "/" + font.file))
5586
                continue;
5587
 
5588
            ffile = *iter + "/" + font.file;
5589
            break;
5590
        }
5591
 
5592
        if (ffile.empty())
5593
        {
5594
            MSG_ERROR("Font " << font.file << " doesn't exists!");
5595
            return;
5596
        }
5597
 
213 andreas 5598
        if (QFontDatabase::addApplicationFont(ffile.c_str()) == -1)
200 andreas 5599
        {
5600
            MSG_ERROR("Font " << ffile << " could not be loaded!");
5601
            TError::setError();
5602
            return;
5603
        }
5604
 
5605
        QFont ft;
5606
        ft.setFamily(font.name.c_str());
5607
 
213 andreas 5608
        if (gPageManager && gPageManager->isSetupActive())
5609
            ft.setPointSize(scaleSetup(font.size));
5610
        else
200 andreas 5611
            ft.setPointSize(font.size);
5612
 
5613
        MSG_DEBUG("Using font \"" << font.name << "\" with size " << font.size << "pt.");
5614
 
291 andreas 5615
        switch (button->getFontStyle())
200 andreas 5616
        {
5617
            case FONT_BOLD:     ft.setBold(true); break;
5618
            case FONT_ITALIC:   ft.setItalic(true); break;
5619
            case FONT_BOLD_ITALIC:
5620
                ft.setBold(true);
5621
                ft.setItalic(true);
5622
            break;
5623
 
5624
            default:
5625
                ft.setBold(false);
5626
                ft.setItalic(false);
5627
        }
5628
 
5629
        QPalette palette;
291 andreas 5630
        TColor::COLOR_T textColor = TColor::getAMXColor(button->getTextColor());
5631
        TColor::COLOR_T fillColor = TColor::getAMXColor(button->getFillColor());
200 andreas 5632
        QColor txcolor(QColor::fromRgba(qRgba(textColor.red, textColor.green, textColor.blue, textColor.alpha)));
5633
        QColor cfcolor(QColor::fromRgba(qRgba(fillColor.red, fillColor.green, fillColor.blue, fillColor.alpha)));
5634
        palette.setColor(QPalette::Base, cfcolor);
5635
        palette.setColor(QPalette::Text, txcolor);
217 andreas 5636
//        pix.save("frame.png");
200 andreas 5637
        palette.setBrush(QPalette::Base, QBrush(pix));
5638
 
296 andreas 5639
        nobj.object.list->setFont(ft);
5640
        nobj.object.list->setPalette(palette);
200 andreas 5641
        // Add content
5642
        if (!listContent.empty())
5643
        {
5644
            vector<string>::iterator iter;
5645
 
296 andreas 5646
            if (nobj.object.list->count() > 0)
5647
                nobj.object.list->clear();
205 andreas 5648
 
5649
            MSG_DEBUG("Adding " << listContent.size() << " entries to list.");
5650
            string selected = gPageManager->getSelectedItem(handle);
5651
            int index = 0;
5652
 
200 andreas 5653
            for (iter = listContent.begin(); iter != listContent.end(); ++iter)
205 andreas 5654
            {
296 andreas 5655
                nobj.object.list->addItem(iter->c_str());
205 andreas 5656
 
5657
                if (selected == *iter)
296 andreas 5658
                    nobj.object.list->setCurrentRow(index);
205 andreas 5659
 
5660
                index++;
5661
            }
200 andreas 5662
        }
205 andreas 5663
        else
5664
            MSG_DEBUG("No items for list!");
200 andreas 5665
 
296 andreas 5666
//        nobj.object.list->show();
5667
 
5668
        if (!addObject(nobj))
5669
        {
5670
            MSG_ERROR("Error creating a list object!");
5671
            return;
5672
        }
200 andreas 5673
    }
5674
    else
297 andreas 5675
    {
277 andreas 5676
        MSG_DEBUG("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " found!");
297 andreas 5677
        enableObject(handle);
5678
    }
200 andreas 5679
}
5680
 
63 andreas 5681
void MainWindow::showKeyboard(const std::string& init, const std::string& prompt, bool priv)
31 andreas 5682
{
63 andreas 5683
    DECL_TRACER("MainWindow::showKeyboard(std::string &init, std::string &prompt, bool priv)");
31 andreas 5684
 
63 andreas 5685
    if (mKeyboard)
5686
        return;
5687
 
5688
    mQKeyboard = new TQKeyboard(init, prompt, this);
5689
    mKeyboard = true;
62 andreas 5690
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
65 andreas 5691
    mQKeyboard->setScaleFactor(mScaleFactor);
62 andreas 5692
#endif
63 andreas 5693
    mQKeyboard->setPrivate(priv);
5694
    mQKeyboard->doResize();
5695
    mQKeyboard->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::FramelessWindowHint);
5696
    int ret = mQKeyboard->exec();
120 andreas 5697
    string text = "KEYB-";
31 andreas 5698
 
62 andreas 5699
    if (ret == QDialog::Accepted)
63 andreas 5700
        text.append(mQKeyboard->getText());
62 andreas 5701
    else
120 andreas 5702
        text = "KEYB-ABORT";
62 andreas 5703
 
120 andreas 5704
    if (gPageManager)
5705
        gPageManager->sendKeyboard(text);
62 andreas 5706
 
63 andreas 5707
    delete mQKeyboard;
5708
    mQKeyboard = nullptr;
5709
    mKeyboard = false;
31 andreas 5710
}
62 andreas 5711
 
63 andreas 5712
void MainWindow::showKeypad(const std::string& init, const std::string& prompt, bool priv)
62 andreas 5713
{
63 andreas 5714
    DECL_TRACER("MainWindow::showKeypad(std::string& init, std::string& prompt, bool priv)");
62 andreas 5715
 
65 andreas 5716
    if (mKeypad)
63 andreas 5717
        return;
5718
 
5719
    mQKeypad = new TQKeypad(init, prompt, this);
65 andreas 5720
    mKeypad = true;
62 andreas 5721
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
63 andreas 5722
    mQKeypad->setScaleFactor(mScaleFactor);
65 andreas 5723
#endif
5724
    mQKeypad->setPrivate(priv);
111 andreas 5725
    mQKeypad->setMaxLength(50);     // Standard maximum length
63 andreas 5726
    mQKeypad->doResize();
5727
    mQKeypad->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::FramelessWindowHint);
65 andreas 5728
    int ret = mQKeypad->exec();
62 andreas 5729
 
5730
    if (ret == QDialog::Accepted)
5731
    {
5732
        string text = "KEYP-";
63 andreas 5733
        text.append(mQKeypad->getText());
62 andreas 5734
 
5735
        if (gPageManager)
5736
            gPageManager->sendKeypad(text);
5737
    }
5738
    else
5739
    {
5740
        string text = "KEYP-ABORT";
5741
 
5742
        if (gPageManager)
5743
            gPageManager->sendKeypad(text);
5744
    }
5745
 
63 andreas 5746
    delete mQKeypad;
5747
    mQKeypad = nullptr;
65 andreas 5748
    mKeypad = false;
62 andreas 5749
}
5750
 
63 andreas 5751
void MainWindow::resetKeyboard()
5752
{
5753
    DECL_TRACER("MainWindow::resetKeyboard()");
5754
 
5755
    if (mQKeyboard)
5756
        mQKeyboard->reject();
5757
 
5758
    if (mQKeypad)
211 andreas 5759
        mQKeypad->reject();
63 andreas 5760
}
5761
 
111 andreas 5762
void MainWindow::sendVirtualKeys(const string& str)
5763
{
5764
    DECL_TRACER("MainWindow::sendVirtualKeys(const string& str)");
5765
 
5766
    if (mKeyboard && mQKeyboard)
5767
        mQKeyboard->setString(str);
5768
    else if (mKeypad && mQKeypad)
5769
        mQKeypad->setString(str);
5770
}
5771
 
64 andreas 5772
void MainWindow::showSetup()
5773
{
5774
    DECL_TRACER("MainWindow::showSetup()");
251 andreas 5775
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
211 andreas 5776
    settings();
5777
#else
250 andreas 5778
#ifndef Q_OS_IOS
197 andreas 5779
    if (gPageManager)
5780
        gPageManager->showSetup();
250 andreas 5781
#else
259 andreas 5782
    mIOSSettingsActive = true;
250 andreas 5783
    QASettings::openSettings();
5784
#endif  // Q_OS_IOS
251 andreas 5785
#endif  // !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
64 andreas 5786
}
5787
 
71 andreas 5788
void MainWindow::playSound(const string& file)
5789
{
5790
    DECL_TRACER("MainWindow::playSound(const string& file)");
5791
 
5792
    MSG_DEBUG("Playing file " << file);
141 andreas 5793
 
5794
    if (TConfig::getMuteState())
326 andreas 5795
    {
5796
#if TESTMODE == 1
5797
        __success = true;
334 andreas 5798
        setAllDone();
326 andreas 5799
#endif
141 andreas 5800
        return;
326 andreas 5801
    }
141 andreas 5802
 
5803
    if (!mMediaPlayer)
181 andreas 5804
    {
141 andreas 5805
        mMediaPlayer = new QMediaPlayer;
264 andreas 5806
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
181 andreas 5807
        mAudioOutput = new QAudioOutput;
335 andreas 5808
        mMediaPlayer->setAudioOutput(mAudioOutput);
181 andreas 5809
#endif
367 andreas 5810
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
5811
        connect(mMediaPlayer, &QMediaPlayer::playingChanged, this, &MainWindow::onPlayingChanged);
5812
#endif
5813
        connect(mMediaPlayer, &QMediaPlayer::mediaStatusChanged, this, &MainWindow::onMediaStatusChanged);
5814
        connect(mMediaPlayer, &QMediaPlayer::errorOccurred, this, &MainWindow::onPlayerError);
181 andreas 5815
    }
141 andreas 5816
 
264 andreas 5817
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
141 andreas 5818
    mMediaPlayer->setMedia(QUrl::fromLocalFile(file.c_str()));
5819
    mMediaPlayer->setVolume(calcVolume(TConfig::getSystemVolume()));
335 andreas 5820
 
342 andreas 5821
    if (mMediaPlayer->state() != QMediaPlayer::StoppedState)
335 andreas 5822
        mMediaPlayer->stop();
346 andreas 5823
#else   // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
181 andreas 5824
    mMediaPlayer->setSource(QUrl::fromLocalFile(file.c_str()));
398 andreas 5825
    mAudioOutput->setVolume(static_cast<float>(calcVolume(TConfig::getSystemVolume())));
335 andreas 5826
 
5827
    if (!mMediaPlayer->isAvailable())
5828
    {
5829
        MSG_WARNING("No audio modul found!");
5830
#if TESTMODE == 1
5831
        setAllDone();
181 andreas 5832
#endif
335 andreas 5833
        return;
5834
    }
5835
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
5836
    if (mMediaPlayer->isPlaying())
367 andreas 5837
        mMediaPlayer->setPosition(0);
5838
//        mMediaPlayer->stop();
335 andreas 5839
#else
5840
    if (mMediaPlayer->playbackState() != QMediaPlayer::StoppedState)
5841
        mMediaPlayer->stop();
367 andreas 5842
 
5843
    mMediaPlayer->setPosition(0);
335 andreas 5844
#endif  // #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
367 andreas 5845
 
335 andreas 5846
#endif  // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
141 andreas 5847
    mMediaPlayer->play();
326 andreas 5848
#if TESTMODE == 1
401 andreas 5849
    if (mMediaPlayer->error() != QMediaPlayer::NoError)
335 andreas 5850
    {
5851
        MSG_ERROR("Error playing \"" << file << "\": " << mMediaPlayer->errorString().toStdString());
5852
    }
5853
    else
5854
        __success = true;
5855
 
334 andreas 5856
    setAllDone();
326 andreas 5857
#endif
71 andreas 5858
}
5859
 
141 andreas 5860
void MainWindow::stopSound()
5861
{
5862
    DECL_TRACER("MainWindow::stopSound()");
5863
 
5864
    if (mMediaPlayer)
5865
        mMediaPlayer->stop();
5866
}
5867
 
5868
void MainWindow::muteSound(bool state)
5869
{
5870
    DECL_TRACER("MainWindow::muteSound(bool state)");
5871
 
264 andreas 5872
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
141 andreas 5873
    if (mMediaPlayer)
5874
        mMediaPlayer->setMuted(state);
181 andreas 5875
#else
5876
    if (mAudioOutput)
5877
        mAudioOutput->setMuted(state);
5878
#endif
335 andreas 5879
#if TESTMODE == 1
5880
    __success = true;
5881
    setAllDone();
5882
#endif
141 andreas 5883
}
5884
 
335 andreas 5885
void MainWindow::setVolume(int volume)
5886
{
5887
    DECL_TRACER("MainWindow::setVolume(int volume)");
5888
 
5889
    if (!mMediaPlayer)
5890
    {
5891
#if TESTMODE == 1
5892
        setAllDone();
5893
#endif
5894
        return;
5895
    }
5896
 
5897
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
5898
    mMediaPlayer->setVolume(calcVolume(volume));
366 andreas 5899
#else   // QT_VERSION
335 andreas 5900
    if (!mMediaPlayer || !mAudioOutput)
5901
    {
5902
#if TESTMODE == 1
5903
        setAllDone();
366 andreas 5904
#endif  // TESTMODE
335 andreas 5905
        return;
5906
    }
5907
 
398 andreas 5908
    mAudioOutput->setVolume(static_cast<float>(calcVolume(volume)));
335 andreas 5909
#if TESTMODE == 1
5910
    __success = true;
5911
    setAllDone();
366 andreas 5912
#endif  // TESTMODE
335 andreas 5913
#endif  // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
5914
}
5915
 
367 andreas 5916
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
5917
void MainWindow::onPlayingChanged(bool playing)
5918
{
5919
    DECL_TRACER("MainWindow::onPlayingChanged(bool playing)");
5920
 
5921
    // If playing stopped for whatever reason, we rewind the track
5922
    if (!playing && mMediaPlayer)
5923
    {
5924
        mMediaPlayer->setPosition(0);
5925
        MSG_DEBUG("Track was rewound.");
5926
    }
5927
}
5928
#endif
5929
 
5930
void MainWindow::onMediaStatusChanged(QMediaPlayer::MediaStatus status)
5931
{
5932
    DECL_TRACER("MainWindow::onMediaStatusChanged(QMediaPlayer::MediaStatus status)");
5933
 
5934
    switch(status)
5935
    {
5936
        case QMediaPlayer::NoMedia:         MSG_WARNING("The is no current media."); break;
5937
        case QMediaPlayer::LoadingMedia:    MSG_INFO("The current media is being loaded."); break;
5938
        case QMediaPlayer::LoadedMedia:     MSG_INFO("The current media has been loaded."); break;
5939
        case QMediaPlayer::StalledMedia:    MSG_WARNING("Playback of the current media has stalled due to insufficient buffering or some other temporary interruption."); break;
5940
        case QMediaPlayer::BufferingMedia:  MSG_INFO("The player is buffering data but has enough data buffered for playback to continue for the immediate future."); break;
5941
        case QMediaPlayer::BufferedMedia:   MSG_INFO("The player has fully buffered the current media."); break;
5942
        case QMediaPlayer::EndOfMedia:      MSG_INFO("Playback has reached the end of the current media."); break;
5943
        case QMediaPlayer::InvalidMedia:    MSG_WARNING("The current media cannot be played.");
5944
    }
5945
}
5946
 
5947
void MainWindow::onPlayerError(QMediaPlayer::Error error, const QString &errorString)
5948
{
5949
    DECL_TRACER("MainWindow::onPlayerError(QMediaPlayer::Error error, const QString &errorString)");
5950
 
5951
    if (error == QMediaPlayer::NoError)
5952
        return;
5953
 
5954
    MSG_ERROR("Media player error (" << error << "): " << errorString.toStdString());
5955
}
386 andreas 5956
/*
31 andreas 5957
void MainWindow::playShowList()
5958
{
5959
    DECL_TRACER("MainWindow::playShowList()");
5960
 
61 andreas 5961
    _EMIT_TYPE_t etype = getNextType();
5962
 
5963
    while (etype != ET_NONE)
5964
    {
5965
        ulong handle = 0;
5966
        ulong parent = 0;
5967
        int left = 0;
5968
        int top = 0;
5969
        int width = 0;
5970
        int height = 0;
192 andreas 5971
        int frame = 0;
289 andreas 5972
        TBitmap image;
61 andreas 5973
        ulong color = 0;
289 andreas 5974
        int space{0};
5975
        bool vertical = false;
5976
        TColor::COLOR_T fillColor;
298 andreas 5977
        bool pth = false;
262 andreas 5978
#ifndef _OPAQUE_SKIA_
5979
        int opacity = 255;
5980
#endif
61 andreas 5981
        ANIMATION_t animate;
5982
        std::string url;
5983
        std::string user;
5984
        std::string pw;
5985
        Button::TButton *button;
5986
        Button::BITMAP_t bm;
5987
 
5988
        switch(etype)
5989
        {
5990
            case ET_BACKGROUND:
262 andreas 5991
#ifdef _OPAQUE_SKIA_
289 andreas 5992
                if (getBackground(&handle, &image, &width, &height, &color))
262 andreas 5993
#else
289 andreas 5994
                if (getBackground(&handle, &image, &width, &height, &color, &opacity))
262 andreas 5995
#endif
61 andreas 5996
                {
271 andreas 5997
                    MSG_PROTOCOL("Replay: BACKGROUND of object " << handleToString(handle));
262 andreas 5998
#ifdef _OPAQUE_SKIA_
289 andreas 5999
                    emit sigSetBackground(handle, image, width, height, color);
262 andreas 6000
#else
289 andreas 6001
                    emit sigSetBackground(handle, image, width, height, color, opacity);
262 andreas 6002
#endif
61 andreas 6003
                }
6004
            break;
6005
 
6006
            case ET_BUTTON:
298 andreas 6007
                if (getButton(&handle, &parent, &image, &left, &top, &width, &height, &pth))
61 andreas 6008
                {
271 andreas 6009
                    MSG_PROTOCOL("Replay: BUTTON object " << handleToString(handle));
298 andreas 6010
                    emit sigDisplayButton(handle, parent, image, width, height, left, top, pth);
61 andreas 6011
                }
6012
            break;
6013
 
6014
            case ET_INTEXT:
192 andreas 6015
                if (getInText(&handle, &button, &bm, &frame))
61 andreas 6016
                {
6017
                    QByteArray buf;
6018
 
6019
                    if (bm.buffer && bm.rowBytes > 0)
6020
                    {
363 andreas 6021
                        size_t s = (size_t)bm.width * (size_t)bm.height * (size_t)(bm.rowBytes / bm.width);
286 andreas 6022
                        buf.insert(0, (const char *)bm.buffer, s);
61 andreas 6023
                    }
6024
 
271 andreas 6025
                    MSG_PROTOCOL("Replay: INTEXT object " << handleToString(handle));
386 andreas 6026
                    emit sigInputText(button, buf, bm.width, bm.height, (int)bm.rowBytes, frame);
61 andreas 6027
                }
6028
            break;
6029
 
6030
            case ET_PAGE:
6031
                if (getPage(&handle, &width, &height))
6032
                {
271 andreas 6033
                    MSG_PROTOCOL("Replay: PAGE object " << handleToString(handle));
217 andreas 6034
 
61 andreas 6035
                    if (isDeleted())
6036
                        emit sigDropPage(handle);
6037
                    else
6038
                        emit sigSetPage(handle, width, height);
6039
                }
6040
            break;
6041
 
6042
            case ET_SUBPAGE:
217 andreas 6043
                if (getSubPage(&handle, &parent, &left, &top, &width, &height, &animate))
61 andreas 6044
                {
271 andreas 6045
                    MSG_PROTOCOL("Replay: SUBPAGE object " << handleToString(handle));
217 andreas 6046
 
61 andreas 6047
                    if (isDeleted())
350 andreas 6048
                        emit sigDropSubPage(handle, parent);
61 andreas 6049
                    else
217 andreas 6050
                        emit sigSetSubPage(handle, parent, left, top, width, height, animate);
61 andreas 6051
                }
6052
            break;
6053
 
289 andreas 6054
            case ET_SUBVIEW:
6055
                if (getViewButton(&handle, &parent, &vertical, &image, &left, &top, &width, &height, &space, &fillColor))
6056
                {
6057
                    MSG_PROTOCOL("Replay: SUBVIEW object " << handleToString(handle));
6058
                    emit sigDisplayViewButton(handle, parent, vertical, image, width, height, left, top, space, fillColor);
6059
                }
6060
            break;
6061
 
61 andreas 6062
            case ET_VIDEO:
6063
                if (getVideo(&handle, &parent, &left, &top, &width, &height, &url, &user, &pw))
6064
                {
271 andreas 6065
                    MSG_PROTOCOL("Replay: VIDEO object " << handleToString(handle));
61 andreas 6066
                    emit sigPlayVideo(handle, parent, left, top, width, height, url, user, pw);
6067
                }
6068
            break;
6069
 
6070
            default:
6071
                MSG_WARNING("Type " << etype << " is currently not supported!");
6072
        }
6073
 
6074
        dropType(etype);
6075
        etype = getNextType();
6076
    }
386 andreas 6077
}
61 andreas 6078
*/
31 andreas 6079
 
38 andreas 6080
int MainWindow::scale(int value)
6081
{
262 andreas 6082
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
6083
    double s = gScale;
6084
#else
6085
    double s = mScaleFactor;
6086
#endif
6087
    if (value <= 0 || s == 1.0 || s < 0.0)
38 andreas 6088
        return value;
6089
 
398 andreas 6090
    return static_cast<int>(static_cast<double>(value) * s);
38 andreas 6091
}
6092
 
198 andreas 6093
int MainWindow::scaleSetup(int value)
6094
{
6095
    DECL_TRACER("MainWindow::scaleSetup(int value)");
6096
 
212 andreas 6097
    if (value <= 0 || mSetupScaleFactor == 1.0 || mSetupScaleFactor <= 0.0)
198 andreas 6098
        return value;
6099
 
398 andreas 6100
    double val = static_cast<double>(static_cast<double>(value) * mSetupScaleFactor);
198 andreas 6101
 
398 andreas 6102
    return static_cast<int>(val);
198 andreas 6103
}
6104
 
259 andreas 6105
bool MainWindow::isScaled()
6106
{
275 andreas 6107
    DECL_TRACER("MainWindow::isScaled()");
6108
 
262 andreas 6109
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
6110
    double s = gScale;
6111
#else
6112
    double s = mScaleFactor;
6113
#endif
6114
    if (s > 0.0 && s != 1.0 && gPageManager && TConfig::getScale())
259 andreas 6115
        return true;
6116
 
6117
    return false;
6118
}
6119
 
198 andreas 6120
bool MainWindow::isSetupScaled()
6121
{
6122
    DECL_TRACER("MainWindow::isSetupScaled()");
6123
 
6124
    return (mSetupScaleFactor > 0.0 && mSetupScaleFactor != 1.0);
6125
}
6126
 
298 andreas 6127
bool MainWindow::startAnimation(TObject::OBJECT_t* obj, ANIMATION_t& ani, bool in)
42 andreas 6128
{
6129
    DECL_TRACER("MainWindow::startAnimation(OBJECT_t* obj, ANIMATION_t& ani)");
43 andreas 6130
 
107 andreas 6131
    if (!obj)
6132
    {
6133
        MSG_ERROR("Got no object to start the animation!");
298 andreas 6134
        return false;
107 andreas 6135
    }
6136
 
369 andreas 6137
//    TLOCKER(anim_mutex);
42 andreas 6138
    int scLeft = obj->left;
6139
    int scTop = obj->top;
6140
    int scWidth = obj->width;
6141
    int scHeight = obj->height;
298 andreas 6142
    int duration = (in ? ani.showTime : ani.hideTime);
6143
    SHOWEFFECT_t effect = (in ? ani.showEffect : ani.hideEffect);
42 andreas 6144
    mLastObject = nullptr;
43 andreas 6145
 
298 andreas 6146
    if (effect == SE_NONE || duration <= 0 || (obj->type != OBJ_SUBPAGE && obj->type != OBJ_PAGE))
6147
        return false;
42 andreas 6148
 
298 andreas 6149
    if (!obj->object.widget)
6150
    {
6151
        MSG_WARNING("Object " << handleToString(obj->handle) << " has no widget defined! Ignoring fade effect.");
332 andreas 6152
#if TESTMODE == 1
334 andreas 6153
        setScreenDone();
332 andreas 6154
#endif
298 andreas 6155
        return false;
6156
    }
43 andreas 6157
 
58 andreas 6158
    if (effect == SE_FADE)
6159
    {
271 andreas 6160
        MSG_DEBUG("Fading object " << handleToString(obj->handle) << (in ? " IN" : " OUT"));
58 andreas 6161
        QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect(obj->object.widget);
289 andreas 6162
 
6163
        if (effect)
6164
        {
298 andreas 6165
            obj->object.widget->setGraphicsEffect(effect);
289 andreas 6166
            obj->animation = new QPropertyAnimation(effect, "opacity");
6167
        }
58 andreas 6168
    }
6169
    else
6170
    {
271 andreas 6171
        MSG_DEBUG("Moving object " << handleToString(obj->handle) << (in ? " IN" : " OUT"));
58 andreas 6172
        obj->animation = new QPropertyAnimation(obj->object.widget);
6173
        obj->animation->setTargetObject(obj->object.widget);
6174
    }
42 andreas 6175
 
298 andreas 6176
    obj->animation->setDuration(duration * 100);    // convert 10th of seconds into milliseconds
296 andreas 6177
    MSG_DEBUG("Processing animation effect " << effect << " with a duration of " << obj->animation->duration() << "ms");
43 andreas 6178
 
54 andreas 6179
    switch(effect)
6180
    {
6181
        case SE_SLIDE_BOTTOM_FADE:
6182
        case SE_SLIDE_BOTTOM:
6183
            obj->animation->setPropertyName("geometry");
42 andreas 6184
 
54 andreas 6185
            if (in)
6186
            {
6187
                obj->animation->setStartValue(QRect(scLeft, scTop + (scHeight * 2), scWidth, scHeight));
6188
                obj->animation->setEndValue(QRect(scLeft, scTop, scWidth, scHeight));
295 andreas 6189
                connect(obj->animation, &QPropertyAnimation::finished, this, &MainWindow::animationInFinished);
296 andreas 6190
                obj->object.widget->show();
54 andreas 6191
            }
6192
            else
6193
            {
6194
                obj->animation->setStartValue(QRect(scLeft, scTop, scWidth, scHeight));
6195
                obj->animation->setEndValue(QRect(scLeft, scTop + (scHeight * 2), scWidth, scHeight));
6196
                obj->remove = true;
6197
                connect(obj->animation, &QPropertyAnimation::finished, this, &MainWindow::animationFinished);
6198
            }
42 andreas 6199
 
296 andreas 6200
            mLastObject = obj;
6201
            mAnimObjects.insert(pair<ulong, OBJECT_t *>(obj->handle, obj));
54 andreas 6202
            obj->animation->start();
295 andreas 6203
            MSG_DEBUG("Animation SLIDE BOTTOM started.");
54 andreas 6204
        break;
43 andreas 6205
 
54 andreas 6206
        case SE_SLIDE_LEFT_FADE:
6207
        case SE_SLIDE_LEFT:
6208
            obj->animation->setPropertyName("geometry");
43 andreas 6209
 
54 andreas 6210
            if (in)
6211
            {
6212
                obj->animation->setStartValue(QRect(scLeft - scWidth, scTop, scWidth, scHeight));
6213
                obj->animation->setEndValue(QRect(scLeft, scTop, scWidth, scHeight));
295 andreas 6214
                connect(obj->animation, &QPropertyAnimation::finished, this, &MainWindow::animationInFinished);
296 andreas 6215
                obj->object.widget->show();
54 andreas 6216
            }
6217
            else
6218
            {
6219
                obj->animation->setStartValue(QRect(scLeft, scTop, scWidth, scHeight));
6220
                obj->animation->setEndValue(QRect(scLeft - scWidth, scTop, scWidth, scHeight));
6221
                obj->remove = true;
6222
                connect(obj->animation, &QPropertyAnimation::finished, this, &MainWindow::animationFinished);
6223
            }
42 andreas 6224
 
296 andreas 6225
            mLastObject = obj;
6226
            mAnimObjects.insert(pair<ulong, OBJECT_t *>(obj->handle, obj));
54 andreas 6227
            obj->animation->start();
6228
        break;
43 andreas 6229
 
54 andreas 6230
        case SE_SLIDE_RIGHT_FADE:
6231
        case SE_SLIDE_RIGHT:
6232
            obj->animation->setPropertyName("geometry");
43 andreas 6233
 
54 andreas 6234
            if (in)
6235
            {
6236
                obj->animation->setStartValue(QRect(scLeft + scWidth, scTop, scWidth, scHeight));
6237
                obj->animation->setEndValue(QRect(scLeft, scTop, scWidth, scHeight));
295 andreas 6238
                connect(obj->animation, &QPropertyAnimation::finished, this, &MainWindow::animationInFinished);
296 andreas 6239
                obj->object.widget->show();
54 andreas 6240
            }
6241
            else
6242
            {
6243
                obj->animation->setStartValue(QRect(scLeft, scTop, scWidth, scHeight));
6244
                obj->animation->setEndValue(QRect(scLeft + scWidth, scTop, scWidth, scHeight));
6245
                obj->remove = true;
6246
                connect(obj->animation, &QPropertyAnimation::finished, this, &MainWindow::animationFinished);
6247
            }
42 andreas 6248
 
296 andreas 6249
            mLastObject = obj;
6250
            mAnimObjects.insert(pair<ulong, OBJECT_t *>(obj->handle, obj));
54 andreas 6251
            obj->animation->start();
6252
        break;
43 andreas 6253
 
54 andreas 6254
        case SE_SLIDE_TOP_FADE:
6255
        case SE_SLIDE_TOP:
6256
            obj->animation->setPropertyName("geometry");
43 andreas 6257
 
54 andreas 6258
            if (in)
6259
            {
6260
                obj->animation->setStartValue(QRect(scLeft, scTop - scHeight, scWidth, scHeight));
6261
                obj->animation->setEndValue(QRect(scLeft, scTop, scWidth, scHeight));
295 andreas 6262
                connect(obj->animation, &QPropertyAnimation::finished, this, &MainWindow::animationInFinished);
296 andreas 6263
                obj->object.widget->show();
54 andreas 6264
            }
6265
            else
6266
            {
6267
                obj->animation->setStartValue(QRect(scLeft, scTop, scWidth, scHeight));
6268
                obj->animation->setEndValue(QRect(scLeft, scTop - scHeight, scWidth, scHeight));
6269
                obj->remove = true;
6270
                connect(obj->animation, &QPropertyAnimation::finished, this, &MainWindow::animationFinished);
6271
            }
43 andreas 6272
 
296 andreas 6273
            mLastObject = obj;
6274
            mAnimObjects.insert(pair<ulong, OBJECT_t *>(obj->handle, obj));
54 andreas 6275
            obj->animation->start();
6276
        break;
6277
 
58 andreas 6278
        case SE_FADE:
6279
            if (in)
6280
            {
289 andreas 6281
                if (obj->object.widget)
6282
                {
6283
                    obj->object.widget->setWindowOpacity(0.0);
6284
                    obj->object.widget->show();
6285
                }
6286
 
58 andreas 6287
                obj->animation->setStartValue(0.0);
6288
                obj->animation->setEndValue(1.0);
295 andreas 6289
                connect(obj->animation, &QPropertyAnimation::finished, this, &MainWindow::animationInFinished);
296 andreas 6290
                obj->object.widget->show();
58 andreas 6291
            }
6292
            else
6293
            {
6294
                obj->animation->setStartValue(1.0);
6295
                obj->animation->setEndValue(0.0);
6296
                obj->remove = true;
6297
                connect(obj->animation, &QPropertyAnimation::finished, this, &MainWindow::animationFinished);
6298
            }
6299
 
296 andreas 6300
            mLastObject = obj;
6301
            mAnimObjects.insert(pair<ulong, OBJECT_t *>(obj->handle, obj));
58 andreas 6302
            obj->animation->setEasingCurve(QEasingCurve::Linear);
6303
            obj->animation->start();
6304
        break;
6305
 
54 andreas 6306
        default:
6307
            MSG_WARNING("Subpage effect " << ani.showEffect << " is not supported.");
298 andreas 6308
            delete obj->animation;
6309
            obj->animation = nullptr;
6310
            return false;
42 andreas 6311
    }
298 andreas 6312
 
6313
    return true;
42 andreas 6314
}
6315
 
179 andreas 6316
void MainWindow::downloadBar(const string &msg, QWidget *parent)
6317
{
6318
    DECL_TRACER("void MainWindow::downloadBar(const string &msg, QWidget *parent)");
6319
 
6320
    if (mBusy)
6321
        return;
6322
 
6323
    mBusy = true;
6324
    mDownloadBar = new TqDownload(msg, parent);
6325
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
6326
    mDownloadBar->setScaleFactor(gScale);
6327
    mDownloadBar->doResize();
6328
#endif
6329
    mDownloadBar->show();
6330
}
6331
 
120 andreas 6332
void MainWindow::runEvents()
6333
{
6334
    DECL_TRACER("MainWindow::runEvents()");
6335
 
6336
    QApplication::processEvents();
6337
}
6338
 
289 andreas 6339
void MainWindow::onSubViewItemClicked(ulong handle, bool pressed)
6340
{
6341
    DECL_TRACER("MainWindow::onSubViewItemClicked(ulong handle)");
6342
 
6343
    if (!handle)
6344
        return;
6345
 
6346
    // Create a thread and call the base program function.
6347
    // We create a thread to not interrupt the QT framework longer then
6348
    // necessary.
6349
    if (gPageManager)
299 andreas 6350
        gPageManager->mouseEvent(handle, pressed);
289 andreas 6351
}
6352
 
303 andreas 6353
void MainWindow::onInputChanged(ulong handle, string& text)
6354
{
6355
    DECL_TRACER("MainWindow::onInputChanged(ulong handle, string& text)");
6356
 
6357
    try
6358
    {
6359
        std::thread thr = std::thread([=] {
6360
            if (gPageManager)
6361
                gPageManager->inputButtonFinished(handle, text);
6362
        });
6363
 
6364
        thr.detach();
6365
    }
6366
    catch (std::exception& e)
6367
    {
6368
        MSG_ERROR("Error starting a thread to handle input line finish: " << e.what());
6369
    }
6370
}
6371
 
309 andreas 6372
void MainWindow::onFocusChanged(ulong handle, bool in)
6373
{
6374
    DECL_TRACER("MainWindow::onFocusChanged(ulong handle, bool in)");
6375
 
6376
    if (gPageManager)
6377
        gPageManager->inputFocusChanged(handle, in);
6378
}
6379
 
6380
void MainWindow::onCursorChanged(ulong handle, int oldPos, int newPos)
6381
{
6382
    DECL_TRACER("MainWindow::onCursorChanged(ulong handle, int oldPos, int newPos)");
6383
 
6384
    if (gPageManager)
6385
        gPageManager->inputCursorPositionChanged(handle, oldPos, newPos);
6386
}
6387
 
323 andreas 6388
void MainWindow::onGestureEvent(QObject *obj, QGestureEvent *event)
6389
{
6390
    DECL_TRACER("MainWindow::onGestureEvent(QObject *obj, QGestureEvent *event)");
6391
 
6392
    Q_UNUSED(obj);
6393
    gestureEvent(event);
6394
}
6395
 
285 andreas 6396
QPixmap MainWindow::scaleImage(QPixmap& pix)
6397
{
6398
    DECL_TRACER("MainWindow::scaleImage(QPixmap& pix)");
6399
 
6400
    int width = scale(pix.width());
6401
    int height = scale(pix.height());
6402
 
6403
    return pix.scaled(width, height);
6404
}
6405
 
6406
QPixmap MainWindow::scaleImage(unsigned char* buffer, int width, int height, int pixline)
6407
{
6408
    DECL_TRACER("MainWindow::scaleImage(unsigned char* buffer, int width, int height, int pixline)");
6409
 
300 andreas 6410
    if (!buffer || width < 1 || height < 1 || pixline < (width * 4))
6411
    {
6412
        MSG_ERROR("Invalid image for scaling!");
6413
        return QPixmap();
6414
    }
6415
 
285 andreas 6416
    QImage img(buffer, width, height, pixline, QImage::Format_ARGB32);  // Original size
6417
 
6418
    if (img.isNull() || !img.valid(width-1, height-1))
6419
    {
6420
        MSG_ERROR("Unable to create a valid image!");
6421
        return QPixmap();
6422
    }
6423
 
6424
    QSize size(scale(width), scale(height));
6425
    QPixmap pixmap;
6426
    bool ret = false;
6427
 
6428
    if (isScaled())
6429
        ret = pixmap.convertFromImage(img.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); // Scaled size
6430
    else
6431
        ret = pixmap.convertFromImage(img);
6432
 
6433
    if (!ret || pixmap.isNull())
6434
    {
6435
        MSG_ERROR("Unable to create a pixmap out of an image!");
6436
    }
6437
 
6438
    return pixmap;
6439
}
6440
 
2 andreas 6441
#ifndef QT_NO_SESSIONMANAGER
6442
void MainWindow::commitData(QSessionManager &manager)
6443
{
5 andreas 6444
    if (manager.allowsInteraction())
6445
    {
6446
        if (!settingsChanged)
6447
            manager.cancel();
6448
    }
6449
    else
6450
    {
6451
        if (settingsChanged)
6452
            writeSettings();
6453
    }
2 andreas 6454
}
5 andreas 6455
#endif