mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-12-23 01:55:48 -05:00
Add buttons to stack MDI windows vertically and put in tabs.
Use right click to auto-stack sub-windows, rather than having a dedicated button. Allow maximize button to make window full screen, if already maximized. Add title to device windows, for when displayed in tabs. Add menu button to workspace toolbar, for Android only, to avoid having menu bar, which takes up a lot of space. Add configuration presets button to workspace toolbar. Add icons for window arangement
This commit is contained in:
parent
7f720a369e
commit
d1c67c971e
@ -65,6 +65,13 @@ QByteArray Configuration::serialize() const
|
||||
s.writeBool(301 + i, m_workspaceAutoStackOptions[i]);
|
||||
}
|
||||
|
||||
nitems = m_workspaceTabSubWindowsOptions.size() < 99 ? m_workspaceTabSubWindowsOptions.size() : 99;
|
||||
s.writeS32(400, nitems);
|
||||
|
||||
for (int i = 0; i < nitems; i++) {
|
||||
s.writeBool(401 + i, m_workspaceTabSubWindowsOptions[i]);
|
||||
}
|
||||
|
||||
return s.final();
|
||||
}
|
||||
|
||||
@ -113,6 +120,14 @@ bool Configuration::deserialize(const QByteArray& data)
|
||||
d.readBool(301 + i, &m_workspaceAutoStackOptions.back());
|
||||
}
|
||||
|
||||
d.readS32(400, &nitems, 0);
|
||||
|
||||
for (int i = 0; i < nitems; i++)
|
||||
{
|
||||
m_workspaceTabSubWindowsOptions.push_back(true);
|
||||
d.readBool(401 + i, &m_workspaceTabSubWindowsOptions.back());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -128,4 +143,5 @@ void Configuration::clearData()
|
||||
m_featureSetPreset.clearFeatures();
|
||||
m_workspaceGeometries.clear();
|
||||
m_workspaceAutoStackOptions.clear();
|
||||
m_workspaceTabSubWindowsOptions.clear();
|
||||
}
|
||||
|
@ -52,6 +52,8 @@ public:
|
||||
const QList<QByteArray>& getWorkspaceGeometries() const { return m_workspaceGeometries; }
|
||||
QList<bool>& getWorkspaceAutoStackOptions() { return m_workspaceAutoStackOptions; }
|
||||
const QList<bool>& getWorkspaceAutoStackOptions() const { return m_workspaceAutoStackOptions; }
|
||||
QList<bool>& getWorkspaceTabSubWindowsOptions() { return m_workspaceTabSubWindowsOptions; }
|
||||
const QList<bool>& getWorkspaceTabSubWindowsOptions() const { return m_workspaceTabSubWindowsOptions; }
|
||||
FeatureSetPreset& getFeatureSetPreset() { return m_featureSetPreset; }
|
||||
const FeatureSetPreset& getFeatureSetPreset() const { return m_featureSetPreset; }
|
||||
QList<Preset>& getDeviceSetPresets() { return m_deviceSetPresets; }
|
||||
@ -76,6 +78,7 @@ private:
|
||||
QString m_description;
|
||||
QList<QByteArray> m_workspaceGeometries;
|
||||
QList<bool> m_workspaceAutoStackOptions;
|
||||
QList<bool> m_workspaceTabSubWindowsOptions;
|
||||
FeatureSetPreset m_featureSetPreset;
|
||||
QList<Preset> m_deviceSetPresets;
|
||||
};
|
||||
|
@ -26,11 +26,13 @@
|
||||
#include <QObjectCleanupHandler>
|
||||
#include <QDesktopServices>
|
||||
#include <QOpenGLWidget>
|
||||
#include <QMdiArea>
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "gui/workspaceselectiondialog.h"
|
||||
#include "gui/devicesetselectiondialog.h"
|
||||
#include "gui/rollupcontents.h"
|
||||
#include "gui/dialogpositioner.h"
|
||||
|
||||
#include "channelgui.h"
|
||||
|
||||
@ -42,7 +44,8 @@ ChannelGUI::ChannelGUI(QWidget *parent) :
|
||||
m_contextMenuType(ContextMenuNone),
|
||||
m_drag(false),
|
||||
m_resizer(this),
|
||||
m_disableResize(false)
|
||||
m_disableResize(false),
|
||||
m_mdi(nullptr)
|
||||
{
|
||||
qDebug("ChannelGUI::ChannelGUI");
|
||||
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
|
||||
@ -92,7 +95,7 @@ ChannelGUI::ChannelGUI(QWidget *parent) :
|
||||
m_maximizeButton->setFixedSize(20, 20);
|
||||
QIcon maximizeIcon(":/maximize.png");
|
||||
m_maximizeButton->setIcon(maximizeIcon);
|
||||
m_maximizeButton->setToolTip("Adjust window to maximum size");
|
||||
m_maximizeButton->setToolTip("Adjust window to maximum size in workspace");
|
||||
|
||||
m_hideButton = new QPushButton();
|
||||
m_hideButton->setFixedSize(20, 20);
|
||||
@ -311,7 +314,9 @@ void ChannelGUI::onWidgetRolled(QWidget *widget, bool show)
|
||||
// onWidgetRolled being called twice.
|
||||
// We need to make sure we don't save widget heights while this occurs. The
|
||||
// window manager will take care of maximizing/restoring the window size.
|
||||
if (!m_disableResize)
|
||||
// We do need to resize when a widget is rolled up, but we also need to avoid
|
||||
// resizing when a window is maximized when first shown in tabbed layout
|
||||
if (!m_disableResize && !isMaximized())
|
||||
{
|
||||
if (show)
|
||||
{
|
||||
@ -379,6 +384,9 @@ void ChannelGUI::sizeToContents()
|
||||
size.setHeight(size.height() + getAdditionalHeight());
|
||||
size.setWidth(size.width() + m_resizer.m_gripSize * 2);
|
||||
setMinimumSize(size);
|
||||
|
||||
// Restrict size of window to size of desktop
|
||||
DialogPositioner::sizeToDesktop(this);
|
||||
}
|
||||
|
||||
void ChannelGUI::duplicateChannel()
|
||||
@ -397,9 +405,24 @@ void ChannelGUI::openMoveToDeviceSetDialog()
|
||||
}
|
||||
|
||||
void ChannelGUI::maximizeWindow()
|
||||
{
|
||||
// If maximize is pressed when maximized, go full screen
|
||||
if (isMaximized())
|
||||
{
|
||||
m_mdi = mdiArea();
|
||||
if (m_mdi) {
|
||||
m_mdi->removeSubWindow(this);
|
||||
}
|
||||
showNormal(); // If we don't go back to normal first, window doesn't get bigger
|
||||
showFullScreen();
|
||||
m_shrinkButton->setToolTip("Adjust window to maximum size in workspace");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_disableResize = true;
|
||||
showMaximized();
|
||||
m_shrinkButton->setToolTip("Restore window to normal");
|
||||
m_maximizeButton->setToolTip("Make window full screen");
|
||||
m_disableResize = false;
|
||||
// QOpenGLWidget widgets don't always paint properly first time after being maximized,
|
||||
// so force an update. Should really fix why they aren't painted properly in the first place
|
||||
@ -408,14 +431,29 @@ void ChannelGUI::maximizeWindow()
|
||||
widget->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelGUI::shrinkWindow()
|
||||
{
|
||||
qDebug("ChannelGUI::shrinkWindow");
|
||||
if (isMaximized())
|
||||
// If m_normalParentWidget, window was made full screen
|
||||
if (m_mdi)
|
||||
{
|
||||
m_disableResize = true;
|
||||
showNormal();
|
||||
m_mdi->addSubWindow(this);
|
||||
show();
|
||||
showMaximized();
|
||||
m_shrinkButton->setToolTip("Restore window to normal");
|
||||
m_disableResize = false;
|
||||
m_mdi = nullptr;
|
||||
}
|
||||
else if (isMaximized())
|
||||
{
|
||||
m_disableResize = true;
|
||||
showNormal();
|
||||
m_shrinkButton->setToolTip("Adjust window to minimum size");
|
||||
m_maximizeButton->setToolTip("Adjust window to maximum size in workspace");
|
||||
m_disableResize = false;
|
||||
}
|
||||
else
|
||||
|
@ -141,6 +141,7 @@ private:
|
||||
QMap<QWidget*, int> m_heightsMap;
|
||||
FramelessWindowResizer m_resizer;
|
||||
bool m_disableResize;
|
||||
QMdiArea *m_mdi; // Saved pointer to MDI when in full screen mode
|
||||
|
||||
private slots:
|
||||
void activateSettingsDialog();
|
||||
|
@ -162,7 +162,7 @@ DeviceGUI::DeviceGUI(QWidget *parent) :
|
||||
m_topLayout->addWidget(m_maximizeButton);
|
||||
m_topLayout->addWidget(m_closeButton);
|
||||
|
||||
m_centerLayout = new QHBoxLayout();
|
||||
m_centerLayout = new QVBoxLayout();
|
||||
m_centerLayout->setContentsMargins(0, 0, 0, 0);
|
||||
m_contents = new QWidget(); // Do not delete! Done in child's destructor with "delete ui"
|
||||
m_centerLayout->addWidget(m_contents);
|
||||
@ -412,6 +412,7 @@ void DeviceGUI::deviceSetPresetsDialog()
|
||||
|
||||
void DeviceGUI::setTitle(const QString& title)
|
||||
{
|
||||
setWindowTitle(title + " Device");
|
||||
m_titleLabel->setText(title);
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
|
||||
#include "gui/channeladddialog.h"
|
||||
#include "gui/framelesswindowresizer.h"
|
||||
@ -32,7 +33,6 @@
|
||||
class QCloseEvent;
|
||||
class Message;
|
||||
class MessageQueue;
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
class QVBoxLayout;
|
||||
class QHBoxLayout;
|
||||
@ -87,6 +87,7 @@ protected:
|
||||
void mouseMoveEvent(QMouseEvent* event) override;
|
||||
void resetContextMenuType() { m_contextMenuType = ContextMenuNone; }
|
||||
int getAdditionalHeight() const { return 22 + 22; }
|
||||
void setStatus(const QString &status) { m_statusLabel->setText(status); }
|
||||
|
||||
DeviceUISet* m_deviceUISet;
|
||||
DeviceType m_deviceType;
|
||||
@ -122,7 +123,7 @@ private:
|
||||
QLabel *m_statusLabel;
|
||||
QVBoxLayout *m_layouts;
|
||||
QHBoxLayout *m_topLayout;
|
||||
QHBoxLayout *m_centerLayout;
|
||||
QVBoxLayout *m_centerLayout;
|
||||
QHBoxLayout *m_bottomLayout;
|
||||
QSizeGrip *m_sizeGripBottomRight;
|
||||
bool m_drag;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <QObjectCleanupHandler>
|
||||
#include <QDesktopServices>
|
||||
#include <QOpenGLWidget>
|
||||
#include <QMdiArea>
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "gui/workspaceselectiondialog.h"
|
||||
@ -37,7 +38,8 @@ FeatureGUI::FeatureGUI(QWidget *parent) :
|
||||
m_contextMenuType(ContextMenuNone),
|
||||
m_drag(false),
|
||||
m_resizer(this),
|
||||
m_disableResize(false)
|
||||
m_disableResize(false),
|
||||
m_mdi(nullptr)
|
||||
{
|
||||
qDebug("FeatureGUI::FeatureGUI");
|
||||
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
|
||||
@ -87,7 +89,7 @@ FeatureGUI::FeatureGUI(QWidget *parent) :
|
||||
m_maximizeButton->setFixedSize(20, 20);
|
||||
QIcon maximizeIcon(":/maximize.png");
|
||||
m_maximizeButton->setIcon(maximizeIcon);
|
||||
m_maximizeButton->setToolTip("Adjust window to maximum size");
|
||||
m_maximizeButton->setToolTip("Adjust window to maximum size in workspace");
|
||||
|
||||
m_closeButton = new QPushButton();
|
||||
m_closeButton->setFixedSize(20, 20);
|
||||
@ -264,7 +266,9 @@ void FeatureGUI::onWidgetRolled(QWidget *widget, bool show)
|
||||
// onWidgetRolled being called twice.
|
||||
// We need to make sure we don't save widget heights while this occurs. The
|
||||
// window manager will take care of maximizing/restoring the window size.
|
||||
if (!m_disableResize)
|
||||
// We do need to resize when a widget is rolled up, but we also need to avoid
|
||||
// resizing when a window is maximized when first shown in tabbed layout
|
||||
if (!m_disableResize && !isMaximized())
|
||||
{
|
||||
if (show)
|
||||
{
|
||||
@ -335,9 +339,24 @@ void FeatureGUI::sizeToContents()
|
||||
}
|
||||
|
||||
void FeatureGUI::maximizeWindow()
|
||||
{
|
||||
// If maximize is pressed when maximized, go full screen
|
||||
if (isMaximized())
|
||||
{
|
||||
m_mdi = mdiArea();
|
||||
if (m_mdi) {
|
||||
m_mdi->removeSubWindow(this);
|
||||
}
|
||||
showNormal(); // If we don't go back to normal first, window doesn't get bigger
|
||||
showFullScreen();
|
||||
m_shrinkButton->setToolTip("Adjust window to maximum size in workspace");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_disableResize = true;
|
||||
showMaximized();
|
||||
m_shrinkButton->setToolTip("Restore window to normal");
|
||||
m_maximizeButton->setToolTip("Make window full screen");
|
||||
m_disableResize = false;
|
||||
// QOpenGLWidget widgets don't always paint properly first time after being maximized,
|
||||
// so force an update. Should really fix why they aren't painted properly in the first place
|
||||
@ -346,14 +365,28 @@ void FeatureGUI::maximizeWindow()
|
||||
widget->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FeatureGUI::shrinkWindow()
|
||||
{
|
||||
qDebug("FeatureGUI::shrinkWindow");
|
||||
if (isMaximized())
|
||||
if (m_mdi)
|
||||
{
|
||||
m_disableResize = true;
|
||||
showNormal();
|
||||
m_mdi->addSubWindow(this);
|
||||
show();
|
||||
showMaximized();
|
||||
m_shrinkButton->setToolTip("Restore window to normal");
|
||||
m_disableResize = false;
|
||||
m_mdi = nullptr;
|
||||
}
|
||||
else if (isMaximized())
|
||||
{
|
||||
m_disableResize = true;
|
||||
showNormal();
|
||||
m_shrinkButton->setToolTip("Adjust window to minimum size");
|
||||
m_maximizeButton->setToolTip("Adjust window to maximum size in workspace");
|
||||
m_disableResize = false;
|
||||
}
|
||||
else
|
||||
|
@ -110,6 +110,7 @@ private:
|
||||
QMap<QWidget*, int> m_heightsMap;
|
||||
FramelessWindowResizer m_resizer;
|
||||
bool m_disableResize;
|
||||
QMdiArea *m_mdi; // Saved pointer to MDI when in full screen mode
|
||||
|
||||
private slots:
|
||||
void activateSettingsDialog();
|
||||
|
@ -27,10 +27,13 @@
|
||||
#include <QFrame>
|
||||
#include <QDebug>
|
||||
#include <QApplication>
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
|
||||
#include "gui/samplingdevicedialog.h"
|
||||
#include "gui/rollupcontents.h"
|
||||
#include "gui/buttonswitch.h"
|
||||
#include "gui/crightclickenabler.h"
|
||||
#include "channel/channelgui.h"
|
||||
#include "feature/featuregui.h"
|
||||
#include "device/devicegui.h"
|
||||
@ -42,8 +45,10 @@
|
||||
Workspace::Workspace(int index, QWidget *parent, Qt::WindowFlags flags) :
|
||||
QDockWidget(parent, flags),
|
||||
m_index(index),
|
||||
m_menuButton(nullptr),
|
||||
m_featureAddDialog(this),
|
||||
m_stacking(false),
|
||||
m_autoStack(false),
|
||||
m_userChannelMinWidth(0)
|
||||
{
|
||||
m_mdi = new QMdiArea(this);
|
||||
@ -64,6 +69,29 @@ Workspace::Workspace(int index, QWidget *parent, Qt::WindowFlags flags) :
|
||||
m_titleLabel->setStyleSheet("QLabel { background-color: rgb(128, 128, 128); qproperty-alignment: AlignCenter; }");
|
||||
m_titleLabel->setText(windowTitle());
|
||||
|
||||
#ifdef ANDROID
|
||||
m_menuButton = new QToolButton();
|
||||
QIcon menuIcon(":/listing.png");
|
||||
m_menuButton->setIcon(menuIcon);
|
||||
m_menuButton->setFixedSize(20, 20);
|
||||
m_menuButton->setPopupMode(QToolButton::InstantPopup);
|
||||
#endif
|
||||
|
||||
m_configurationPresetsButton = new QPushButton();
|
||||
QIcon configurationPresetsIcon(":/star.png");
|
||||
m_configurationPresetsButton->setIcon(configurationPresetsIcon);
|
||||
m_configurationPresetsButton->setToolTip("Configuration presets");
|
||||
m_configurationPresetsButton->setFixedSize(20, 20);
|
||||
|
||||
m_startStopButton = new ButtonSwitch();
|
||||
m_startStopButton->setCheckable(true);
|
||||
updateStartStopButton(false);
|
||||
m_startStopButton->setFixedSize(20, 20);
|
||||
|
||||
m_vline1 = new QFrame();
|
||||
m_vline1->setFrameShape(QFrame::VLine);
|
||||
m_vline1->setFrameShadow(QFrame::Sunken);
|
||||
|
||||
m_addRxDeviceButton = new QPushButton();
|
||||
QIcon addRxIcon(":/rx.png");
|
||||
m_addRxDeviceButton->setIcon(addRxIcon);
|
||||
@ -82,14 +110,9 @@ Workspace::Workspace(int index, QWidget *parent, Qt::WindowFlags flags) :
|
||||
m_addMIMODeviceButton->setToolTip("Add MIMO device");
|
||||
m_addMIMODeviceButton->setFixedSize(20, 20);
|
||||
|
||||
m_startStopButton = new ButtonSwitch();
|
||||
m_startStopButton->setCheckable(true);
|
||||
updateStartStopButton(false);
|
||||
m_startStopButton->setFixedSize(20, 20);
|
||||
|
||||
m_vline1 = new QFrame();
|
||||
m_vline1->setFrameShape(QFrame::VLine);
|
||||
m_vline1->setFrameShadow(QFrame::Sunken);
|
||||
m_vline2 = new QFrame();
|
||||
m_vline2->setFrameShape(QFrame::VLine);
|
||||
m_vline2->setFrameShadow(QFrame::Sunken);
|
||||
|
||||
m_addFeatureButton = new QPushButton();
|
||||
QIcon addFeatureIcon(":/tool_add.png");
|
||||
@ -103,9 +126,9 @@ Workspace::Workspace(int index, QWidget *parent, Qt::WindowFlags flags) :
|
||||
m_featurePresetsButton->setToolTip("Feature presets");
|
||||
m_featurePresetsButton->setFixedSize(20, 20);
|
||||
|
||||
m_vline2 = new QFrame();
|
||||
m_vline2->setFrameShape(QFrame::VLine);
|
||||
m_vline2->setFrameShadow(QFrame::Sunken);
|
||||
m_vline3 = new QFrame();
|
||||
m_vline3->setFrameShape(QFrame::VLine);
|
||||
m_vline3->setFrameShadow(QFrame::Sunken);
|
||||
|
||||
m_cascadeSubWindows = new QPushButton();
|
||||
QIcon cascadeSubWindowsIcon(":/cascade.png");
|
||||
@ -119,19 +142,26 @@ Workspace::Workspace(int index, QWidget *parent, Qt::WindowFlags flags) :
|
||||
m_tileSubWindows->setToolTip("Tile sub windows");
|
||||
m_tileSubWindows->setFixedSize(20, 20);
|
||||
|
||||
m_stackSubWindows = new QPushButton("S");
|
||||
//QIcon stackSubWindowsIcon(":/stack.png"); // FIXME
|
||||
//m_stackSubWindows->setIcon(stackSubWindowsIcon);
|
||||
m_stackSubWindows->setToolTip("Stack sub windows");
|
||||
m_stackSubWindows->setFixedSize(20, 20);
|
||||
m_stackVerticalSubWindows = new QPushButton();
|
||||
QIcon stackVerticalSubWindowsIcon(":/stackvertical.png");
|
||||
m_stackVerticalSubWindows->setIcon(stackVerticalSubWindowsIcon);
|
||||
m_stackVerticalSubWindows->setToolTip("Stack sub windows vertically");
|
||||
m_stackVerticalSubWindows->setFixedSize(20, 20);
|
||||
|
||||
m_autoStackSubWindows = new ButtonSwitch();
|
||||
m_autoStackSubWindows->setText("AS");
|
||||
m_autoStackSubWindows->setCheckable(true);
|
||||
//QIcon autoStackSubWindowsIcon(":/autostack.png"); // FIXME
|
||||
//m_autoStackSubWindows->setIcon(autoStackSubWindowsIcon);
|
||||
m_autoStackSubWindows->setToolTip("Automatically stack sub windows");
|
||||
m_autoStackSubWindows->setFixedSize(20, 20);
|
||||
m_stackSubWindows = new QPushButton();
|
||||
QIcon stackSubWindowsIcon(":/stackcolumns.png");
|
||||
m_stackSubWindows->setIcon(stackSubWindowsIcon);
|
||||
m_stackSubWindows->setToolTip("Stack sub windows in columns. Right click to stack automatically.");
|
||||
m_stackSubWindows->setFixedSize(20, 20);
|
||||
CRightClickEnabler *stackSubWindowsRightClickEnabler = new CRightClickEnabler(m_stackSubWindows);
|
||||
connect(stackSubWindowsRightClickEnabler, &CRightClickEnabler::rightClick, this, &Workspace::autoStackSubWindows);
|
||||
|
||||
m_tabSubWindows = new ButtonSwitch();
|
||||
QIcon tabSubWindowsIcon(":/tab.png");
|
||||
m_tabSubWindows->setIcon(tabSubWindowsIcon);
|
||||
m_tabSubWindows->setCheckable(true);
|
||||
m_tabSubWindows->setToolTip("Display sub windows in tabs");
|
||||
m_tabSubWindows->setFixedSize(20, 20);
|
||||
|
||||
m_normalButton = new QPushButton();
|
||||
QIcon normalIcon(":/dock.png");
|
||||
@ -146,21 +176,34 @@ Workspace::Workspace(int index, QWidget *parent, Qt::WindowFlags flags) :
|
||||
m_closeButton->setFixedSize(20, 20);
|
||||
|
||||
m_titleBarLayout->addWidget(m_titleLabel);
|
||||
if (m_menuButton) {
|
||||
m_titleBarLayout->addWidget(m_menuButton);
|
||||
}
|
||||
m_titleBarLayout->addWidget(m_configurationPresetsButton);
|
||||
m_titleBarLayout->addWidget(m_startStopButton);
|
||||
m_titleBarLayout->addWidget(m_vline1);
|
||||
m_titleBarLayout->addWidget(m_addRxDeviceButton);
|
||||
m_titleBarLayout->addWidget(m_addTxDeviceButton);
|
||||
m_titleBarLayout->addWidget(m_addMIMODeviceButton);
|
||||
m_titleBarLayout->addWidget(m_startStopButton);
|
||||
m_titleBarLayout->addWidget(m_vline1);
|
||||
m_titleBarLayout->addWidget(m_vline2);
|
||||
m_titleBarLayout->addWidget(m_addFeatureButton);
|
||||
m_titleBarLayout->addWidget(m_featurePresetsButton);
|
||||
m_titleBarLayout->addWidget(m_vline2);
|
||||
m_titleBarLayout->addWidget(m_vline3);
|
||||
m_titleBarLayout->addWidget(m_cascadeSubWindows);
|
||||
m_titleBarLayout->addWidget(m_tileSubWindows);
|
||||
m_titleBarLayout->addWidget(m_stackVerticalSubWindows);
|
||||
m_titleBarLayout->addWidget(m_stackSubWindows);
|
||||
m_titleBarLayout->addWidget(m_autoStackSubWindows);
|
||||
m_titleBarLayout->addWidget(m_tabSubWindows);
|
||||
m_titleBarLayout->addStretch(1);
|
||||
#ifndef ANDROID
|
||||
// Can't undock on Android, as windows don't have title bars to allow them to be moved
|
||||
m_titleBarLayout->addWidget(m_normalButton);
|
||||
// Don't allow workspaces to be hidden on Android, as if all are hidden, they'll
|
||||
// be no way to redisplay them, as we currently don't have a main menu bar
|
||||
m_titleBarLayout->addWidget(m_closeButton);
|
||||
#else
|
||||
setFeatures(QDockWidget::NoDockWidgetFeatures);
|
||||
#endif
|
||||
setTitleBarWidget(m_titleBar);
|
||||
|
||||
QObject::connect(
|
||||
@ -198,6 +241,13 @@ Workspace::Workspace(int index, QWidget *parent, Qt::WindowFlags flags) :
|
||||
&Workspace::featurePresetsDialog
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
m_configurationPresetsButton,
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&Workspace::configurationPresetsDialog
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
m_cascadeSubWindows,
|
||||
&QPushButton::clicked,
|
||||
@ -212,6 +262,13 @@ Workspace::Workspace(int index, QWidget *parent, Qt::WindowFlags flags) :
|
||||
&Workspace::tileSubWindows
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
m_stackVerticalSubWindows,
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&Workspace::stackVerticalSubWindows
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
m_stackSubWindows,
|
||||
&QPushButton::clicked,
|
||||
@ -227,10 +284,10 @@ Workspace::Workspace(int index, QWidget *parent, Qt::WindowFlags flags) :
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
m_autoStackSubWindows,
|
||||
m_tabSubWindows,
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&Workspace::autoStackSubWindows
|
||||
&Workspace::tabSubWindows
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
@ -256,6 +313,17 @@ Workspace::Workspace(int index, QWidget *parent, Qt::WindowFlags flags) :
|
||||
&Workspace::deviceStateChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
m_mdi,
|
||||
&QMdiArea::subWindowActivated,
|
||||
this,
|
||||
&Workspace::subWindowActivated
|
||||
);
|
||||
|
||||
#ifdef ANDROID
|
||||
m_tabSubWindows->setChecked(true);
|
||||
tabSubWindows();
|
||||
#endif
|
||||
}
|
||||
|
||||
Workspace::~Workspace()
|
||||
@ -263,13 +331,17 @@ Workspace::~Workspace()
|
||||
qDebug("Workspace::~Workspace");
|
||||
delete m_closeButton;
|
||||
delete m_normalButton;
|
||||
delete m_autoStackSubWindows;
|
||||
delete m_tabSubWindows;
|
||||
delete m_stackSubWindows;
|
||||
delete m_stackVerticalSubWindows;
|
||||
delete m_tileSubWindows;
|
||||
delete m_cascadeSubWindows;
|
||||
delete m_vline3;
|
||||
delete m_vline2;
|
||||
delete m_vline1;
|
||||
delete m_startStopButton;
|
||||
delete m_configurationPresetsButton;
|
||||
delete m_menuButton;
|
||||
delete m_addRxDeviceButton;
|
||||
delete m_addTxDeviceButton;
|
||||
delete m_addMIMODeviceButton;
|
||||
@ -346,18 +418,126 @@ void Workspace::featurePresetsDialog()
|
||||
emit featurePresetsDialogRequested(p, this);
|
||||
}
|
||||
|
||||
void Workspace::configurationPresetsDialog()
|
||||
{
|
||||
emit configurationPresetsDialogRequested();
|
||||
}
|
||||
|
||||
void Workspace::cascadeSubWindows()
|
||||
{
|
||||
m_autoStackSubWindows->setChecked(false);
|
||||
setAutoStackOption(false);
|
||||
m_tabSubWindows->setChecked(false);
|
||||
m_mdi->setViewMode(QMdiArea::SubWindowView);
|
||||
m_mdi->cascadeSubWindows();
|
||||
}
|
||||
|
||||
void Workspace::tileSubWindows()
|
||||
{
|
||||
m_autoStackSubWindows->setChecked(false);
|
||||
setAutoStackOption(false);
|
||||
m_tabSubWindows->setChecked(false);
|
||||
m_mdi->setViewMode(QMdiArea::SubWindowView);
|
||||
m_mdi->tileSubWindows();
|
||||
}
|
||||
|
||||
void Workspace::stackVerticalSubWindows()
|
||||
{
|
||||
setAutoStackOption(false);
|
||||
unmaximizeSubWindows();
|
||||
m_mdi->setViewMode(QMdiArea::SubWindowView);
|
||||
|
||||
// Spacing between windows
|
||||
const int spacing = 2;
|
||||
|
||||
// Categorise windows according to type and calculate min size needed
|
||||
QList<QMdiSubWindow *> windows = m_mdi->subWindowList(QMdiArea::CreationOrder);
|
||||
QList<DeviceGUI *> devices;
|
||||
QList<MainSpectrumGUI *> spectrums;
|
||||
QList<ChannelGUI *> channels;
|
||||
QList<FeatureGUI *> features;
|
||||
int minHeight = 0;
|
||||
int minWidth = 0;
|
||||
int nonFixedWindows = 0;
|
||||
|
||||
for (auto window : windows)
|
||||
{
|
||||
if (window->isVisible() && !window->isMaximized())
|
||||
{
|
||||
if (window->inherits("DeviceGUI")) {
|
||||
devices.append(qobject_cast<DeviceGUI *>(window));
|
||||
} else if (window->inherits("MainSpectrumGUI")) {
|
||||
spectrums.append(qobject_cast<MainSpectrumGUI *>(window));
|
||||
} else if (window->inherits("ChannelGUI")) {
|
||||
channels.append(qobject_cast<ChannelGUI *>(window));
|
||||
} else if (window->inherits("FeatureGUI")) {
|
||||
features.append(qobject_cast<FeatureGUI *>(window));
|
||||
}
|
||||
minHeight += window->minimumSizeHint().height() + spacing;
|
||||
minWidth = std::max(minWidth, window->minimumSizeHint().width());
|
||||
if (window->sizePolicy().verticalPolicy() != QSizePolicy::Fixed) {
|
||||
nonFixedWindows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Order windows by device/feature/channel index
|
||||
orderByIndex(devices);
|
||||
orderByIndex(spectrums);
|
||||
orderByIndex(channels);
|
||||
orderByIndex(features);
|
||||
|
||||
// Will we need scroll bars?
|
||||
QSize mdiSize = m_mdi->size();
|
||||
bool requiresHScrollBar = minWidth > mdiSize.width();
|
||||
bool requiresVScrollBar = minHeight > mdiSize.height();
|
||||
|
||||
// Reduce available size if scroll bars needed
|
||||
int sbWidth = qApp->style()->pixelMetric(QStyle::PM_ScrollBarExtent);
|
||||
if (requiresVScrollBar) {
|
||||
mdiSize.setWidth(mdiSize.width() - sbWidth);
|
||||
}
|
||||
if (requiresHScrollBar) {
|
||||
mdiSize.setHeight(mdiSize.height() - sbWidth);
|
||||
}
|
||||
|
||||
// Calculate spare vertical space, to be shared between non-fixed windows
|
||||
int spareSpacePerWindow;
|
||||
if (requiresVScrollBar) {
|
||||
spareSpacePerWindow = 0;
|
||||
} else {
|
||||
spareSpacePerWindow = (mdiSize.height() - minHeight) / nonFixedWindows;
|
||||
}
|
||||
|
||||
// Now position the windows
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
for (auto window : devices)
|
||||
{
|
||||
window->move(x, y);
|
||||
y += window->size().height() + spacing;
|
||||
}
|
||||
for (auto window : spectrums)
|
||||
{
|
||||
window->move(x, y);
|
||||
window->resize(mdiSize.width(), window->minimumSizeHint().height() + spareSpacePerWindow);
|
||||
y += window->size().height() + spacing;
|
||||
}
|
||||
for (auto window : channels)
|
||||
{
|
||||
window->move(x, y);
|
||||
int extra = (window->sizePolicy().verticalPolicy() == QSizePolicy::Fixed) ? 0 : spareSpacePerWindow;
|
||||
window->resize(mdiSize.width(), window->minimumSizeHint().height() + extra);
|
||||
y += window->size().height() + spacing;
|
||||
}
|
||||
for (auto window : features)
|
||||
{
|
||||
window->move(x, y);
|
||||
int extra = (window->sizePolicy().verticalPolicy() == QSizePolicy::Fixed) ? 0 : spareSpacePerWindow;
|
||||
window->resize(mdiSize.width(), window->minimumSizeHint().height() + extra);
|
||||
y += window->size().height() + spacing;
|
||||
}
|
||||
}
|
||||
|
||||
void Workspace::orderByIndex(QList<ChannelGUI *> &list)
|
||||
{
|
||||
std::sort(list.begin(), list.end(),
|
||||
@ -398,16 +578,36 @@ void Workspace::orderByIndex(QList<MainSpectrumGUI *> &list)
|
||||
});
|
||||
}
|
||||
|
||||
void Workspace::unmaximizeSubWindows()
|
||||
{
|
||||
if (m_tabSubWindows->isChecked())
|
||||
{
|
||||
m_tabSubWindows->setChecked(false);
|
||||
// Unmaximize any maximized windows
|
||||
QList<QMdiSubWindow *> windows = m_mdi->subWindowList(QMdiArea::CreationOrder);
|
||||
for (auto window : windows)
|
||||
{
|
||||
if (window->isMaximized()) {
|
||||
window->showNormal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to arrange windows somewhat like in earlier versions of SDRangel
|
||||
// Devices and fixed size features stacked on left
|
||||
// Spectrum and expandable features stacked in centre
|
||||
// Channels stacked on right
|
||||
void Workspace::stackSubWindows()
|
||||
{
|
||||
unmaximizeSubWindows();
|
||||
|
||||
// Set a flag so event handler knows if it's this code or the user that
|
||||
// resizes a window
|
||||
m_stacking = true;
|
||||
|
||||
m_mdi->setViewMode(QMdiArea::SubWindowView);
|
||||
|
||||
// Categorise windows according to type
|
||||
QList<QMdiSubWindow *> windows = m_mdi->subWindowList(QMdiArea::CreationOrder);
|
||||
QList<DeviceGUI *> devices;
|
||||
@ -653,7 +853,54 @@ void Workspace::stackSubWindows()
|
||||
|
||||
void Workspace::autoStackSubWindows()
|
||||
{
|
||||
if (m_autoStackSubWindows->isChecked()) {
|
||||
setAutoStackOption(!m_autoStack);
|
||||
}
|
||||
|
||||
void Workspace::tabSubWindows()
|
||||
{
|
||||
if (m_tabSubWindows->isChecked())
|
||||
{
|
||||
// Disable autostack
|
||||
setAutoStackOption(false);
|
||||
|
||||
// Move sub windows out of view, so they can't be seen next to a non-expandible window
|
||||
// Perhaps there's a better way to do this - showMinimized didn't work
|
||||
QList<QMdiSubWindow *> windows = m_mdi->subWindowList(QMdiArea::CreationOrder);
|
||||
for (auto window : windows)
|
||||
{
|
||||
if ((window != m_mdi->activeSubWindow()) && ((window->x() != 5000) || (window->y() != 0))) {
|
||||
window->move(5000, 0);
|
||||
}
|
||||
}
|
||||
|
||||
m_mdi->setViewMode(QMdiArea::TabbedView);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_mdi->setViewMode(QMdiArea::SubWindowView);
|
||||
}
|
||||
}
|
||||
|
||||
void Workspace::subWindowActivated(QMdiSubWindow *activatedWindow)
|
||||
{
|
||||
if (activatedWindow && m_tabSubWindows->isChecked())
|
||||
{
|
||||
// Move other windows out of the way
|
||||
QList<QMdiSubWindow *> windows = m_mdi->subWindowList(QMdiArea::CreationOrder);
|
||||
for (auto window : windows)
|
||||
{
|
||||
if ((window != activatedWindow) && ((window->x() != 5000) || (window->y() != 0))) {
|
||||
window->move(5000, 0);
|
||||
} else if ((window == activatedWindow) && ((window->x() != 0) || (window->y() != 0))) {
|
||||
window->move(0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Workspace::layoutSubWindows()
|
||||
{
|
||||
if (m_autoStack) {
|
||||
stackSubWindows();
|
||||
}
|
||||
}
|
||||
@ -716,7 +963,7 @@ void Workspace::deviceStateChanged(int index, DeviceAPI *deviceAPI)
|
||||
void Workspace::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QDockWidget::resizeEvent(event);
|
||||
autoStackSubWindows();
|
||||
layoutSubWindows();
|
||||
}
|
||||
|
||||
void Workspace::addToMdiArea(QMdiSubWindow *sub)
|
||||
@ -725,17 +972,20 @@ void Workspace::addToMdiArea(QMdiSubWindow *sub)
|
||||
sub->installEventFilter(this);
|
||||
// Can't use Close event, as it's before window is closed, so
|
||||
// catch sub-window destroyed signal instead
|
||||
connect(sub, &QObject::destroyed, this, &Workspace::autoStackSubWindows);
|
||||
connect(sub, &QObject::destroyed, this, &Workspace::layoutSubWindows);
|
||||
m_mdi->addSubWindow(sub);
|
||||
sub->show();
|
||||
// Auto-stack when sub-window's widgets are rolled up
|
||||
ChannelGUI *channel = qobject_cast<ChannelGUI *>(sub);
|
||||
if (channel) {
|
||||
connect(channel->getRollupContents(), &RollupContents::widgetRolled, this, &Workspace::autoStackSubWindows);
|
||||
connect(channel->getRollupContents(), &RollupContents::widgetRolled, this, &Workspace::layoutSubWindows);
|
||||
}
|
||||
FeatureGUI *feature = qobject_cast<FeatureGUI *>(sub);
|
||||
if (feature) {
|
||||
connect(feature->getRollupContents(), &RollupContents::widgetRolled, this, &Workspace::autoStackSubWindows);
|
||||
connect(feature->getRollupContents(), &RollupContents::widgetRolled, this, &Workspace::layoutSubWindows);
|
||||
}
|
||||
if (m_tabSubWindows->isChecked()) {
|
||||
sub->showMaximized();
|
||||
}
|
||||
}
|
||||
|
||||
@ -743,14 +993,14 @@ void Workspace::removeFromMdiArea(QMdiSubWindow *sub)
|
||||
{
|
||||
m_mdi->removeSubWindow(sub);
|
||||
sub->removeEventFilter(this);
|
||||
disconnect(sub, &QObject::destroyed, this, &Workspace::autoStackSubWindows);
|
||||
disconnect(sub, &QObject::destroyed, this, &Workspace::layoutSubWindows);
|
||||
ChannelGUI *channel = qobject_cast<ChannelGUI *>(sub);
|
||||
if (channel) {
|
||||
disconnect(channel->getRollupContents(), &RollupContents::widgetRolled, this, &Workspace::autoStackSubWindows);
|
||||
disconnect(channel->getRollupContents(), &RollupContents::widgetRolled, this, &Workspace::layoutSubWindows);
|
||||
}
|
||||
FeatureGUI *feature = qobject_cast<FeatureGUI *>(sub);
|
||||
if (feature) {
|
||||
disconnect(feature->getRollupContents(), &RollupContents::widgetRolled, this, &Workspace::autoStackSubWindows);
|
||||
disconnect(feature->getRollupContents(), &RollupContents::widgetRolled, this, &Workspace::layoutSubWindows);
|
||||
}
|
||||
}
|
||||
|
||||
@ -760,19 +1010,19 @@ bool Workspace::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
QWidget *widget = qobject_cast<QWidget *>(obj);
|
||||
if (!widget->isMaximized()) {
|
||||
autoStackSubWindows();
|
||||
layoutSubWindows();
|
||||
}
|
||||
}
|
||||
else if (event->type() == QEvent::Hide)
|
||||
{
|
||||
QWidget *widget = qobject_cast<QWidget *>(obj);
|
||||
if (!widget->isMaximized()) {
|
||||
autoStackSubWindows();
|
||||
layoutSubWindows();
|
||||
}
|
||||
}
|
||||
else if (event->type() == QEvent::Resize)
|
||||
{
|
||||
if (!m_stacking && m_autoStackSubWindows->isChecked())
|
||||
if (!m_stacking && m_autoStack)
|
||||
{
|
||||
QWidget *widget = qobject_cast<QWidget *>(obj);
|
||||
QResizeEvent *resizeEvent = static_cast<QResizeEvent *>(event);
|
||||
@ -812,12 +1062,38 @@ void Workspace::restoreMdiGeometry(const QByteArray& blob)
|
||||
|
||||
bool Workspace::getAutoStackOption() const
|
||||
{
|
||||
return m_autoStackSubWindows->isChecked();
|
||||
return m_autoStack;
|
||||
}
|
||||
|
||||
void Workspace::setAutoStackOption(bool autoStack)
|
||||
{
|
||||
m_autoStackSubWindows->doToggle(autoStack);
|
||||
m_autoStack = autoStack;
|
||||
if (!m_autoStack)
|
||||
{
|
||||
m_stackSubWindows->setStyleSheet(QString("QPushButton{ background-color: %1; }")
|
||||
.arg(palette().button().color().name()));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_stackSubWindows->setStyleSheet(QString("QPushButton{ background-color: %1; }")
|
||||
.arg(palette().highlight().color().darker(150).name()));
|
||||
stackSubWindows();
|
||||
}
|
||||
}
|
||||
|
||||
bool Workspace::getTabSubWindowsOption() const
|
||||
{
|
||||
return m_tabSubWindows->isChecked();
|
||||
}
|
||||
|
||||
void Workspace::setTabSubWindowsOption(bool tab)
|
||||
{
|
||||
m_tabSubWindows->doToggle(tab);
|
||||
if (tab) {
|
||||
tabSubWindows();
|
||||
} else {
|
||||
m_mdi->setViewMode(QMdiArea::SubWindowView);
|
||||
}
|
||||
}
|
||||
|
||||
void Workspace::adjustSubWindowsAfterRestore()
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
class QHBoxLayout;
|
||||
class QLabel;
|
||||
class QToolButton;
|
||||
class QPushButton;
|
||||
class QMdiArea;
|
||||
class QMdiSubWindow;
|
||||
@ -37,7 +38,6 @@ class ChannelGUI;
|
||||
class FeatureGUI;
|
||||
class DeviceGUI;
|
||||
class MainSpectrumGUI;
|
||||
|
||||
class SDRGUI_API Workspace : public QDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -56,6 +56,8 @@ public:
|
||||
void restoreMdiGeometry(const QByteArray& blob);
|
||||
bool getAutoStackOption() const;
|
||||
void setAutoStackOption(bool autoStack);
|
||||
bool getTabSubWindowsOption() const;
|
||||
void setTabSubWindowsOption(bool tab);
|
||||
QList<QMdiSubWindow *> getSubWindowList() const;
|
||||
void orderByIndex(QList<ChannelGUI *> &list);
|
||||
void orderByIndex(QList<FeatureGUI *> &list);
|
||||
@ -63,21 +65,26 @@ public:
|
||||
void orderByIndex(QList<MainSpectrumGUI *> &list);
|
||||
void adjustSubWindowsAfterRestore();
|
||||
void updateStartStopButton(bool checked);
|
||||
QToolButton *getMenuButton() const { return m_menuButton; }
|
||||
|
||||
private:
|
||||
int m_index;
|
||||
QToolButton *m_menuButton;
|
||||
QPushButton *m_configurationPresetsButton;
|
||||
ButtonSwitch *m_startStopButton;
|
||||
QFrame *m_vline1;
|
||||
QPushButton *m_addRxDeviceButton;
|
||||
QPushButton *m_addTxDeviceButton;
|
||||
QPushButton *m_addMIMODeviceButton;
|
||||
ButtonSwitch *m_startStopButton;
|
||||
QFrame *m_vline1;
|
||||
QFrame *m_vline2;
|
||||
QPushButton *m_addFeatureButton;
|
||||
QPushButton *m_featurePresetsButton;
|
||||
QFrame *m_vline2;
|
||||
QFrame *m_vline3;
|
||||
QPushButton *m_cascadeSubWindows;
|
||||
QPushButton *m_tileSubWindows;
|
||||
QPushButton *m_stackVerticalSubWindows;
|
||||
QPushButton *m_stackSubWindows;
|
||||
ButtonSwitch *m_autoStackSubWindows;
|
||||
ButtonSwitch *m_tabSubWindows;
|
||||
QWidget *m_titleBar;
|
||||
QHBoxLayout *m_titleBarLayout;
|
||||
QLabel *m_titleLabel;
|
||||
@ -86,8 +93,11 @@ private:
|
||||
FeatureAddDialog m_featureAddDialog;
|
||||
QMdiArea *m_mdi;
|
||||
bool m_stacking; // Set when stackSubWindows() is running
|
||||
bool m_autoStack; // Automatically stack
|
||||
int m_userChannelMinWidth; // Minimum width of channels column for stackSubWindows(), set by user resizing a channel window
|
||||
|
||||
void unmaximizeSubWindows();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
@ -98,14 +108,19 @@ private slots:
|
||||
void addMIMODeviceClicked();
|
||||
void addFeatureDialog();
|
||||
void featurePresetsDialog();
|
||||
void configurationPresetsDialog();
|
||||
void cascadeSubWindows();
|
||||
void tileSubWindows();
|
||||
void stackVerticalSubWindows();
|
||||
void stackSubWindows();
|
||||
void autoStackSubWindows();
|
||||
void tabSubWindows();
|
||||
void layoutSubWindows();
|
||||
void startStopClicked(bool checked = false);
|
||||
void addFeatureEmitted(int featureIndex);
|
||||
void toggleFloating();
|
||||
void deviceStateChanged(int index, DeviceAPI *deviceAPI);
|
||||
void subWindowActivated(QMdiSubWindow *window);
|
||||
|
||||
signals:
|
||||
void addRxDevice(Workspace *inWorkspace, int deviceIndex);
|
||||
@ -113,6 +128,7 @@ signals:
|
||||
void addMIMODevice(Workspace *inWorkspace, int deviceIndex);
|
||||
void addFeature(Workspace*, int);
|
||||
void featurePresetsDialogRequested(QPoint, Workspace*);
|
||||
void configurationPresetsDialogRequested();
|
||||
void startAllDevices(Workspace *inWorkspace);
|
||||
void stopAllDevices(Workspace *inWorkspace);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user