Continues migration with DDS, Common

This commit is contained in:
torsten committed 2026-07-17 12:41:42 +02:00
1 parent 9b15cee841
commit fa48db111e
668 files changed
+111841 -2

No files matched your search

+49
View File
@@ -0,0 +1,49 @@
#
# $Id$
# $HeadURL$
# $Author$
#
# Created by Mike Wille, SLSE, 2016-11-01
#
# LtsMultiMonitor
SET(LtsMultiMonitor_SRCS
lts_multi_monitor_export.h
lts_multi_monitor.cpp
lts_dummy_widget.cpp
lts_screen_container.cpp
lts_multi_monitor_selector_base.cpp
lts_screen_base.cpp
lts_magic_corner.h
lts_magic_corner.cpp
# normal screen
lts_multi_monitor_selector_normal.cpp
lts_screen_normal.cpp
# ultra wide screen
lts_multi_monitor_selector_wide.cpp
lts_screen_wide.cpp
)
NGL_ADD_LIBRARY(WS LtsMultiMonitor SHARED ${LtsMultiMonitor_SRCS})
NGL_TARGET_INCLUDE_DIRECTORIES(LtsMultiMonitor
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(LtsMultiMonitor
PUBLIC
Qt5::Core
Qt5::Widgets
PRIVATE
Qt5::Gui
LtsWidgets
LtsSessionData
LtsUtilsCore
LtsUtilsGuiDds
)
NGL_INSTALL_TARGET(LtsMultiMonitor)
+44
View File
@@ -0,0 +1,44 @@
#include "lts_dummy_widget.h"
#include <LtsUtilsGui/LtsUtilsGuiDds/dds_vector_to_pixmap.h>
#include <QIcon>
#include <QEvent>
#include <QDebug>
namespace LtsMultiMonitor
{
FullscreenVideoDummyWidget::FullscreenVideoDummyWidget()
{
setWindowIcon(LtsUtils::iconFromSvg(QStringLiteral(":/style/mobile_video.svg")));
setWindowTitle(tr("Fullscreen Video Helper"));
}
void FullscreenVideoDummyWidget::hideVideo()
{
qWarning() << "FullscreenVideoDummyWidget::hideVideo()";
emit signalHideVideo();
}
void FullscreenVideoDummyWidget::showVideo()
{
emit signalShowVideo();
}
bool FullscreenVideoDummyWidget::event(QEvent *event)
{
if (event->type() == QEvent::Type::Show)
assert(false);
return QWidget::event(event);
}
}
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include <LtsMultiMonitor/lts_multi_monitor_export.h>
#include <QWidget>
class QEvent;
namespace LtsMultiMonitor
{
class LTSMULTIMONITOR_EXPORT SecondaryWidget : public QWidget
{
Q_OBJECT
public:
SecondaryWidget() = default;
virtual ~SecondaryWidget() = default;
};
class LTSMULTIMONITOR_EXPORT FullscreenVideoDummyWidget : public SecondaryWidget
{
Q_OBJECT
public:
FullscreenVideoDummyWidget();
void hideVideo();
void showVideo();
protected:
bool event(QEvent *);
signals:
void signalWidgetPlaced(const QRect &globalGeometry);
void signalHideVideo();
void signalShowVideo();
};
}
+214
View File
@@ -0,0 +1,214 @@
#include "lts_magic_corner.h"
#include <LtsUtilsGui/LtsUtilsGuiDds/dds_vector_to_pixmap.h>
#include <QMouseEvent>
#include <QHBoxLayout>
#include <QIcon>
#include <QLabel>
#include <QTimer>
#include <QDebug>
#include <chrono>
#define SMOL 48
#define SWOLE 100
using namespace std::chrono_literals;
namespace LtsMultiMonitor
{
LtsMagicCorner::LtsMagicCorner(const QRect &neogeo)
: m_neogeo(neogeo)
, m_shrinkTimer(new QTimer(this))
, m_label(new QLabel(this))
{
m_shrinkTimer->setInterval(1500ms);
m_shrinkTimer->setSingleShot(true);
connect(m_shrinkTimer, &QTimer::timeout,
this, &LtsMagicCorner::makeSmol);
makeSmol();
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
setMouseTracking(true);
setContentsMargins(0, 0, 0, 0);
setWindowFlag(Qt::WindowType::WindowStaysOnTopHint);
setWindowFlag(Qt::WindowType::X11BypassWindowManagerHint);
activateWindow();
auto *t = new QTimer(this);
connect(t, &QTimer::timeout,
this, [this]()
{
if (!isVisible())
return;
raise();
});
t->setInterval(750ms);
t->start();
m_label->setMinimumSize(SWOLE, SWOLE);
m_label->setMaximumSize(SWOLE, SWOLE);
m_label->setGeometry(0, 0, SWOLE, SWOLE);
m_label->setText(QStringLiteral("<unknown>"));
m_label->setAlignment(Qt::AlignmentFlag::AlignCenter);
}
void LtsMagicCorner::setActiveWidgetType(LtsScreenBase::WidgetType widgetType)
{
m_activeWidgetType = widgetType;
if (widgetType == LtsScreenBase::WidgetType::MainWidget)
m_label->setPixmap(m_mainPixmap);
else
m_label->setPixmap(m_secondaryPixmap);
}
void LtsMagicCorner::setFreezed(bool freezed)
{
setVisible(!freezed);
}
void LtsMagicCorner::setIcon(const QIcon &icon, LtsScreenBase::WidgetType widgetType)
{
QPixmap p(LtsUtils::pixmapFromIcon(icon));
if (widgetType == LtsScreenBase::WidgetType::MainWidget)
m_mainPixmap = p;
else
m_secondaryPixmap = p;
if (widgetType != m_activeWidgetType)
m_label->setPixmap(p);
}
void LtsMagicCorner::mousePressEvent(QMouseEvent *event)
{
m_mousePressed = (event->button() == Qt::MouseButton::LeftButton);
}
void LtsMagicCorner::mouseReleaseEvent(QMouseEvent *event)
{
if (!m_mousePressed)
return;
m_mousePressed = false;
if (event->button() != Qt::MouseButton::LeftButton)
return;
m_shrinkTimer->start();
emit toggle();
}
void LtsMagicCorner::makeSmol()
{
setAttribute(Qt::WA_TranslucentBackground);
setGeometry(m_neogeo.x(), m_neogeo.y(), SMOL, SMOL);
setMinimumSize(SMOL, SMOL);
setMaximumSize(SMOL, SMOL);
m_label->hide();
}
void LtsMagicCorner::makeSwole()
{
if (!isVisible())
return;
setAttribute(Qt::WA_TranslucentBackground, false);
setAttribute(Qt::WA_NoSystemBackground, false);
setGeometry(m_neogeo.x(), m_neogeo.y(), SWOLE, SWOLE);
setMinimumSize(SWOLE, SWOLE);
setMaximumSize(SWOLE, SWOLE);
m_label->show();
m_shrinkTimer->start();
update();
}
void LtsMagicCorner::mouseMoveEvent(QMouseEvent *)
{
emit signalMakeAllSwole();
}
}
+55
View File
@@ -0,0 +1,55 @@
#pragma once
#include "lts_screen_base.h"
#include <QDialog>
#include <QPixmap>
class QMouseEvent;
class QPaintEvent;
class QLabel;
class QTimer;
namespace LtsMultiMonitor
{
class LtsMagicCorner : public QDialog
{
Q_OBJECT
public:
explicit LtsMagicCorner(const QRect &neogeo);
void setIcon(const QIcon &icon, LtsScreenBase::WidgetType widgetType);
void setActiveWidgetType(LtsScreenBase::WidgetType widgetType);
void setFreezed(bool freezed);
protected:
void mouseMoveEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
signals:
void toggle();
void signalMakeAllSwole();
private slots:
void makeSmol();
public slots:
void makeSwole();
private:
QRect m_neogeo;
QTimer *m_shrinkTimer;
bool m_mousePressed { false };
bool m_freezed = false;
QLabel *m_label;
QPixmap m_mainPixmap;
QPixmap m_secondaryPixmap;
LtsScreenBase::WidgetType m_activeWidgetType;
};
}
+696
View File
@@ -0,0 +1,696 @@
#include "lts_multi_monitor.h"
#include "lts_multi_monitor_selector_normal.h"
#include "lts_multi_monitor_selector_wide.h"
#include "lts_screen_normal.h"
#include "lts_screen_wide.h"
#include "lts_dummy_widget.h"
#include "lts_screen_container.h"
#include <LtsWidgets/lts_message_dialog.h>
#include <LtsWidgets/lts_base_layout_widget.h>
#include <LtsSession/lts_session_data.h>
#include <QGuiApplication>
#include <QScreen>
#include <QPointer>
#include <QWidget>
#include <QRect>
#include <QMessageBox>
#include <QDebug>
#ifdef Q_OS_WIN
#include <QtPlatformHeaders/qwindowswindowfunctions.h>
#endif
namespace LtsMultiMonitor
{
static LtsMultiMonitor *s_ltsMultiMonitor = nullptr;
LtsMultiMonitor *LtsMultiMonitor::getInstance()
{
if (!s_ltsMultiMonitor)
{
s_ltsMultiMonitor = new LtsMultiMonitor;
qAddPostRoutine(&cleanupLtsMultiMonitor);
}
return s_ltsMultiMonitor;
}
void LtsMultiMonitor::cleanupLtsMultiMonitor()
{
delete s_ltsMultiMonitor;
s_ltsMultiMonitor = nullptr;
}
LtsMultiMonitor::LtsMultiMonitor()
: QObject(nullptr)
, m_mainScreen(nullptr)
, m_active(false)
, m_initialized(false)
, m_skipScreenId(-1)
, m_subSkipScreenId(-1)
, m_overlapBaseLayouts(false)
, m_debugMargins(false)
{}
LtsMultiMonitor::~LtsMultiMonitor()
{
for (auto i = m_screens.begin(); i != m_screens.end(); ++i)
{
LtsScreenBase *screen = *i;
disconnect(screen, &QObject::destroyed, this, &LtsMultiMonitor::screenDied);
screen->deleteLater();
}
}
void LtsMultiMonitor::screenDied()
{
Q_ASSERT(false);
}
void LtsMultiMonitor::init()
{
if (LtsSessionData::LtsSessionData::getInstance()->isTablet())
{
m_overlapBaseLayouts = true;
m_initialized = true;
return;
}
if (m_initialized || !m_active)
return;
QList<QScreen *> screenList = QGuiApplication::screens();
const QScreen &mainScreen = *QGuiApplication::primaryScreen();
for (auto i = screenList.constBegin(); i != screenList.constEnd(); ++i)
{
const QScreen &screen = **i;
bool found = false;
for (LtsScreenBase *ltsScreen : qAsConst(m_screens))
{
if (ltsScreen->serialNumber() == screen.name())
{
found = true;
break;
}
}
if (found)
continue;
int screenId = m_nextScreenId++;
QRect screenGeo(screen.geometry());
if (screenId == m_skipScreenId)
{
if (m_subSkipScreenId == 0)
{
QRect newScreenGeo(screenGeo);
newScreenGeo.moveLeft(screenGeo.x() + (screenGeo.width() / 2));
newScreenGeo.setWidth(screenGeo.width() / 2);
screenGeo = newScreenGeo;
}
else if (m_subSkipScreenId == 1)
{
QRect newScreenGeo(screenGeo);
newScreenGeo.setWidth(screenGeo.width() / 2);
screenGeo = newScreenGeo;
}
else
{
continue;
}
}
bool isUltraWideView = (screenGeo.width() > 3000);
LtsScreenBase *newScreen;
if (isUltraWideView)
{
newScreen = new LtsScreenWide(screenGeo, screenId, m_debugMargins, screen.name());
}
else
{
auto *newScreenNormal = new LtsScreenNormal(std::move(screenGeo), screenId, m_debugMargins, screen.name());
newScreen = newScreenNormal;
connect(newScreenNormal, &LtsScreenNormal::signalMakeAllSwole,
this, &LtsMultiMonitor::signalMakeAllSwole);
connect(this, &LtsMultiMonitor::signalMakeAllSwole,
newScreenNormal, &LtsScreenNormal::signalMakeSwole);
}
connect(newScreen, &QObject::destroyed, this, &LtsMultiMonitor::screenDied);
if ((&mainScreen) == (&screen))
m_mainScreen = newScreen;
m_screens.append(newScreen);
}
if (m_screens.isEmpty())
{
QMessageBox::critical(nullptr, QString(), tr("No screens found - cannot start application."));
abort();
}
if (m_mainScreen == nullptr)
m_mainScreen = m_screens.first();
m_initialized = true;
emit signalScreenCountChanged(screenCount());
}
int LtsMultiMonitor::screenCount() const
{
return m_screens.count();
}
bool LtsMultiMonitor::cancelAndProcessIfInactive(QWidget *widget) const
{
if (m_active)
return false;
widget->activateWindow();
widget->show();
place(widget);
return true;
}
void LtsMultiMonitor::place(QWidget *widget)
{
auto *blw = qobject_cast<LtsWidgets::LtsBaseLayoutWidget *>(widget);
if (blw != nullptr)
emit blw->signalSuccessfullyPlaced();
}
bool LtsMultiMonitor::putScreen(QWidget *widget, int screenId, int screenPart)
{
Q_ASSERT(widget != nullptr);
if (widget == nullptr)
return false;
if (cancelAndProcessIfInactive(widget))
return true;
init();
if (overlapBaseLayouts(widget))
return true;
bool isSecondary = isWidgetSecondary(widget);
qWarning() << "putScreen: isSecondary" << isSecondary;
for (LtsScreenBase *screen : qAsConst(m_screens))
{
if (screen->screenId() != screenId)
continue;
screen->switchToTemp(isSecondary ? LtsScreenBase::WidgetType::SecondaryWidget : LtsScreenBase::WidgetType::MainWidget);
try
{
screen->putWidget(widget, screenPart);
}
catch (...)
{
screen->revertSwitch();
return selectScreen(widget);
}
screen->check();
place(widget);
screen->finalizeSwitch();
return true;
}
return selectScreen(widget);
}
bool LtsMultiMonitor::putScreenAutomatically(QWidget *widget)
{
if (widget == nullptr)
return false;
if (cancelAndProcessIfInactive(widget))
return true;
init();
if (overlapBaseLayouts(widget))
return true;
for (LtsScreenBase *screen : qAsConst(m_screens))
{
if (screen->screenId() == m_skipScreenId || !screen->isEmpty())
continue;
screen->switchToTemp(LtsScreenBase::WidgetType::SecondaryWidget);
try
{
screen->putWidget(widget, 1);
}
catch (...)
{
try
{
screen->putWidget(widget, 2);
}
catch (...)
{
screen->revertSwitch();
continue;
}
}
screen->check();
place(widget);
screen->finalizeSwitch();
return true;
}
return false;
}
bool LtsMultiMonitor::isOverlapBaseLayouts() const
{
return (m_overlapBaseLayouts );
}
void LtsMultiMonitor::freezeMagicCorner(int screenId)
{
for (auto *screen : qAsConst(m_screens))
{
if (screen->screenId() == screenId)
{
LtsScreenNormal* normalScreen = qobject_cast<LtsScreenNormal*>(screen);
if(normalScreen->child()->hasMainWidget() && normalScreen->child()->hasSecondaryWidget())
{
normalScreen->hideMagicCorner(true);
if(normalScreen->child()->activeWidgetType() == LtsScreenBase::WidgetType::MainWidget)
normalScreen->child()->toggle();
}
}
}
}
void LtsMultiMonitor::unfreezeMagicCorner(int screenId)
{
for (auto *screen : qAsConst(m_screens))
{
if (screen->screenId() == screenId)
{
LtsScreenNormal* normalScreen = qobject_cast<LtsScreenNormal*>(screen);
if(normalScreen->child()->hasMainWidget() && normalScreen->child()->hasSecondaryWidget())
normalScreen->hideMagicCorner(false);
}
}
}
bool LtsMultiMonitor::overlapBaseLayouts(QWidget *widget)
{
if (!isOverlapBaseLayouts())
return false;
Q_ASSERT(qobject_cast<FullscreenVideoDummyWidget *>(widget) == nullptr);
if (qobject_cast<FullscreenVideoDummyWidget *>(widget) != nullptr)
{
return false;
}
#ifdef Q_OS_WIN
widget->winId();
QWindowsWindowFunctions::setHasBorderInFullScreen(widget->windowHandle(), true);
#endif
widget->activateWindow();
widget->showFullScreen();
place(widget);
return true;
}
bool LtsMultiMonitor::selectAndSwap(QWidget *widget)
{
if (!m_active)
return false;
Q_ASSERT(!isOverlapBaseLayouts());
if (isOverlapBaseLayouts())
return false;
LtsScreenContainer *oldContainer = nullptr;
for (LtsScreenBase *_screen : qAsConst(m_screens))
{
try
{
oldContainer = _screen->containerOfWidget(widget);
}
catch (...){}
}
if (oldContainer == nullptr)
{
LtsWidgets::LtsMessageDialog::showMessage(widget, tr("Could not determine screen id for this swap!<br>Swapping not possible, please try again later."));
return false;
}
return selectScreen(widget, oldContainer);
}
LtsScreenBase *LtsMultiMonitor::widgetsScreen(QWidget *widget)
{
for (LtsScreenBase *screen : qAsConst(m_screens))
if (screen->hasWidget(widget))
return screen;
return nullptr;
}
bool LtsMultiMonitor::isWidgetSecondary(QWidget *widget)
{
#ifndef GUEZ_MODE
return false;
#endif
auto *blw = qobject_cast<LtsWidgets::LtsBaseLayoutWidget *>(widget);
auto *secondaryWidget = qobject_cast<SecondaryWidget *>(widget);
bool isSecondaryWidget = ((blw != nullptr && blw->isSecondaryWidget()) || secondaryWidget != nullptr);
return isSecondaryWidget;
}
class StupidDeleter
{
public:
explicit StupidDeleter(LtsScreenBase *screen)
: m_screen(screen)
{}
~StupidDeleter()
{
if (m_screen != nullptr)
{
m_screen->revertSwitch();
}
}
void reset()
{
m_screen = nullptr;
}
private:
LtsScreenBase *m_screen;
};
bool LtsMultiMonitor::selectScreen(QWidget *widget, LtsScreenContainer *swap, bool putOnMainIfFree, bool ltsScreenNormalOnly, const QVector<QWidget *> &irreplacableWidgets)
{
Q_ASSERT(widget != nullptr);
if (widget == nullptr)
return false;
if (cancelAndProcessIfInactive(widget))
return true;
init();
if (overlapBaseLayouts(widget))
return true;
bool isSecondary = isWidgetSecondary(widget);
if (!isSecondary)
{
bool allEmpty = putOnMainIfFree;
for (LtsScreenBase *screen : qAsConst(m_screens))
{
screen->switchToTemp(LtsScreenBase::WidgetType::MainWidget);
bool isEmpty = screen->isEmpty();
screen->revertSwitch();
if (isEmpty)
continue;
allEmpty = false;
break;
}
if (allEmpty)
{
m_mainScreen->switchToTemp(LtsScreenBase::WidgetType::MainWidget);
try
{
m_mainScreen->putWidget(widget);
}
catch (...)
{
qWarning() << "failed - reverting";
m_mainScreen->revertSwitch();
Q_ASSERT_X(false, __FUNCTION__, "screen promised to be empty but 'putWidgetSomewhere' method failed regardless");
auto *blw = qobject_cast<LtsWidgets::LtsBaseLayoutWidget *>(widget);
if (blw != nullptr)
emit blw->signalClose();
else
widget->deleteLater();
return false;
}
m_mainScreen->check();
place(widget);
m_mainScreen->finalizeSwitch();
return true;
}
}
auto *selectionProcessWatcher = new QObject;
bool minOnce = false;
for (auto i = m_screens.begin(); i != m_screens.end(); ++i)
{
LtsScreenBase *screen = *i;
screen->switchToTemp(isSecondary ? LtsScreenBase::WidgetType::SecondaryWidget : LtsScreenBase::WidgetType::MainWidget);
StupidDeleter _(screen);
if (screen->isIrreplaceable())
{
continue;
}
bool skip = false;
for (QWidget *widget : qAsConst(irreplacableWidgets))
{
if (screen->hasWidget(widget))
{
skip = true;
continue;
}
}
if (skip)
continue;
MultiMonitorSelectorBase *mms;
if (qobject_cast<LtsScreenNormal *>(screen) != nullptr)
{
auto *screenNormal = static_cast<LtsScreenNormal *>(screen);
mms = new MultiMonitorSelectorNormal(screenNormal, isSecondary, irreplacableWidgets);
}
else if (qobject_cast<LtsScreenWide *>(screen) != nullptr && !ltsScreenNormalOnly)
{
auto *screenWide = static_cast<LtsScreenWide *>(screen);
mms = new MultiMonitorSelectorWide(screenWide, nullptr, irreplacableWidgets);
}
else
continue;
QPointer<QWidget> widgetPtr(widget);
connect(widget, &QWidget::destroyed,
mms, &MultiMonitorSelectorBase::close);
connect(mms, &MultiMonitorSelectorBase::rejected,
this, [widgetPtr, swap]()
{
if (!widgetPtr || swap != nullptr)
return;
auto *blw = qobject_cast<LtsWidgets::LtsBaseLayoutWidget *>(widgetPtr.data());
if (blw != nullptr)
emit blw->signalClose();
else
widgetPtr->deleteLater();
});
connect(mms, &MultiMonitorSelectorBase::signalSelected,
this, [this, mms, widgetPtr]()
{
for (LtsScreenBase *screen : qAsConst(m_screens))
screen->check();
if (widgetPtr)
place(widgetPtr.data());
mms->deleteLater();
emit signalSelected();
});
connect(mms, &MultiMonitorSelectorBase::destroyed,
selectionProcessWatcher, &QObject::deleteLater);
connect(selectionProcessWatcher, &QObject::destroyed,
mms, &MultiMonitorSelectorBase::close);
mms->setSwap(swap);
mms->setWidget(widget);
mms->show();
_.reset();
minOnce = true;
}
if (!minOnce)
{
selectionProcessWatcher->deleteLater();
auto *blw = qobject_cast<LtsWidgets::LtsBaseLayoutWidget *>(widget);
if (blw != nullptr)
emit blw->signalClose();
else
widget->deleteLater();
LtsWidgets::LtsMessageDialog::showMessage(m_mainScreen->screenDialog(), tr("There are no free screens available to select from."));
return false;
}
return true;
}
}
+85
View File
@@ -0,0 +1,85 @@
#pragma once
#include "lts_multi_monitor_export.h"
#include <QObject>
#include <QVector>
#include <memory>
namespace LtsMultiMonitor
{
class LtsScreenBase;
class MultiMonitorSelectorBase;
class LtsScreenContainer;
class LTSMULTIMONITOR_EXPORT LtsMultiMonitor : public QObject
{
Q_OBJECT
public:
static LtsMultiMonitor *getInstance();
bool selectScreen(QWidget *widget, LtsScreenContainer *swap = nullptr, bool putOnMainIfFree = true, bool ltsScreenNormalOnly = false, const QVector<QWidget *> &irreplacableWidgets = {});
bool selectAndSwap(QWidget *widget);
void setEnableMultiMonitorMode() { m_active = true; }
void setDebugMultiMonitorMode() { m_debugMargins = true; }
bool isActive() const { return m_active; }
LtsScreenBase *widgetsScreen(QWidget *widget);
void freezeMagicCorner(int screenId);
void unfreezeMagicCorner(int screenId);
bool putScreen(QWidget *widget, int screenId, int screenPart);
bool putScreenAutomatically(QWidget *widget);
static void place(QWidget *widget);
void setSkipScreen(int screenId, int subScreenId = -1) { m_skipScreenId = screenId; m_subSkipScreenId = subScreenId; }
LtsScreenBase *mainScreen() const { return m_mainScreen; }
int screenCount() const;
private slots:
void screenDied();
private:
LtsMultiMonitor();
~LtsMultiMonitor();
static void cleanupLtsMultiMonitor();
void init();
bool cancelAndProcessIfInactive(QWidget *widget) const;
static bool isWidgetSecondary(QWidget *widget) ;
bool overlapBaseLayouts(QWidget *widget);
bool isOverlapBaseLayouts() const;
QVector<LtsScreenBase *> m_screens;
int m_nextScreenId { 0 };
LtsScreenBase *m_mainScreen;
bool m_active;
bool m_initialized;
int m_skipScreenId;
int m_subSkipScreenId;
bool m_overlapBaseLayouts;
bool m_debugMargins;
signals:
void signalQuitLoop();
void signalSelected();
void signalScreenCountChanged(int);
void signalMakeAllSwole();
};
}
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include <QtCore/qglobal.h>
#ifndef LTSMULTIMONITOR_EXPORT
# ifdef BUILD_STATIC_LIBRARIES
# define LTSMULTIMONITOR_EXPORT
# else
# if defined(MAKE_LTSMULTIMONITOR_LIB)
# define LTSMULTIMONITOR_EXPORT Q_DECL_EXPORT
# else
# define LTSMULTIMONITOR_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif
@@ -0,0 +1,419 @@
#include "lts_multi_monitor_selector_base.h"
#include "lts_multi_monitor.h"
#include "lts_screen_base.h"
#include "lts_screen_container.h"
#include <LtsWidgets/lts_base_layout_widget.h>
#include <LtsUtilsCore/promise.h>
#include <QPaintEvent>
#include <QCloseEvent>
#include <QStyle>
#include <QRect>
#include <QSize>
#include <QPainter>
#include <QPen>
#include <QColor>
#include <QDebug>
namespace LtsMultiMonitor
{
int MultiMonitorSelectorBase::s_margin = 10;
int MultiMonitorSelectorBase::s_offset = 6;
int MultiMonitorSelectorBase::s_buttonSize = 20;
MultiMonitorSelectorBase::MultiMonitorSelectorBase(LtsScreenBase *screen, const QVector<QWidget *> &irreplacableWidgets, QWidget *)
: QDialog(nullptr)
, m_irreplacableWidgets(irreplacableWidgets)
, m_screen(screen)
, m_screenIsIrreplaceable(screen->isIrreplaceable())
{
setGeometry(screen->screenRect());
setMouseTracking(true);
setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint );
setAttribute(Qt::WA_TranslucentBackground);
setAttribute(Qt::WA_DeleteOnClose);
}
bool MultiMonitorSelectorBase::isNullSwap(LtsScreenContainer *container)
{
if (container == m_swap)
{
return true;
}
return false;
}
void MultiMonitorSelectorBase::closeEvent(QCloseEvent *event)
{
qWarning() << "closeEvent";
if (!m_selected && !m_reverted)
{
qWarning() << "closeEvent: not selected and not reverted! reverting!";
m_screen->revertSwitch();
}
event->accept();
}
bool MultiMonitorSelectorBase::killOrSwapOldBLW(LtsScreenContainer *container ) noexcept(false)
{
if (isNullSwap(container))
return true;
if (m_swap != nullptr)
{
QWidget *oldSwapWidget;
try
{
oldSwapWidget = m_swap->stealWidget();
}
catch (...)
{
throw;
}
if (!container->isEmpty())
{
QWidget *oldContainerWidget;
try
{
oldContainerWidget = container->stealWidget();
}
catch (...)
{
throw;
}
m_swap->setWidget(oldContainerWidget);
}
container->setWidget(oldSwapWidget);
if(m_swap->activeWidgetType() == LtsScreenBase::WidgetType::SecondaryWidget && !m_swap->hasSecondaryWidget() && m_swap->hasMainWidget())
m_swap->toggle();
else if(m_swap->activeWidgetType() == LtsScreenBase::WidgetType::MainWidget && !m_swap->hasMainWidget() && m_swap->hasSecondaryWidget())
m_swap->toggle();
return true;
}
QWidget *oldWidget;
try
{
oldWidget = container->widget();
}
catch (...)
{
return false;
}
auto *oldBLW = qobject_cast<LtsWidgets::LtsBaseLayoutWidget *>(oldWidget);
if (oldBLW == nullptr)
{
container->stealWidget()->deleteLater();
return false;
}
if (!oldBLW->slotClose())
{
throw "MultiMonitorSelectorBase::killOrSwapOldBLW: failed to close old blw";
}
container->stealWidget();
return false;
}
void MultiMonitorSelectorBase::setWidget(QWidget *widget)
{
m_widget = widget;
}
void MultiMonitorSelectorBase::mouseMoveEvent(QMouseEvent *event)
{
m_cursorPos = event->pos();
update();
}
void MultiMonitorSelectorBase::mousePressEvent(QMouseEvent *event)
{
const QRect abortButtonRect(QRect(centeredRect().topRight() + QPoint(s_buttonSize, s_buttonSize), QSize(s_buttonSize, s_buttonSize)));
auto pos = event->pos();
Q_ASSERT(m_widget != nullptr);
if (abortButtonRect.contains(pos) || m_widget == nullptr)
{
qWarning() << "X pressed!";
m_reverted = true;
m_screen->revertSwitch();
reject();
return;
}
if (processSelection(pos))
{
qWarning() << "process!";
m_screen->finalizeSwitch();
selected();
return;
}
}
void MultiMonitorSelectorBase::selected()
{
m_widget = nullptr;
m_selected = true;
emit signalSelected();
}
QRect MultiMonitorSelectorBase::centeredRect() const
{
if (m_cachedCenteredRect.isValid())
return m_cachedCenteredRect;
const QSize thisSize(size());
const QSize newSize(thisSize.width() * 0.20, thisSize.height() * 0.20);
m_cachedCenteredRect = QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter, newSize, rect());
return m_cachedCenteredRect;
}
void MultiMonitorSelectorBase::setColors(QPainter &p, const QRect checkSelection, bool occupied, bool countEdge)
{
if (occupied)
{
p.setBrush(QColor("silver"));
p.setPen(QPen(QColor("white"), 2));
return;
}
if (checkSelection.contains(m_cursorPos, countEdge))
{
p.setBrush(QColor("grey"));
p.setPen(QPen(QColor("white"), 2));
return;
}
p.setBrush(QColor("black"));
p.setPen(QPen(p.brush(), 1));
}
void MultiMonitorSelectorBase::drawBase(QPainter &p, bool drawSelector, bool occupied, bool isSecondary, bool isInactiveWidgetOccupied)
{
bool showReplacementIndicator = true;
#ifndef GUEZ_MODE
isSecondary = false;
showReplacementIndicator = false;
#endif
p.save();
p.setRenderHint(QPainter::Antialiasing, true);
p.setRenderHint(QPainter::HighQualityAntialiasing, true);
p.setBrush(QColor(53, 53, 53, 150));
p.drawRect(geometry());
const QRect centered(centeredRect());
p.setBrush(QColor("silver"));
p.setPen(QPen(QColor("black"), 0.5));
if (isSecondary && isInactiveWidgetOccupied)
{
const QRect r(centered.adjusted(12, 12, 12, 12));
setColors(p, r, true);
p.drawRoundedRect(r, 7, 7);
}
if (drawSelector)
{
if (!m_screenIsIrreplaceable)
{
setColors(p, centered, occupied);
}
p.drawRoundedRect(centered, 7, 7);
}
const int cX = centered.x();
const int cW = centered.width();
const int cY = centered.y();
const int cH = centered.height();
if (isSecondary)
{
QPen pen(p.pen());
QColor pc(pen.color());
const QColor c(255 - pc.red(), 255 - pc.green(), 255 - pc.blue());
pen.setColor(c);
p.setPen(pen);
QFont f(p.font());
f.setBold(true);
f.setPixelSize(cH / 2);
p.setFont(f);
const QString text(tr("S", "Secondary (German: 'H' for 'Hilfsansicht')"));
p.drawText(centered, Qt::AlignCenter, text);
}
const QRect abortButtonRect(QRect(centered.topRight() + QPoint(s_buttonSize, s_buttonSize), QSize(s_buttonSize, s_buttonSize)));
const QPoint topRight(abortButtonRect.topLeft() );
setColors(p, abortButtonRect, false, false);
QPen pen(p.pen());
pen.setWidth(5.0);
p.setPen(pen);
p.drawLines(QVector<QLine>()
<< QLine(topRight , topRight + QPoint(s_buttonSize, s_buttonSize))
<< QLine(topRight + QPoint(0, s_buttonSize), topRight + QPoint(s_buttonSize, 0))
);
if (showReplacementIndicator && occupied)
{
p.setBrush(QColor("silver"));
p.setPen(QPen(QColor("white"), 2));
const QRect secondRect(centered.adjusted(cW + 70, 0, cW + 70, 0));
p.drawRoundedRect(secondRect, 7, 7);
p.drawLine(cX + cW + 15, cY + (cH / 2),
cX + cW + 55, cY + (cH / 2));
p.drawPolygon(QPolygon(
{
QPoint(cX + cW + 56, cY + (cH / 2)),
QPoint(cX + cW + 46, cY + (cH / 2) - 10),
QPoint(cX + cW + 46, cY + (cH / 2) + 10),
}));
const int srX = secondRect.x();
const int srY = secondRect.y();
const int srH = secondRect.height();
const int diameter = srH - 50;
const int widthByTwo = (secondRect.width() / 2);
const int diameterByTwo = (diameter / 2);
const int lineX1 = srX + widthByTwo - diameterByTwo;
const int lineY1 = srY + 25;
p.drawEllipse(lineX1, lineY1, diameter, diameter);
if (isSecondary)
{
QFont f(p.font());
f.setBold(true);
f.setPixelSize(srH / 2);
p.setFont(f);
const QString text(tr("S", "Secondary (German: 'H' for 'Hilfsansicht')"));
p.drawText(secondRect, Qt::AlignCenter, text);
}
const int lineX2 = lineX1 + diameter;
const int lineY2 = lineY1 + diameter;
p.drawLine(lineX1, lineY1, lineX2, lineY2);
p.drawLine(lineX2, lineY1, lineX1, lineY2);
}
p.restore();
}
}
@@ -0,0 +1,64 @@
#pragma once
#include <QDialog>
#include <QMap>
class QScreen;
class QPainter;
class QPaintEvent;
class QMouseEvent;
class QCloseEvent;
namespace LtsMultiMonitor
{
class LtsScreenBase;
class LtsScreenContainer;
class MultiMonitorSelectorBase : public QDialog
{
Q_OBJECT
public:
explicit MultiMonitorSelectorBase(LtsScreenBase *screen, const QVector<QWidget *> &irreplacableWidgets, QWidget *);
virtual ~MultiMonitorSelectorBase() {}
void setSwap(LtsScreenContainer *swap) { m_swap = swap; }
void setWidget(QWidget *widget);
LtsScreenBase *screen() const { return m_screen; }
signals:
void signalSelected();
protected:
static int s_offset;
static int s_margin;
static int s_buttonSize;
LtsScreenContainer *m_swap { nullptr };
QWidget *m_widget { nullptr };
mutable QRect m_cachedCenteredRect;
QVector<QWidget *> m_irreplacableWidgets;
void drawBase(QPainter &p, bool drawSelector = true, bool occupied = false, bool isSecondary = false, bool isInactiveWidgetOccupied = false);
bool killOrSwapOldBLW(LtsScreenContainer *container) noexcept(false);
bool isNullSwap(LtsScreenContainer *container);
QRect centeredRect() const;
void setColors(QPainter &p, const QRect checkSelection, bool occupied = false, bool countEdge = false);
void selected();
virtual bool processSelection(const QPoint &selection) = 0;
private:
QPoint m_cursorPos;
bool m_selected { false };
LtsScreenBase *m_screen;
bool m_screenIsIrreplaceable;
bool m_reverted { false };
void closeEvent(QCloseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
};
}
@@ -0,0 +1,100 @@
#include "lts_multi_monitor.h"
#include "lts_multi_monitor_selector_normal.h"
#include "lts_screen_container.h"
#include "lts_screen_normal.h"
#include "lts_dummy_widget.h"
#include <LtsWidgets/lts_base_layout_widget.h>
#include <QPaintEvent>
#include <QStyle>
#include <QRect>
#include <QSize>
#include <QPainter>
#include <QPen>
#include <QColor>
#include <QDebug>
namespace LtsMultiMonitor
{
MultiMonitorSelectorNormal::MultiMonitorSelectorNormal(LtsScreenNormal *screen, bool isSecondary, const QVector<QWidget *> &irreplacableWidgets)
: MultiMonitorSelectorBase(screen, irreplacableWidgets, nullptr)
, m_screen(screen)
, m_screenIsEmpty(screen->isEmpty())
, m_isSecondary(isSecondary)
, m_isInactiveWidgetOccupied(screen->child()->isInactiveWidgetOccupied())
{
}
MultiMonitorSelectorNormal::~MultiMonitorSelectorNormal()
{
}
bool MultiMonitorSelectorNormal::processSelection(const QPoint &selection)
{
if (!centeredRect().contains(selection))
{
return false;
}
if (m_screen->isIrreplaceable())
{
return false;
}
try
{
if (m_irreplacableWidgets.contains(m_screen->child()->widget()))
return false;
}
catch(...){}
try
{
if (killOrSwapOldBLW(m_screen->child()))
{
return true;
}
}
catch (...)
{
return false;
}
m_screen->putWidgetUnmanaged(m_widget);
return true;
}
void MultiMonitorSelectorNormal::paintEvent(QPaintEvent *)
{
QPainter p(this);
drawBase(p, true, !m_screenIsEmpty, m_isSecondary, m_isInactiveWidgetOccupied);
}
}
@@ -0,0 +1,37 @@
#pragma once
#include "lts_multi_monitor_selector_base.h"
#include <QDialog>
#include <QMap>
class QScreen;
class QPaintEvent;
class QMouseEvent;
namespace LtsMultiMonitor
{
class LtsScreenBase;
class LtsScreenNormal;
class MultiMonitorSelectorNormal : public MultiMonitorSelectorBase
{
Q_OBJECT
public:
explicit MultiMonitorSelectorNormal(LtsScreenNormal *screen, bool isSecondary, const QVector<QWidget *> &irreplacableWidgets = {});
~MultiMonitorSelectorNormal();
private:
LtsScreenNormal *m_screen;
bool m_screenIsEmpty;
bool m_isSecondary;
bool m_isInactiveWidgetOccupied;
bool processSelection(const QPoint &selection) override;
void paintEvent(QPaintEvent *event) override;
};
}
@@ -0,0 +1,324 @@
#include "lts_multi_monitor.h"
#include "lts_multi_monitor_selector_wide.h"
#include "lts_screen_container.h"
#include "lts_screen_wide.h"
#include <QPaintEvent>
#include <QStyle>
#include <QRect>
#include <QSize>
#include <QPainter>
#include <QPen>
#include <QColor>
namespace LtsMultiMonitor
{
MultiMonitorSelectorWide::MultiMonitorSelectorWide(LtsScreenWide *screen, QWidget *, const QVector<QWidget *> &irreplacableWidgets)
: MultiMonitorSelectorBase(screen, irreplacableWidgets, nullptr )
, m_screen(screen)
{}
bool MultiMonitorSelectorWide::isDrawOnlyOneSelector()
{
bool res = ((m_screen->childMain()->isEmpty() && m_screen->childLeft()->isEmpty() && m_screen->childRight()->isEmpty())
|| (!m_screen->childMain()->isEmpty() && m_swap != nullptr && m_screen->childMain() == m_swap));
return res;
}
bool MultiMonitorSelectorWide::processSelection(const QPoint &selection)
{
LtsScreenContainer *main = m_screen->childMain();
LtsScreenContainer *left = m_screen->childLeft();
LtsScreenContainer *right = m_screen->childRight();
bool singleSelector = isDrawOnlyOneSelector();
if (singleSelector)
{
if (main->isIrreplaceable())
{
return false;
}
try
{
if (m_irreplacableWidgets.contains(main->widget()))
return false;
}
catch(...){}
if (isNullSwap(m_screen->childMain()))
{
return true;
}
if (centeredRect().contains(selection))
{
try
{
if (killOrSwapOldBLW(m_screen->childMain()))
{
return true;
}
}
catch (...)
{
return false;
}
m_screen->putWidgetUnmanagedMain(m_widget);
return true;
}
return false;
}
bool leftContains = leftSide().contains(selection);
bool rightContains = rightSide().contains(selection);
if (leftContains)
{
if (left->isIrreplaceable())
{
return false;
}
try
{
if (m_irreplacableWidgets.contains(left->widget()))
return false;
}
catch(...){}
try
{
QWidget *oldWidget = main->stealWidget();
m_screen->putWidgetUnmanagedRight(oldWidget);
}
catch (...) {}
try
{
if (killOrSwapOldBLW(left))
{
return true;
}
}
catch (...)
{
return false;
}
m_screen->putWidgetUnmanagedLeft(m_widget);
return true;
}
else if (rightContains)
{
if (right->isIrreplaceable())
{
return false;
}
try
{
if (m_irreplacableWidgets.contains(right->widget()))
return false;
}
catch(...){}
try
{
QWidget *oldWidget = main->stealWidget();
m_screen->putWidgetUnmanagedLeft(oldWidget);
}
catch (...) {}
try
{
if (killOrSwapOldBLW(right))
{
return true;
}
}
catch (...)
{
return false;
}
m_screen->putWidgetUnmanagedRight(m_widget);
return true;
}
return false;
}
QRect MultiMonitorSelectorWide::leftSide() const
{
QRect centered = centeredRect();
return QRect(centered.x() + s_margin,
centered.y() + s_margin,
(centered.width() / 2) - (s_margin*2),
centered.height() - (s_margin*2));
}
QRect MultiMonitorSelectorWide::rightSide() const
{
QRect centered = centeredRect();
return QRect(centered.x() + (centered.width() / 2) + s_margin,
centered.y() + s_margin,
(centered.width() / 2) - (s_margin*2),
centered.height() - (s_margin*2));
}
void MultiMonitorSelectorWide::paintEvent(QPaintEvent *)
{
QPainter p(this);
p.save();
p.setRenderHint(QPainter::Antialiasing, true);
p.setRenderHint(QPainter::HighQualityAntialiasing, true);
const QRect centered(centeredRect());
bool drawOnlyOneSelector = isDrawOnlyOneSelector();
drawBase(p, drawOnlyOneSelector, false );
if (!drawOnlyOneSelector)
{
p.setBrush(QColor("silver"));
p.setPen(QPen(QColor("black"), 0.5));
p.drawRoundedRect(centered, 7, 7);
bool leftIrreplacable = false;
try
{
leftIrreplacable = m_irreplacableWidgets.contains(m_screen->childLeft()->widget());
}
catch(...){}
if (!m_screen->childLeft()->isIrreplaceable() && !leftIrreplacable)
{
const QRect leftSide(centered.x() + s_margin,
centered.y() + s_margin,
(centered.width() / 2) - (s_margin*2),
centered.height() - (s_margin*2));
setColors(p, leftSide, !m_screen->childLeft()->isEmpty());
p.drawRoundedRect(leftSide, 6, 6);
}
bool rightIrreplacable = false;
try
{
rightIrreplacable = m_irreplacableWidgets.contains(m_screen->childRight()->widget());
}
catch(...){}
if (!m_screen->childRight()->isIrreplaceable() && !rightIrreplacable)
{
const QRect rightSide(centered.x() + (centered.width() / 2) + s_margin,
centered.y() + s_margin,
(centered.width() / 2) - (s_margin*2),
centered.height() - (s_margin*2));
setColors(p, rightSide, !m_screen->childRight()->isEmpty());
p.drawRoundedRect(rightSide, 6, 6);
}
}
static int buttonSize = 20;
const QRect abortButtonRect(QRect(centered.topRight() + QPoint(buttonSize, buttonSize), QSize(buttonSize, buttonSize)));
const QPoint topRight(abortButtonRect.topLeft() );
setColors(p, abortButtonRect, false, false);
QPen pen(p.pen());
pen.setWidth(5.0);
p.setPen(pen);
p.drawLines(QVector<QLine>()
<< QLine(topRight , topRight + QPoint(buttonSize, buttonSize))
<< QLine(topRight + QPoint(0, buttonSize), topRight + QPoint(buttonSize, 0))
);
p.restore();
}
}
@@ -0,0 +1,36 @@
#pragma once
#include "LtsMultiMonitor/lts_multi_monitor_selector_base.h"
#include <QDialog>
#include <QMap>
class QScreen;
class QPaintEvent;
class QMouseEvent;
namespace LtsMultiMonitor
{
class LtsScreenWide;
class LtsScreenBase;
class MultiMonitorSelectorWide : public MultiMonitorSelectorBase
{
Q_OBJECT
public:
explicit MultiMonitorSelectorWide(LtsScreenWide *screen, QWidget *superParent, const QVector<QWidget *> &irreplacableWidgets);
private:
LtsScreenWide *m_screen;
bool isDrawOnlyOneSelector();
QRect leftSide() const;
QRect rightSide() const;
bool processSelection(const QPoint &selection) override;
void paintEvent(QPaintEvent *event) override;
};
}
+70
View File
@@ -0,0 +1,70 @@
#include "lts_screen_base.h"
#include "lts_dummy_widget.h"
#include <LtsWidgets/lts_base_layout_widget.h>
#include <LtsUtilsCore/promise.h>
#include <QDebug>
#include <QSplitter>
#include <QHBoxLayout>
#include <QCloseEvent>
#ifdef Q_OS_WIN
#include <QtPlatformHeaders/qwindowswindowfunctions.h>
#endif
class NoCloseWidget : public QWidget
{
void closeEvent(QCloseEvent *event) override
{
event->ignore();
}
};
namespace LtsMultiMonitor
{
LtsScreenBase::LtsScreenBase(QRect screenGeo, int screenId, bool debugMargins, const QString &serial)
: m_screenDialog(new NoCloseWidget())
, m_screenId(screenId)
, m_serial(serial)
, m_screenRect(screenGeo)
{
connect(this, &LtsScreenBase::destroyed,
m_screenDialog, &QWidget::deleteLater);
if (debugMargins)
{
qWarning() << "LtsScreenBase: screen rect adjusted for dev machines!";
m_screenRect.adjust(+50, +50, -100, -100);
}
m_screenDialog->setWindowFlags(Qt::FramelessWindowHint);
m_screenDialog->setGeometry(m_screenRect);
m_screenDialog->setMinimumSize(m_screenRect.width(), m_screenRect.height());
m_screenDialog->setMaximumSize(m_screenRect.width(), m_screenRect.height());
m_screenDialog->setContentsMargins(0, 0, 0, 0);
m_screenDialog->setWindowFlag(Qt::WindowType::WindowStaysOnBottomHint);
#ifdef Q_OS_WIN
m_screenDialog->winId();
QWindowsWindowFunctions::setHasBorderInFullScreen(m_screenDialog->windowHandle(), true);
#endif
m_screenDialog->activateWindow();
m_screenDialog->show();
}
}
+59
View File
@@ -0,0 +1,59 @@
#pragma once
#include "lts_multi_monitor_export.h"
#include <QWidget>
#include <QRect>
class QSplitter;
class QHBoxLayout;
namespace LtsUtils { class Promise; }
namespace LtsMultiMonitor
{
class LtsScreenContainer;
class LTSMULTIMONITOR_EXPORT LtsScreenBase : public QObject
{
Q_OBJECT
public:
enum WidgetType
{
MainWidget,
SecondaryWidget,
None,
};
LtsScreenBase(QRect screenGeo, int screenId, bool debugMargins, const QString &serial);
const QRect &screenRect() const { return m_screenRect; }
int screenId() const { return m_screenId; }
const QString serialNumber() const { return m_serial; }
QWidget *screenDialog() const { return m_screenDialog; }
virtual int screenType() const = 0;
virtual int containerIdOfWidget(QWidget *widget) const noexcept(false) = 0;
virtual LtsScreenContainer *putWidget(QWidget *widget, int screenPart = -1 ) noexcept(false) = 0;
virtual LtsScreenContainer *containerOfWidget(QWidget *widget) noexcept(false) = 0;
virtual bool isEmpty() const = 0;
virtual bool isIrreplaceable() const = 0;
virtual void check() {}
virtual bool hasWidget(QWidget *widget) const = 0;
virtual void switchToTemp(WidgetType ) {}
virtual void finalizeSwitch() {}
virtual void revertSwitch() {}
protected:
QWidget *m_screenDialog;
private:
int m_screenId;
QString m_serial;
QRect m_screenRect;
};
}
+555
View File
@@ -0,0 +1,555 @@
#include "lts_screen_container.h"
#include "lts_dummy_widget.h"
#include <LtsWidgets/lts_base_layout_widget.h>
#include <QHBoxLayout>
#include <QResizeEvent>
#include <QRect>
#include <QTimer>
#include <QDebug>
namespace LtsMultiMonitor
{
QString LtsScreenContainer::geoStr() const
{
return QStringLiteral("%1:%2:")
.arg(QString::number(m_screenGeo.x()).rightJustified(4, QLatin1Char(' ')))
.arg(QString::number(m_screenGeo.y()).rightJustified(4, QLatin1Char(' ')))
;
}
LtsScreenContainer::LtsScreenContainer(QRect screenGeo)
: m_layout(new QHBoxLayout)
, m_screenGeo(screenGeo)
{
m_layout->setMargin(0);
m_layout->setSpacing(0);
m_layout->setStretch(0, 999);
setContentsMargins(0, 0, 0, 0);
vanish();
setLayout(m_layout);
QTimer *t = new QTimer(this);
t->setInterval(3000);
#ifdef LTS_DEBUG
t->start();
#endif
connect(t, &QTimer::timeout,
this, [this, screenGeo]()
{
QString old(QStringLiteral("<#!UNKNOWN!#>"));
if (m_oldActiveWidget == nullptr)
old = QStringLiteral("null");
else if (m_oldActiveWidget == &m_mainWidget)
old = QStringLiteral("MAIN");
else if (m_oldActiveWidget == &m_secondaryWidget)
old = QStringLiteral("SECONDARY");
});
}
bool LtsScreenContainer::isInactiveWidgetOccupied() const
{
if (m_activeWidget == &m_mainWidget && m_secondaryWidget != nullptr)
return true;
if (m_activeWidget == &m_secondaryWidget && m_mainWidget != nullptr)
return true;
return false;
}
QIcon LtsScreenContainer::mainWindowIcon() const
{
if (m_mainWidget != nullptr)
return m_mainWidget->windowIcon();
return {};
}
QIcon LtsScreenContainer::secondaryWindowIcon() const
{
if (m_secondaryWidget != nullptr)
return m_secondaryWidget->windowIcon();
return {};
}
bool LtsScreenContainer::mainAndSecondaryOccupied() const
{
return (m_mainWidget != nullptr && m_secondaryWidget != nullptr);
}
LtsScreenBase::WidgetType LtsScreenContainer::activeWidgetType() const
{
if (m_activeWidget == &m_mainWidget)
return LtsScreenBase::WidgetType::MainWidget;
if (m_activeWidget == &m_secondaryWidget)
return LtsScreenBase::WidgetType::SecondaryWidget;
assert(false);
return LtsScreenBase::WidgetType::None;
}
void LtsScreenContainer::toggle()
{
switchToTemp((*m_activeWidget == m_mainWidget) ? LtsScreenBase::WidgetType::SecondaryWidget : LtsScreenBase::WidgetType::MainWidget);
QWidget *w = activeWidget();
assert(w != nullptr);
if (w == nullptr)
{
revertSwitch();
return;
}
if (!tryPutDummyUnmanaged(w))
w->show();
finalizeSwitch();
}
bool LtsScreenContainer::isIrreplaceable() const
{
if (m_activeWidget == nullptr)
return false;
auto *blw = qobject_cast<LtsWidgets::LtsBaseLayoutWidget *>(activeWidget());
if (blw == nullptr)
return false;
return blw->isIrreplaceable();
}
QWidget *LtsScreenContainer::activeWidget() const
{
assert(m_activeWidget != nullptr);
return *m_activeWidget;
}
QWidget **LtsScreenContainer::activeWidgetPtr()
{
assert(m_activeWidget != nullptr);
return m_activeWidget;
}
void LtsScreenContainer::vanish()
{
return;
m_layout->setParent(nullptr);
}
void LtsScreenContainer::reappear()
{
return;
setAttribute(Qt::WA_TranslucentBackground, false);
if (m_layout->parent() == nullptr)
setLayout(m_layout);
}
QWidget *LtsScreenContainer::stealWidget() noexcept(false)
{
QWidget **widgetPtr = activeWidgetPtr();
QWidget *widget = *widgetPtr;
if (widget == nullptr)
{
throw "stealWidget: no widget to steal";
}
widget->setParent(nullptr);
vanish();
disconnect(widget, &QWidget::destroyed,
this, &LtsScreenContainer::slotChildDestroyed);
QWidget *oldWidget = widget;
*widgetPtr = nullptr;
return oldWidget;
}
bool LtsScreenContainer::hasWidget(QWidget *widget) const
{
if (m_mainWidget != nullptr && m_mainWidget == widget)
return true;
if (m_secondaryWidget != nullptr && m_secondaryWidget == widget)
return true;
return false;
}
bool LtsScreenContainer::isEmpty() const
{
QWidget **currentWidgetPtr = m_activeWidget;
if (currentWidgetPtr == nullptr)
return true;
return (*currentWidgetPtr == nullptr);
}
bool LtsScreenContainer::hasMainWidget()
{
return m_mainWidget != nullptr;
}
bool LtsScreenContainer::hasSecondaryWidget()
{
return m_secondaryWidget != nullptr;
}
bool LtsScreenContainer::tryPutDummyUnmanaged(QWidget *widget)
{
auto *dummy = qobject_cast<FullscreenVideoDummyWidget *>(widget);
if (dummy == nullptr)
return false;
QRect r(mapToGlobal(rect().topLeft()), rect().size());
emit dummy->signalWidgetPlaced(r);
emit signalSetCornerIcons();
return true;
}
void LtsScreenContainer::switchToTemp(LtsScreenBase::WidgetType widgetType)
{
Q_ASSERT(widgetType != LtsScreenBase::WidgetType::None);
if ((m_activeWidget == &m_mainWidget && widgetType == LtsScreenBase::WidgetType::MainWidget) ||
(m_activeWidget == &m_secondaryWidget && widgetType == LtsScreenBase::WidgetType::SecondaryWidget))
{
m_nullSwitchActive = true;
return;
}
if (widgetType == LtsScreenBase::WidgetType::MainWidget)
m_oldActiveWidget = &m_secondaryWidget;
else if (widgetType == LtsScreenBase::WidgetType::SecondaryWidget)
m_oldActiveWidget = &m_mainWidget;
else
Q_ASSERT(false);
m_activeWidget = (widgetType == LtsScreenBase::WidgetType::SecondaryWidget ? &m_secondaryWidget : &m_mainWidget);
}
void LtsScreenContainer::finalizeSwitch()
{
QWidget **oldActiveWidget = m_oldActiveWidget;
m_oldActiveWidget = nullptr;
if (m_nullSwitchActive)
{
m_nullSwitchActive = false;
return;
}
if (oldActiveWidget == nullptr)
{
return;
}
if (*oldActiveWidget == nullptr)
{
return;
}
QWidget *widget = *oldActiveWidget;
auto *dummy = qobject_cast<FullscreenVideoDummyWidget *>(widget);
if (dummy != nullptr)
{
dummy->hideVideo();
}
else
{
widget->hide();
}
QWidget *widget2 = *m_activeWidget;
auto *dummy2 = qobject_cast<FullscreenVideoDummyWidget *>(widget2);
if (dummy2 != nullptr)
{
dummy2->showVideo();
}
emit signalSetCornerIcons();
}
void LtsScreenContainer::revertSwitch()
{
QWidget **oldActiveWidgetBackup = m_oldActiveWidget;
m_oldActiveWidget = nullptr;
if (m_nullSwitchActive)
{
m_nullSwitchActive = false;
return;
}
if (oldActiveWidgetBackup == nullptr)
return;
m_activeWidget = oldActiveWidgetBackup;
}
void LtsScreenContainer::setWidget(QWidget *widget)
{
QWidget **widgetPtr = activeWidgetPtr();
qWarning() << geoStr() << "setWidget: m_activeWidget" << m_activeWidget;
QWidget *currentWidget = *widgetPtr;
Q_ASSERT(currentWidget == nullptr);
*widgetPtr = widget;
reappear();
connect(widget, &QWidget::destroyed,
this, &LtsScreenContainer::slotChildDestroyed,
Qt::UniqueConnection);
if (tryPutDummyUnmanaged(widget))
return;
m_layout->addWidget(widget);
widget->show();
emit signalSetCornerIcons();
}
void LtsScreenContainer::slotChildDestroyed()
{
if (sender() == static_cast<QObject *>(m_mainWidget))
{
m_mainWidget = nullptr;
qWarning() << geoStr() << "m_mainWidget set to nullptr!";
if (*m_activeWidget == m_mainWidget)
{
qWarning() << "slotChildDestroyed: switching to sec";
switchToTemp(LtsScreenBase::WidgetType::SecondaryWidget);
QWidget *widget = activeWidget();
if (widget != nullptr)
{
auto *dummy = qobject_cast<FullscreenVideoDummyWidget *>(widget);
if (dummy != nullptr)
{
QRect r(mapToGlobal(rect().topLeft()), rect().size());
qWarning() << geoStr() << "LtsScreenContainer::slotChildDestroyed => (main) dummy->signalWidgetPlaced";
emit dummy->signalWidgetPlaced(r);
}
else
{
widget->show();
}
}
finalizeSwitch();
}
}
else if (sender() == static_cast<QObject *>(m_secondaryWidget))
{
m_secondaryWidget = nullptr;
qWarning() << geoStr() << "m_secondaryWidget set to nullptr!";
if (*m_activeWidget == m_secondaryWidget)
{
qWarning() << "slotChildDestroyed: switching to main";
switchToTemp(LtsScreenBase::WidgetType::MainWidget);
QWidget *widget = activeWidget();
if (widget != nullptr)
{
auto *dummy = qobject_cast<FullscreenVideoDummyWidget *>(widget);
if (dummy != nullptr)
{
QRect r(mapToGlobal(rect().topLeft()), rect().size());
qWarning() << geoStr() << "LtsScreenContainer::slotChildDestroyed => (sec) dummy->signalWidgetPlaced";
emit dummy->signalWidgetPlaced(r);
}
else
{
widget->show();
}
}
finalizeSwitch();
}
}
else
{
qWarning() << geoStr() << "slotChildDestroyed NOT received from any known widget !!";
Q_ASSERT(false);
}
vanish();
emit check();
}
QWidget *LtsScreenContainer::widget() noexcept(false)
{
QWidget **widgetPtr = m_activeWidget;
if (widgetPtr != nullptr && *widgetPtr != nullptr)
return *widgetPtr;
throw "no widget in container";
}
}
+68
View File
@@ -0,0 +1,68 @@
#pragma once
#include "lts_screen_base.h"
#include <lts_multi_monitor_export.h>
#include <QWidget>
#include <QRect>
class QHBoxLayout;
namespace LtsMultiMonitor
{
class LTSMULTIMONITOR_EXPORT LtsScreenContainer : public QWidget
{
Q_OBJECT
public:
LtsScreenContainer(QRect screenGeo);
bool isIrreplaceable() const;
bool isEmpty() const;
bool hasMainWidget();
bool hasSecondaryWidget();
void setWidget(QWidget *widget);
bool hasWidget(QWidget *widget) const;
QWidget *widget() noexcept(false);
QWidget *stealWidget() noexcept(false);
void switchToTemp(LtsScreenBase::WidgetType widgetType);
void finalizeSwitch();
void revertSwitch();
bool mainAndSecondaryOccupied() const;
QIcon mainWindowIcon() const;
QIcon secondaryWindowIcon() const;
LtsScreenBase::WidgetType activeWidgetType() const;
bool isInactiveWidgetOccupied() const;
signals:
void check();
void signalSetCornerIcons();
private:
QHBoxLayout *m_layout { nullptr };
QWidget *m_mainWidget { nullptr };
QWidget *m_secondaryWidget { nullptr };
QWidget **m_activeWidget { nullptr };
QWidget **m_oldActiveWidget { nullptr };
bool m_nullSwitchActive { false };
QRect m_screenGeo;
QString geoStr() const;
bool tryPutDummyUnmanaged(QWidget *widget);
void vanish();
void reappear();
QWidget *activeWidget() const;
QWidget **activeWidgetPtr();
public slots:
void toggle();
private slots:
void slotChildDestroyed();
};
}
+201
View File
@@ -0,0 +1,201 @@
#include "lts_screen_normal.h"
#include "lts_dummy_widget.h"
#include "lts_screen_container.h"
#include "lts_magic_corner.h"
#include <LtsWidgets/lts_base_layout_widget.h>
#include <QDebug>
#include <QSplitter>
#include <QHBoxLayout>
#ifdef Q_OS_WIN
#include <QtPlatformHeaders/qwindowswindowfunctions.h>
#endif
namespace LtsMultiMonitor
{
LtsScreenNormal::LtsScreenNormal(QRect screenGeo, int screenId, bool debugMargins, const QString &serial)
: LtsScreenBase(screenGeo, screenId, debugMargins, serial)
, m_childContainer(new LtsScreenContainer(screenGeo))
, m_corner(new LtsMagicCorner(screenGeo))
{
connect(m_childContainer, &LtsScreenContainer::check,
this, &LtsScreenNormal::check);
auto *theLayout = new QHBoxLayout;
theLayout->setContentsMargins(0, 0, 0, 0);
theLayout->setMargin(0);
theLayout->setSpacing(0);
theLayout->setStretch(0, 999);
theLayout->addWidget(m_childContainer);
m_screenDialog->setLayout(theLayout);
m_corner->hide();
connect(m_corner, &LtsMagicCorner::toggle,
this, [this]()
{
m_childContainer->toggle();
m_corner->setActiveWidgetType(m_childContainer->activeWidgetType());
setCornerIcons();
});
connect(m_corner, &LtsMagicCorner::signalMakeAllSwole,
this, &LtsScreenNormal::signalMakeAllSwole);
connect(this, &LtsScreenNormal::signalMakeSwole,
m_corner, &LtsMagicCorner::makeSwole);
connect(m_childContainer, &LtsScreenContainer::signalSetCornerIcons,
this, &LtsScreenNormal::setCornerIcons);
}
LtsScreenNormal::~LtsScreenNormal()
{
m_corner->deleteLater();
}
void LtsScreenNormal::setCornerIcons()
{
m_corner->setActiveWidgetType(m_childContainer->activeWidgetType());
m_corner->setIcon(m_childContainer->mainWindowIcon(), LtsScreenBase::WidgetType::MainWidget);
m_corner->setIcon(m_childContainer->secondaryWindowIcon(), LtsScreenBase::WidgetType::SecondaryWidget);
}
void LtsScreenNormal::check()
{
m_childContainer->mainAndSecondaryOccupied() ? m_corner->show() : m_corner->hide();
}
LtsScreenContainer *LtsScreenNormal::containerOfWidget(QWidget *widget)
{
if (m_childContainer->hasWidget(widget))
return m_childContainer;
throw "widget is not present on this container";
}
void LtsScreenNormal::hideMagicCorner(bool hide)
{
m_corner->setFreezed(hide);
}
bool LtsScreenNormal::isIrreplaceable() const
{
return m_childContainer->isIrreplaceable();
}
int LtsScreenNormal::containerIdOfWidget(QWidget *widget) const noexcept(false)
{
if (m_childContainer->hasWidget(widget))
return 0;
throw "widget not on this screen";
}
LtsScreenContainer *LtsScreenNormal::putWidget(QWidget *widget, int ) noexcept(false)
{
if (!isEmpty())
throw "cannot put widget as container is non-empty";
putWidgetUnmanaged(widget);
return m_childContainer;
}
bool LtsScreenNormal::hasWidget(QWidget *widget) const
{
return (m_childContainer->hasWidget(widget));
}
void LtsScreenNormal::putWidgetUnmanaged(QWidget *widget)
{
m_childContainer->setWidget(widget);
setCornerIcons();
}
void LtsScreenNormal::slotOverlayDestroyed()
{
m_screenDialog->show();
}
bool LtsScreenNormal::isEmpty() const
{
return m_childContainer->isEmpty();
}
void LtsScreenNormal::switchToTemp(LtsScreenBase::WidgetType widgetType)
{
m_childContainer->switchToTemp(widgetType);
}
void LtsScreenNormal::finalizeSwitch()
{
m_childContainer->finalizeSwitch();
}
void LtsScreenNormal::revertSwitch()
{
m_childContainer->revertSwitch();
}
}
+58
View File
@@ -0,0 +1,58 @@
#pragma once
#include "lts_screen_base.h"
#include <LtsMultiMonitor/lts_multi_monitor_export.h>
#include <QWidget>
#include <QRect>
class QSplitter;
class QHBoxLayout;
namespace LtsMultiMonitor
{
class LtsMagicCorner;
class LTSMULTIMONITOR_EXPORT LtsScreenNormal : public LtsScreenBase
{
Q_OBJECT
public:
LtsScreenNormal(QRect screenGeo, int screenId, bool debugMargins, const QString &serial);
~LtsScreenNormal();
int screenType() const override { return 0; }
int containerIdOfWidget(QWidget *widget) const noexcept(false) override;
LtsScreenContainer *child() const { return m_childContainer; }
LtsScreenContainer *putWidget(QWidget *widget, int) noexcept(false) override;
LtsScreenContainer *containerOfWidget(QWidget *widget) noexcept(false) override;
void hideMagicCorner(bool hide);
bool isEmpty() const override;
bool isIrreplaceable() const override;
void putWidgetUnmanaged(QWidget *widget);
bool hasWidget(QWidget *widget) const override;
void switchToTemp(WidgetType widgetType) override;
void finalizeSwitch() override;
void revertSwitch() override;
void check() override;
private:
LtsScreenContainer *m_childContainer { nullptr };
LtsMagicCorner *m_corner;
void swapLeftRight();
bool tryPutDummyUnmanaged(QWidget *widget);
signals:
void signalMakeAllSwole();
void signalMakeSwole();
private slots:
void slotOverlayDestroyed();
void setCornerIcons();
};
}
+236
View File
@@ -0,0 +1,236 @@
#include "lts_screen_wide.h"
#include "lts_dummy_widget.h"
#include "lts_screen_container.h"
#include <LtsWidgets/lts_base_layout_widget.h>
#include <QDebug>
#include <QSplitter>
#include <QHBoxLayout>
#include <QTimer>
#ifdef Q_OS_WIN
#include <QtPlatformHeaders/qwindowswindowfunctions.h>
#endif
namespace LtsMultiMonitor
{
LtsScreenWide::LtsScreenWide(const QRect &screenGeo, int screenId, bool debugMargins, const QString &serial)
: LtsScreenBase(screenGeo, screenId, debugMargins, serial)
, m_childContainerMain(new LtsScreenContainer(screenGeo))
, m_childContainerLeft(new LtsScreenContainer(screenGeo))
, m_childContainerRight(new LtsScreenContainer(screenGeo))
{
connect(m_childContainerMain, &LtsScreenContainer::check,
this, &LtsScreenWide::check);
connect(m_childContainerLeft, &LtsScreenContainer::check,
this, &LtsScreenWide::check);
connect(m_childContainerRight, &LtsScreenContainer::check,
this, &LtsScreenWide::check);
auto *theLayout = new QHBoxLayout;
theLayout->setContentsMargins(0, 0, 0, 0);
theLayout->setMargin(0);
theLayout->setSpacing(0);
theLayout->setStretch(0, 9999);
m_splitter = new QSplitter;
m_splitter->setContentsMargins(0, 0, 0, 0);
m_splitter->addWidget(m_childContainerLeft);
m_splitter->addWidget(m_childContainerRight);
theLayout->addWidget(m_splitter);
theLayout->addWidget(m_childContainerMain);
m_screenDialog->setLayout(theLayout);
m_splitter->hide();
}
void LtsScreenWide::putWidgetUnmanagedMain(QWidget *widget)
{
m_childContainerMain->setWidget(widget);
}
void LtsScreenWide::putWidgetUnmanagedRight(QWidget *widget)
{
m_childContainerRight->setWidget(widget);
}
void LtsScreenWide::putWidgetUnmanagedLeft(QWidget *widget)
{
m_childContainerLeft->setWidget(widget);
}
bool LtsScreenWide::hasWidget(QWidget *widget) const
{
return (m_childContainerMain->hasWidget(widget) ||
m_childContainerLeft->hasWidget(widget) ||
m_childContainerRight->hasWidget(widget));
}
bool LtsScreenWide::isIrreplaceable() const
{
return (childLeft()->isIrreplaceable() && childRight()->isIrreplaceable() && childMain()->isIrreplaceable());
}
bool LtsScreenWide::isEmpty() const
{
return (m_childContainerLeft->isEmpty() && m_childContainerRight->isEmpty() && m_childContainerMain->isEmpty());
}
int LtsScreenWide::containerIdOfWidget(QWidget *widget) const noexcept(false)
{
if (m_childContainerMain->hasWidget(widget))
return 0;
if (m_childContainerLeft->hasWidget(widget))
return 1;
if (m_childContainerRight->hasWidget(widget))
return 2;
throw "widget not on this screen";
}
LtsScreenContainer *LtsScreenWide::containerOfWidget(QWidget *widget) noexcept(false)
{
if (m_childContainerMain->hasWidget(widget))
return m_childContainerMain;
if (m_childContainerLeft->hasWidget(widget))
return m_childContainerLeft;
if (m_childContainerRight->hasWidget(widget))
return m_childContainerRight;
throw "widget is not present on this container";
}
LtsScreenContainer *LtsScreenWide::putWidget(QWidget *widget, int screenPart) noexcept(false)
{
if (screenPart == -1)
{
if (!isEmpty())
throw "cannot put widget as at least one container is occupied and screen part was not specified";
putWidgetUnmanagedMain(widget);
return m_childContainerMain;
}
switch (screenPart)
{
case 0:
{
if (!m_childContainerMain->isEmpty())
throw "cannot put widget as main container is already occupied";
putWidgetUnmanagedMain(widget);
return m_childContainerMain;
}
case 1:
{
if (!m_childContainerLeft->isEmpty())
throw "cannot put widget as left container is already occupied";
if (!m_childContainerMain->isEmpty())
putWidgetUnmanagedRight(m_childContainerMain->stealWidget());
putWidgetUnmanagedLeft(widget);
return m_childContainerLeft;
}
case 2:
{
if (!m_childContainerRight->isEmpty())
throw "cannot put widget as right container is already occupied";
if (!m_childContainerMain->isEmpty())
putWidgetUnmanagedLeft(m_childContainerMain->stealWidget());
putWidgetUnmanagedRight(widget);
return m_childContainerRight;
}
default:
{
throw "unknown screen part id";
}
}
}
void LtsScreenWide::check()
{
Q_ASSERT( (!m_childContainerMain->isEmpty() && m_childContainerLeft->isEmpty() && m_childContainerRight->isEmpty()) || m_childContainerMain->isEmpty() );
if (m_childContainerMain->isEmpty())
{
if (m_childContainerLeft->isEmpty() && !m_childContainerRight->isEmpty())
{
try
{
QWidget *widget = m_childContainerRight->stealWidget();
m_childContainerMain->setWidget(widget);
}
catch(...)
{
}
}
else if (!m_childContainerLeft->isEmpty() && m_childContainerRight->isEmpty())
{
try
{
QWidget *widget = m_childContainerLeft->stealWidget();
m_childContainerMain->setWidget(widget);
}
catch(...)
{
}
}
}
if (!m_childContainerMain->isEmpty())
{
m_childContainerMain->show();
m_splitter->hide();
return;
}
m_childContainerMain->hide();
m_splitter->setVisible(!m_childContainerLeft->isEmpty() || !m_childContainerRight->isEmpty());
m_childContainerLeft->setVisible(!m_childContainerLeft->isEmpty());
m_childContainerRight->setVisible(!m_childContainerRight->isEmpty());
}
}
+51
View File
@@ -0,0 +1,51 @@
#pragma once
#include "lts_screen_base.h"
#include <LtsMultiMonitor/lts_multi_monitor_export.h>
#include <QWidget>
#include <QRect>
class QSplitter;
class QHBoxLayout;
namespace LtsMultiMonitor
{
class LTSMULTIMONITOR_EXPORT LtsScreenWide : public LtsScreenBase
{
Q_OBJECT
public:
LtsScreenWide(const QRect &screenGeo, int screenId, bool debugMargins, const QString &serial);
int screenType() const override { return 1; }
LtsScreenContainer *containerOfWidget(QWidget *widget) noexcept(false) override;
bool isEmpty() const override;
LtsScreenContainer *childLeft() const { return m_childContainerLeft; }
LtsScreenContainer *childRight() const { return m_childContainerRight; }
LtsScreenContainer *childMain() const { return m_childContainerMain; }
void putWidgetUnmanagedMain(QWidget *widget);
void putWidgetUnmanagedLeft(QWidget *widget);
void putWidgetUnmanagedRight(QWidget *widget);
bool isIrreplaceable() const override;
bool hasWidget(QWidget *widget) const override;
LtsScreenContainer *putWidget(QWidget *widget, int screenPart) noexcept(false) override;
int containerIdOfWidget(QWidget *widget) const noexcept(false) override;
public slots:
void check() override;
private:
LtsScreenContainer *m_childContainerMain;
LtsScreenContainer *m_childContainerLeft;
LtsScreenContainer *m_childContainerRight;
QSplitter *m_splitter;
void swapLeftRight();
};
}