Rev 19 | Blame | Last modification | View Log | RSS feed
/*
* Copyright (C) 2020, 2021 by Andreas Theofilu <andreas@theosys.at>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/** @file tqtmain.cpp
* @brief Implements the surface of the application.
*
* This file implements the callback functions of the suface. While the most
* classes are drawing the elements, the methods here take the ready elements
* and display them. This file makes the surface completely independent of
* the rest of the application which makes it easy to change the surface by
* any other technology.
*/
#include <QApplication>
#include <QByteArray>
#include <QCommandLineParser>
#include <QCommandLineOption>
#include <QLabel>
#include <QtWidgets>
#include <QMouseEvent>
#include <QMoveEvent>
#include <QPalette>
#include <QPixmap>
#include <QFont>
#include <QFontDatabase>
#include <QtMultimediaWidgets/QVideoWidget>
#include <QtMultimedia/QMediaPlayer>
#include <QtMultimedia/QMediaPlaylist>
#include <QUrl>
#include <QThread>
#include <functional>
#include <mutex>
#include "tpagemanager.h"
#include "tqtmain.h"
#include "tconfig.h"
#include "tqtsettings.h"
#include "tcolor.h"
/**
* @def __ANDROID__
* Here we've to define some extra place holders because on Android only 10
* place holders are defined by default. But we've a callback functions which
* need 13 place holders. The defination is taken from the original defination
* of place holders and expanded.
*/
#ifdef __ANDROID__
#if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _11;
_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _12;
_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _13;
_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _14;
_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _15;
_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _16;
_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _17;
_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _18;
_LIBCPP_FUNC_VIS extern const std::placeholders::__ph<10> _19;
_LIBCPP_FUNC_VIS extern const _std::placeholders::_ph<10> _20;
#else
/* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<11> _11{};
/* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<12> _12{};
/* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<13> _13{};
/* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<14> _14{};
/* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<15> _15{};
/* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<16> _16{};
/* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<17> _17{};
/* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<18> _18{};
/* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<19> _19{};
/* _LIBCPP_INLINE_VAR */ constexpr std::placeholders::__ph<20> _20{};
#endif // defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
#endif
static TPageManager *pageManager = nullptr; //!< The pointer to the global defined main class.
std::mutex draw_mutex; //!< We're using threads and need to block execution sometimes
using std::bind;
using std::string;
/**
* @brief qtmain is used here as the entry point for the surface.
*
* The main entry function parses the command line parameters, if there were
* any and sets the basic attributes. It creates the main window and starts the
* application.
*
* @param argc The number of command line arguments
* @param argv A pointer to a 2 dimensional array containing the command
* line parameters.
* @param pmanager A pointer to the page manager class which is the main class
* managing everything.
*
* @return If no errors occured it returns 0.
*/
int qtmain(int argc, char **argv, TPageManager *pmanager)
{
DECL_TRACER("qtmain(int argc, char **argv, width, int height)");
pageManager = pmanager;
// Q_INIT_RESOURCE(tpanel);
#ifdef Q_OS_ANDROID
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QApplication app(argc, argv);
QCoreApplication::setOrganizationName(TConfig::getProgName().c_str());
QCoreApplication::setApplicationName("AMX panel simulator");
QCoreApplication::setApplicationVersion(QT_VERSION_STR);
QCommandLineParser parser;
parser.setApplicationDescription(QCoreApplication::applicationName());
parser.addHelpOption();
parser.addVersionOption();
parser.process(app);
MainWindow mainWin;
mainWin.show();
return app.exec();
}
/**
* @brief MainWindow::MainWindow constructor
*
* This method is the constructor for this class. It registers the callback
* functions to the class TPageManager and starts the main run loop.
*/
MainWindow::MainWindow()
{
DECL_TRACER("MainWindow::MainWindow()");
pageManager->registerCallbackDB(bind(&MainWindow::_displayButton, this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_4,
std::placeholders::_5,
std::placeholders::_6,
std::placeholders::_7,
std::placeholders::_8));
pageManager->registerCallbackSP(bind(&MainWindow::_setPage, this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3));
pageManager->registerCallbackSSP(bind(&MainWindow::_setSubPage, this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_4,
std::placeholders::_5));
pageManager->registerCallbackSB(bind(&MainWindow::_setBackground, this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_4,
std::placeholders::_5));
pageManager->registerCallbackFT(bind(&MainWindow::_setText, this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_4,
std::placeholders::_5,
std::placeholders::_6,
std::placeholders::_7,
std::placeholders::_8,
std::placeholders::_9,
std::placeholders::_10,
#ifdef __ANDROID__
_11,
_12,
_13));
#else
std::placeholders::_11,
std::placeholders::_12,
std::placeholders::_13));
#endif
pageManager->regCallDropPage(bind(&MainWindow::_dropPage, this, std::placeholders::_1));
pageManager->regCallDropSubPage(bind(&MainWindow::_dropSubPage, this, std::placeholders::_1));
pageManager->regCallPlayVideo(bind(&MainWindow::_playVideo, this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_4,
std::placeholders::_5,
std::placeholders::_6,
std::placeholders::_7,
std::placeholders::_8,
std::placeholders::_9));
createActions();
#ifndef QT_NO_SESSIONMANAGER
QGuiApplication::setFallbackSessionManagementEnabled(false);
connect(qApp, &QGuiApplication::commitDataRequest,
this, &MainWindow::writeSettings);
#endif
qRegisterMetaType<size_t>("size_t");
qRegisterMetaType<QByteArray>("QByteArray");
try
{
connect(this, &MainWindow::sigDisplayButton, this, &MainWindow::displayButton);
connect(this, &MainWindow::sigDisplayButton, // same sender and signal
this, // context object to break this connection
[this]() { // debug output
MSG_DEBUG("Direct? " << ((QThread::currentThread() == this->thread())?"YES":"NO"));
},
Qt::DirectConnection);
connect(this, &MainWindow::sigSetPage, this, &MainWindow::setPage);
connect(this, &MainWindow::sigSetSubPage, this, &MainWindow::setSubPage);
connect(this, &MainWindow::sigSetBackground, this, &MainWindow::setBackground);
connect(this, &MainWindow::sigSetText, this, &MainWindow::setText);
connect(this, &MainWindow::sigDropPage, this, &MainWindow::dropPage);
connect(this, &MainWindow::sigDropSubPage, this, &MainWindow::dropSubPage);
connect(this, &MainWindow::sigPlayVideo, this, &MainWindow::playVideo);
}
catch (std::exception& e)
{
MSG_ERROR("Connection error: " << e.what());
}
setUnifiedTitleAndToolBarOnMac(true);
pageManager->run();
}
/**
* @brief MainWindow::closeEvent called when the application receives an exit event.
*
* If the user clicks on the exit icon or on the menu point _Exit_ this method
* is called. It makes sure everything is written to the configuration file
* and accepts the evernt.
*
* @param event The exit event
*/
void MainWindow::closeEvent(QCloseEvent *event)
{
DECL_TRACER("MainWindow::closeEvent(QCloseEvent *event)");
if (settingsChanged)
{
writeSettings();
event->accept();
}
else
{
// event->ignore();
prg_stopped = true;
MSG_TRACE("Program will stop!");
event->accept();
}
}
/**
* @brief MainWindow::eventFilter filters the QEvent::MouseMove event
* @param obj The object where the event occured.
* @param event The event.
* @return `true` when the event should be ignored.
*/
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
// DECL_TRACER("MainWindow::eventFilter(QObject *obj, QEvent *event)");
if (event->type() == QEvent::MouseMove)
return true; // Filter event out, i.e. stop it being handled further.
return QMainWindow::eventFilter(obj, event);
}
/**
* @brief MainWindow::createActions creates the configuration dialog window.
*/
void MainWindow::createActions()
{
DECL_TRACER("MainWindow::createActions()");
// Add a menu
QMenu *editMenu = menuBar()->addMenu(tr("&Edit"));
const QIcon settingsIcon = QIcon::fromTheme("document-open", QIcon(":/images/settings-configure.png"));
QAction *settingsAct = new QAction(settingsIcon, tr("&Settings..."), this);
settingsAct->setStatusTip(tr("Change the settings"));
connect(settingsAct, &QAction::triggered, this, &MainWindow::settings);
editMenu->addAction(settingsAct);
const QIcon aboutIcon = QIcon::fromTheme("document-open", QIcon(":/images/help-about.png"));
QAction *aboutAct = new QAction(aboutIcon, tr("&About..."), this);
aboutAct->setShortcuts(QKeySequence::Open);
aboutAct->setStatusTip(tr("About this program"));
connect(aboutAct, &QAction::triggered, this, &MainWindow::about);
editMenu->addAction(aboutAct);
editMenu->addSeparator();
const QIcon exitIcon = QIcon::fromTheme("application-exit");
QAction *exitAct = editMenu->addAction(exitIcon, tr("E&xit"), this, &QWidget::close);
exitAct->setShortcuts(QKeySequence::Quit);
exitAct->setStatusTip(tr("Exit the application"));
}
/**
* @brief MainWindow::mousePressEvent catches the event Qt::LeftButton.
*
* If the user presses the left mouse button somewhere in the main window, this
* method is triggered. It retrieves the position of the mouse pointer and
* sends it to the page manager TPageManager.
*
* @param event The event
*/
void MainWindow::mousePressEvent(QMouseEvent* event)
{
if(event->button() == Qt::LeftButton)
{
pageManager->mouseEvent(event->x(), event->y(), true);
}
}
/**
* @brief MainWindow::mouseReleaseEvent catches the event Qt::LeftButton.
*
* If the user releases the left mouse button somewhere in the main window, this
* method is triggered. It retrieves the position of the mouse pointer and
* sends it to the page manager TPageManager.
*
* @param event The event
*/
void MainWindow::mouseReleaseEvent(QMouseEvent* event)
{
if(event->button() == Qt::LeftButton)
{
pageManager->mouseEvent(event->x(), event->y(), false);
}
}
/**
* @brief MainWindow::settings initiates the configuration dialog.
*/
void MainWindow::settings()
{
DECL_TRACER("MainWindow::settings()");
TQtSettings *dlg_settings = new TQtSettings(this);
dlg_settings->show();
}
/**
* @brief MainWindow::writeSettings Writes the settings into the configuration file.
*/
void MainWindow::writeSettings()
{
DECL_TRACER("MainWindow::writeSettings()");
}
/**
* @brief MainWindow::about displays the _about_ dialog.
*/
void MainWindow::about()
{
DECL_TRACER("MainWindow::about()");
QMessageBox::about(this, tr(std::string("About ").append(TConfig::getProgName()).c_str()),
tr("Simulation of an AMX G4 panel\n"
"(C) Copyright 2020 by Andreas Theofilu <andreas@theosys.at>\n"
"This program is under the terms of GPL version 3"));
}
/******************* Signal handling *************************/
void MainWindow::_displayButton(ulong handle, ulong parent, unsigned char* buffer, int width, int height, int pixline, int left, int top)
{
DECL_TRACER("MainWindow::_displayButton(ulong handle, ulong parent, unsigned char* buffer, int width, int height, int pixline, int left, int top)");
if (prg_stopped)
return;
QByteArray buf;
if (buffer && pixline > 0)
{
size_t size = width * height * (pixline / width);
MSG_DEBUG("Buffer size=" << size << ", width=" << width << ", height=" << height << ", left=" << left << ", top=" << top);
buf.insert(0, (const char *)buffer, size);
}
try
{
emit sigDisplayButton(handle, parent, buf, width, height, pixline, left, top);
}
catch (std::exception& e)
{
MSG_ERROR("Error triggering function \"displayButton()\": " << e.what());
}
}
void MainWindow::_setPage(ulong handle, int width, int height)
{
DECL_TRACER("MainWindow::_setPage(ulong handle, int width, int height)");
if (prg_stopped)
return;
emit sigSetPage(handle, width, height);
}
void MainWindow::_setSubPage(ulong handle, int left, int top, int width, int height)
{
DECL_TRACER("MainWindow::_setSubPage(ulong handle, int left, int top, int width, int height)");
if (prg_stopped)
return;
emit sigSetSubPage(handle, left, top, width, height);
}
void MainWindow::_setBackground(ulong handle, unsigned char *image, size_t size, size_t rowBytes, ulong color)
{
DECL_TRACER("MainWindow::_setBackground(ulong handle, unsigned char *image, size_t size, size_t rowBytes, ulong color)");
if (prg_stopped)
return;
QByteArray buf;
if (image && size > 0)
buf.insert(0, (const char *)image, size);
emit sigSetBackground(handle, buf, rowBytes, color);
}
void MainWindow::_setText(ulong handle, const std::string& text, const std::string& font, const std::string& family, int size, int x, int y, ulong color, ulong effectColor, FONT_STYLE style, Button::TEXT_ORIENTATION ori, Button::TEXT_EFFECT effect, bool ww)
{
DECL_TRACER("MainWindow::_setText(ulong handle, const std::string& text, const std::string& font, const std::string& family, int size, int x, int y, ulong color, ulong effectColor, FONT_STYLE style, Button::TEXT_ORIENTATION ori, Button::TEXT_EFFECT effect, bool ww)");
if (prg_stopped)
return;
emit sigSetText(handle, text, font, family, size, x, y, color, effectColor, style, ori, effect, ww);
}
void MainWindow::_dropPage(ulong handle)
{
DECL_TRACER("MainWindow::_dropPage(ulong handle)");
emit sigDropPage(handle);
}
void MainWindow::_dropSubPage(ulong handle)
{
DECL_TRACER("MainWindow::_dropSubPage(ulong handle)");
emit sigDropSubPage(handle);
}
void MainWindow::_playVideo(ulong handle, ulong parent, int left, int top, int width, int height, const string& url, const string& user, const string& pw)
{
DECL_TRACER("MainWindow::_playVideo(ulong handle, const string& url)");
if (prg_stopped)
return;
emit sigPlayVideo(handle, parent, left, top, width, height, url, user, pw);
}
/******************* Draw elements *************************/
void MainWindow::displayButton(ulong handle, ulong parent, QByteArray buffer, int width, int height, int pixline, int left, int top)
{
draw_mutex.lock();
DECL_TRACER("MainWindow::displayButton(ulong handle, unsigned char* buffer, size_t size, int width, int height, int pixline, int left, int top)");
OBJECT_t *obj = findObject(handle);
OBJECT_t *par = findObject(parent);
MSG_DEBUG("Processing button " << handleToString(handle) << " from parent " << handleToString(parent));
if (!par)
{
MSG_WARNING("Button " << handle << " has no parent (" << parent << ")! Ignoring it.");
draw_mutex.unlock();
return;
}
if (!obj)
{
MSG_DEBUG("Adding new object ...");
obj = addObject();
if (!obj)
{
MSG_ERROR("Error creating an object!");
TError::setError();
draw_mutex.unlock();
return;
}
obj->type = OBJ_BUTTON;
obj->handle = handle;
obj->width = width;
obj->height = height;
obj->left = left;
obj->top = top;
obj->object.label = new QLabel("", par->object.widget);
obj->object.label->installEventFilter(this);
}
else
MSG_DEBUG("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " found!");
obj->object.label->setFixedSize(width, height);
obj->object.label->move(left, top);
obj->object.label->setAttribute(Qt::WA_TransparentForMouseEvents);
MSG_DEBUG("Geometry: l:" << left << ", t:" << top << ", w:" << width << ", h:" << height);
if (buffer.size() > 0 && pixline > 0)
{
MSG_DEBUG("Adding image for " << handleToString(handle) << " ...");
QImage img((unsigned char *)buffer.data(), width, height, pixline, QImage::Format_ARGB32);
QPixmap pixmap(width, height);
pixmap.convertFromImage(img);
obj->object.label->setPixmap(pixmap);
}
else
{
MSG_DEBUG("No image found.");
}
obj->object.label->show();
draw_mutex.unlock();
}
void MainWindow::setPage(ulong handle, int width, int height)
{
draw_mutex.lock();
DECL_TRACER("MainWindow::setPage(ulong handle, int width, int height)");
QSize qs = menuBar()->sizeHint();
this->setMinimumSize(width, height + qs.height());
OBJECT_t *obj = findObject(handle);
if (!obj)
{
obj = addObject();
if (!obj)
{
MSG_ERROR("Error crating an object for handle " << handleToString(handle));
TError::setError();
draw_mutex.unlock();
return;
}
obj->handle = handle;
obj->height = height;
obj->width = width;
obj->type = OBJ_PAGE;
}
bool newBackground = false;
if (!mBackground)
{
mBackground = new QWidget();
mBackground->setAutoFillBackground(true);
mBackground->setFixedSize(obj->width, obj->height);
QRect rectBack = mBackground->geometry();
QRect rectMain = this->geometry();
pageManager->setFirstTopPixel(rectMain.height() - rectBack.height());
newBackground = true;
}
// By default set a transparent background
QPixmap pix(width, height);
pix.fill(QColor::fromRgba(qRgba(0,0,0,0xff)));
QPalette palette;
palette.setBrush(QPalette::Window, pix);
mBackground->setPalette(palette);
if (newBackground)
this->setCentralWidget(mBackground);
mBackground->show();
draw_mutex.unlock();
}
void MainWindow::setSubPage(ulong handle, int left, int top, int width, int height)
{
draw_mutex.lock();
DECL_TRACER("MainWindow::setSubPage(ulong handle, int left, int top, int width, int height)");
OBJECT_t *obj = addObject();
if (!obj)
{
MSG_ERROR("Error adding an object!");
TError::setError();
draw_mutex.unlock();
return;
}
obj->type = OBJ_SUBPAGE;
obj->handle = handle;
obj->object.widget = new QWidget(centralWidget());
obj->object.widget->setAutoFillBackground(true);
obj->object.widget->setFixedSize(width, height);
obj->object.widget->move(left, top);
obj->left = left;
obj->top = top;
obj->width = width;
obj->height = height;
// filter move event
obj->object.widget->installEventFilter(this);
// By default set a transparent background
QPixmap pix(width, height);
pix.fill(QColor::fromRgba(qRgba(0,0,0,0xff)));
QPalette palette;
palette.setBrush(QPalette::Window, QBrush(pix));
obj->object.widget->setPalette(palette);
draw_mutex.unlock();
}
void MainWindow::setBackground(ulong handle, QByteArray image, size_t rowBytes, ulong color)
{
draw_mutex.lock();
DECL_TRACER("MainWindow::setBackground(ulong handle, unsigned char* image, size_t size, size_t rowBytes, ulong color)");
OBJECT_t *obj = findObject(handle);
if (!obj)
{
MSG_WARNING("No object " << handleToString(handle) << " found!");
draw_mutex.unlock();
return;
}
MSG_DEBUG("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " found!");
if (obj->type == OBJ_BUTTON || obj->type == OBJ_SUBPAGE)
{
MSG_DEBUG("Processing object " << objectToString(obj->type));
QPixmap pix(obj->width, obj->height);
pix.fill(QColor::fromRgba(qRgba(TColor::getRed(color),TColor::getGreen(color),TColor::getBlue(color),TColor::getAlpha(color))));
if (image.size() > 0)
{
MSG_DEBUG("Setting image of size " << image.size());
QImage img((unsigned char *)image.data(), obj->width, obj->height, rowBytes, QImage::Format_ARGB32);
pix.convertFromImage(img);
}
if (obj->type == OBJ_BUTTON)
{
obj->object.label->setPixmap(pix);
obj->object.label->show();
}
else
{
MSG_DEBUG("Setting image as background for page " << ((handle >> 16) & 0x0000ffff));
QPalette palette;
palette.setBrush(QPalette::Window, QBrush(pix));
// FIXME: Background image is not visible!
obj->object.widget->setPalette(palette);
obj->object.widget->show();
}
}
else if (obj->type == OBJ_PAGE)
{
bool newBackground = false;
if (!mBackground)
{
mBackground = new QWidget();
mBackground->setAutoFillBackground(true);
mBackground->setFixedSize(obj->width, obj->height);
newBackground = true;
MSG_DEBUG("New background image added to page with size " << obj->width << " x " << obj->height);
}
QPixmap pix(obj->width, obj->height);
pix.fill(QColor::fromRgba(qRgba(TColor::getRed(color),TColor::getGreen(color),TColor::getBlue(color),TColor::getAlpha(color))));
if (image.size() > 0)
{
QImage img((unsigned char *)image.data(), obj->width, obj->height, rowBytes, QImage::Format_ARGB32);
pix.convertFromImage(img);
}
QPalette palette;
palette.setBrush(QPalette::Window, QBrush(pix));
mBackground->setPalette(palette);
if (newBackground)
this->setCentralWidget(mBackground);
mBackground->show();
MSG_DEBUG("Background set");
}
draw_mutex.unlock();
}
void MainWindow::setText(ulong handle, const std::string& text, const std::string& font, const std::string& family, int size, int x, int y, ulong color, ulong effectColor, FONT_STYLE style, Button::TEXT_ORIENTATION ori, Button::TEXT_EFFECT effect, bool ww)
{
draw_mutex.lock();
DECL_TRACER("MainWindow::setText(ulong handle, const std::string& text, const std::string& font, int size, int x, int y, ulong color, ulong effectColor, FONT_STYLE style, Button::TEXT_ORIENTATION ori, Button::TEXT_EFFECT effect, bool ww)");
OBJECT_t *obj = findObject(handle);
if (!obj)
{
MSG_ERROR("Object " << handleToString(handle) << " not found!");
TError::setError();
draw_mutex.unlock();
return;
}
if (!obj->object.label)
{
MSG_ERROR("Object " << handleToString(handle) << " contains no child element!");
TError::setError();
draw_mutex.unlock();
return;
}
MSG_DEBUG("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " found!");
#if !defined(QT_DISABLE_DEPRECATED_BEFORE) || (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
QPixmap pix = *obj->object.label->pixmap();
#else
QPixmap pix = obj->object.label->pixmap(Qt::ReturnByValue);
#endif
// Load the font
int fontID = 0;
if ((fontID = QFontDatabase::addApplicationFont(font.c_str())) == -1)
{
MSG_ERROR("Font " << font << " could not be loaded!");
TError::setError();
draw_mutex.unlock();
return;
}
QFont ft;
ft.setFamily(family.c_str());
ft.setPointSize(size);
switch (style)
{
case FONT_BOLD: ft.setBold(true); break;
case FONT_ITALIC: ft.setItalic(true); break;
case FONT_BOLD_ITALIC:
ft.setBold(true);
ft.setItalic(true);
break;
default:
ft.setBold(false);
ft.setItalic(false);
}
QPalette palette = obj->object.label->palette();
palette.setColor(QPalette::WindowText, QColor::fromRgba(qRgba(TColor::getRed(color),TColor::getGreen(color),TColor::getBlue(color),TColor::getAlpha(color))));
obj->object.label->setPalette(palette);
obj->object.label->setFont(ft);
obj->object.label->setWordWrap(ww);
obj->object.label->setIndent(4);
switch (ori)
{
case Button::ORI_ABSOLUT:
{
QString pos = "<font style=\"position: absolute;left:";
pos.append(x);
pos.append(";top:");
pos.append(y);
pos.append(";>");
pos.append(text.c_str());
pos.append("</font>");
MSG_DEBUG("Text: " << pos.data());
}
break;
case Button::ORI_TOP_LEFT: obj->object.label->setAlignment(Qt::AlignTop | Qt::AlignLeft); break;
case Button::ORI_TOP_MIDDLE: obj->object.label->setAlignment(Qt::AlignTop | Qt::AlignHCenter); break;
case Button::ORI_TOP_RIGHT: obj->object.label->setAlignment(Qt::AlignTop | Qt::AlignRight); break;
case Button::ORI_CENTER_LEFT: obj->object.label->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); break;
case Button::ORI_CENTER_MIDDLE: obj->object.label->setAlignment(Qt::AlignCenter); break;
case Button::ORI_CENTER_RIGHT: obj->object.label->setAlignment(Qt::AlignVCenter | Qt::AlignRight); break;
case Button::ORI_BOTTOM_LEFT: obj->object.label->setAlignment(Qt::AlignBottom | Qt::AlignLeft); break;
case Button::ORI_BOTTOM_MIDDLE: obj->object.label->setAlignment(Qt::AlignBottom | Qt::AlignHCenter); break;
case Button::ORI_BOTTOM_RIGHT: obj->object.label->setAlignment(Qt::AlignBottom | Qt::AlignRight); break;
}
obj->object.label->setText(text.c_str());
draw_mutex.unlock();
}
void MainWindow::dropPage(ulong handle)
{
draw_mutex.lock();
DECL_TRACER("MainWindow::dropPage(ulong handle)");
removeAllChilds(handle);
removeObject(handle);
if (mBackground)
{
delete mBackground;
mBackground = nullptr;
}
draw_mutex.unlock();
}
void MainWindow::dropSubPage(ulong handle)
{
draw_mutex.lock();
DECL_TRACER("MainWindow::dropSubPage(ulong handle)");
removeAllChilds(handle);
OBJECT_t *obj = findObject(handle);
if (!obj)
{
MSG_WARNING("Object " << handleToString(handle) << " does not exist. Ignoring!");
draw_mutex.unlock();
return;
}
dropContent(obj);
removeObject(handle);
draw_mutex.unlock();
}
void MainWindow::playVideo(ulong handle, ulong parent, int left, int top, int width, int height, const string& url, const string& user, const string& pw)
{
draw_mutex.lock();
DECL_TRACER("MainWindow::playVideo(ulong handle, const string& url, const string& user, const string& pw))");
OBJECT_t *obj = findObject(handle);
OBJECT_t *par = findObject(parent);
MSG_DEBUG("Processing button " << handleToString(handle) << " from parent " << handleToString(parent));
if (!par)
{
MSG_WARNING("Button has no parent! Ignoring it.");
draw_mutex.unlock();
return;
}
if (!obj)
{
MSG_DEBUG("Adding new video object ...");
obj = addObject();
if (!obj)
{
MSG_ERROR("Error creating a video object!");
TError::setError();
draw_mutex.unlock();
return;
}
obj->type = OBJ_VIDEO;
obj->handle = handle;
obj->width = width;
obj->height = height;
obj->left = left;
obj->top = top;
obj->object.vwidget = new QVideoWidget(par->object.widget);
obj->object.vwidget->installEventFilter(this);
}
else
MSG_DEBUG("Object " << handleToString(handle) << " of type " << objectToString(obj->type) << " found!");
QMediaPlaylist *playlist = new QMediaPlaylist;
QUrl qurl(url.c_str());
if (!user.empty())
qurl.setUserName(user.c_str());
if (!pw.empty())
qurl.setPassword(pw.c_str());
playlist->addMedia(qurl);
obj->player = new QMediaPlayer;
obj->player->setPlaylist(playlist);
obj->player->setVideoOutput(obj->object.vwidget);
obj->object.vwidget->show();
obj->player->play();
}
#ifndef QT_NO_SESSIONMANAGER
void MainWindow::commitData(QSessionManager &manager)
{
if (manager.allowsInteraction())
{
if (!settingsChanged)
manager.cancel();
}
else
{
if (settingsChanged)
writeSettings();
}
}
#endif