From 2b70aafafd362629a0ca31ed3a53076cd433688d Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sun, 24 Apr 2022 11:49:43 +0200 Subject: [PATCH] Some minor cosmetic changes to the SGCT editor --- .../launcher/include/sgctedit/windowcontrol.h | 24 +- .../ext/launcher/resources/qss/launcher.qss | 9 + .../src/sgctedit/displaywindowunion.cpp | 9 + .../launcher/src/sgctedit/settingswidget.cpp | 2 +- .../launcher/src/sgctedit/windowcontrol.cpp | 370 +++++++++++------- 5 files changed, 262 insertions(+), 152 deletions(-) diff --git a/apps/OpenSpace/ext/launcher/include/sgctedit/windowcontrol.h b/apps/OpenSpace/ext/launcher/include/sgctedit/windowcontrol.h index 1223db53ca..493ab9aef7 100644 --- a/apps/OpenSpace/ext/launcher/include/sgctedit/windowcontrol.h +++ b/apps/OpenSpace/ext/launcher/include/sgctedit/windowcontrol.h @@ -33,8 +33,10 @@ class QCheckBox; class QComboBox; +class QDoubleSpinBox; class QLabel; class QLineEdit; +class QSpinBox; class WindowControl final : public QWidget { Q_OBJECT @@ -99,10 +101,10 @@ private: QWidget* createCylindricalWidget(); QWidget* createEquirectangularWidget(); - void onSizeXChanged(const QString& newText); - void onSizeYChanged(const QString& newText); - void onOffsetXChanged(const QString& newText); - void onOffsetYChanged(const QString& newText); + void onSizeXChanged(int newValue); + void onSizeYChanged(int newValue); + void onOffsetXChanged(int newValue); + void onOffsetYChanged(int newValue); void onProjectionChanged(int newSelection); void onFullscreenClicked(); void onAspectRatioLockClicked(); @@ -124,18 +126,18 @@ private: QLabel* _windowNumber = nullptr; QLineEdit* _windowName = nullptr; QComboBox* _monitor = nullptr; - QLineEdit* _sizeX = nullptr; - QLineEdit* _sizeY = nullptr; - QLineEdit* _offsetX = nullptr; - QLineEdit* _offsetY = nullptr; + QSpinBox* _sizeX = nullptr; + QSpinBox* _sizeY = nullptr; + QSpinBox* _offsetX = nullptr; + QSpinBox* _offsetY = nullptr; QCheckBox* _windowDecoration = nullptr; QCheckBox* _webGui = nullptr; QComboBox* _projectionType = nullptr; struct { QWidget* widget = nullptr; - QLineEdit* fovH = nullptr; - QLineEdit* fovV = nullptr; + QDoubleSpinBox* fovH = nullptr; + QDoubleSpinBox* fovV = nullptr; } _planar; struct { @@ -152,7 +154,7 @@ private: struct { QWidget* widget = nullptr; QComboBox* quality = nullptr; - QLineEdit* heightOffset = nullptr; + QDoubleSpinBox* heightOffset = nullptr; } _cylindrical; struct { diff --git a/apps/OpenSpace/ext/launcher/resources/qss/launcher.qss b/apps/OpenSpace/ext/launcher/resources/qss/launcher.qss index d18724d26a..09c2ea5cb4 100644 --- a/apps/OpenSpace/ext/launcher/resources/qss/launcher.qss +++ b/apps/OpenSpace/ext/launcher/resources/qss/launcher.qss @@ -178,3 +178,12 @@ HorizonsDialog QLabel#error { HorizonsDialog QLabel#normal { color: rgb(0, 0, 0); } + +/* + * SGCT + */ +WindowControl QLabel#info { + font-style: italic; + font-weight: normal; + font-size: 8pt; +} diff --git a/apps/OpenSpace/ext/launcher/src/sgctedit/displaywindowunion.cpp b/apps/OpenSpace/ext/launcher/src/sgctedit/displaywindowunion.cpp index 1f179f9740..bcb1425447 100644 --- a/apps/OpenSpace/ext/launcher/src/sgctedit/displaywindowunion.cpp +++ b/apps/OpenSpace/ext/launcher/src/sgctedit/displaywindowunion.cpp @@ -78,7 +78,9 @@ void DisplayWindowUnion::createWidgets(int nMaxWindows, } QBoxLayout* layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); layout->setSizeConstraint(QLayout::SizeConstraint::SetMinimumSize); + { QBoxLayout* layoutMonButton = new QHBoxLayout; _removeWindowButton = new QPushButton("Remove Window"); @@ -107,7 +109,14 @@ void DisplayWindowUnion::createWidgets(int nMaxWindows, layout->addLayout(layoutMonButton); } + QFrame* line = new QFrame; + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); + layout->addWidget(line); + QBoxLayout* layoutWindows = new QHBoxLayout; + layoutWindows->setContentsMargins(0, 0, 0, 0); + layoutWindows->setSpacing(0); for (int i = 0; i < nMaxWindows; ++i) { layoutWindows->addWidget(_windowControl[i]); if (i < (nMaxWindows - 1)) { diff --git a/apps/OpenSpace/ext/launcher/src/sgctedit/settingswidget.cpp b/apps/OpenSpace/ext/launcher/src/sgctedit/settingswidget.cpp index 9641085822..a361b169fd 100644 --- a/apps/OpenSpace/ext/launcher/src/sgctedit/settingswidget.cpp +++ b/apps/OpenSpace/ext/launcher/src/sgctedit/settingswidget.cpp @@ -38,7 +38,7 @@ SettingsWidget::SettingsWidget(sgct::quat orientation, QWidget* parent) _checkBoxVsync = new QCheckBox("Enable VSync"); _checkBoxVsync->setToolTip( - "If enabled, the server will frame lock and wait for all client nodes" + "If enabled the framerate will be locked to the refresh rate of the monitor" ); layout->addWidget(_checkBoxVsync); diff --git a/apps/OpenSpace/ext/launcher/src/sgctedit/windowcontrol.cpp b/apps/OpenSpace/ext/launcher/src/sgctedit/windowcontrol.cpp index cd50965115..8faaf22a2c 100644 --- a/apps/OpenSpace/ext/launcher/src/sgctedit/windowcontrol.cpp +++ b/apps/OpenSpace/ext/launcher/src/sgctedit/windowcontrol.cpp @@ -35,6 +35,7 @@ #include #include #include +#include namespace { std::array MonitorNames = { @@ -91,20 +92,21 @@ WindowControl::WindowControl(int monitorIndex, int windowIndex, } void WindowControl::createWidgets(const QColor& windowColor) { - // Column 0 Column 1 Column 2 Column 3 Column 4 Column 5 * Column 6 * - // *----------*----------*----------*----------*----------*----------*----------* - // | Window {n} | R0 - // | Name * [ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo] | R1 - // | Monitor * DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD> | R2 - // | Size * [xxxxxx] * x * [yyyyyyy] * px * * | R3 - // | Offset * [xxxxxx] * , * [yyyyyyy] * px * * | R4 - // | | R5 - // | [] Window Decoration | R6 - // | [] UI only in this window | R7 - // | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~Detail components~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | R8 - // *----------*----------*----------*----------*----------*----------*----------* + // Col 0 Col 1 Col 2 Col 3 Col 4 Col 5 Col 6 Col 7 + // *----------*----------*-------*----------*-------*--------*-------*-------* + // | Window {n} | R0 + // | Name * [oooooooooooooooooooooooooooooooooooooooooooooooooooooooooo] | R1 + // | Monitor * DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD> | R2 + // | Size * [xxxxxx] * x * [yyyyyy] * px * * < Set to | R3 + // | Offset * [xxxxxx] * , * [yyyyyy] * px * * Fullscreen> | R4 + // | [] Window Decoration | R5 + // | [] UI only in this window | R6 + // | ~~~~~~~~~~~~~~~~~~~~~~~~~Projection components~~~~~~~~~~~~~~~~~~~~~~~~~ | R7 + // *----------*----------*-------*----------*-------*--------*-------*-------* QGridLayout* layout = new QGridLayout(this); + QMargins margins = layout->contentsMargins(); + layout->setContentsMargins(margins.left(), 0, margins.right(), 0); layout->setColumnStretch(6, 1); layout->setRowStretch(8, 1); @@ -113,7 +115,7 @@ void WindowControl::createWidgets(const QColor& windowColor) { "QLabel {{ color : #{:02x}{:02x}{:02x}; }}", windowColor.red(), windowColor.green(), windowColor.blue() ))); - layout->addWidget(_windowNumber, 0, 0, 1, 7, Qt::AlignCenter); + layout->addWidget(_windowNumber, 0, 0, 1, 8, Qt::AlignCenter); { QString tip = "The name for the window (displayed in title bar)."; @@ -123,7 +125,7 @@ void WindowControl::createWidgets(const QColor& windowColor) { _windowName = new QLineEdit; _windowName->setToolTip(tip); - layout->addWidget(_windowName, 1, 1, 1, 6); + layout->addWidget(_windowName, 1, 1, 1, 7); } if (_monitorResolutions.size() > 1) { QString tip = "The monitor where this window is located."; @@ -136,7 +138,7 @@ void WindowControl::createWidgets(const QColor& windowColor) { _monitor->addItems(monitorNames(_monitorResolutions)); _monitor->setCurrentIndex(_monitorIndexDefault); _monitor->setToolTip(tip); - layout->addWidget(_monitor, 2, 1, 1, 6); + layout->addWidget(_monitor, 2, 1, 1, 7); connect( _monitor, qOverload(&QComboBox::currentIndexChanged), [this]() { @@ -150,27 +152,35 @@ void WindowControl::createWidgets(const QColor& windowColor) { } { QLabel* size = new QLabel("Size"); - size->setToolTip("The window's width & height in pixels."); + size->setToolTip("The window's width & height in pixels"); size->setFixedWidth(55); layout->addWidget(size, 3, 0); - _sizeX = new QLineEdit; - _sizeX->setValidator(new QIntValidator(10, MaxWindowSizePixels, this)); + _sizeX = new QSpinBox; + _sizeX->setMinimum(0); + _sizeX->setMaximum(MaxWindowSizePixels); _sizeX->setFixedWidth(LineEditWidthFixedWindowSize); _sizeX->setToolTip("The window's width (pixels)"); layout->addWidget(_sizeX, 3, 1); - connect(_sizeX, &QLineEdit::textChanged, this, &WindowControl::onSizeXChanged); + connect( + _sizeX, QOverload::of(&QSpinBox::valueChanged), + this, &WindowControl::onSizeXChanged + ); QLabel* delim = new QLabel("x"); delim->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum)); layout->addWidget(delim, 3, 2); - _sizeY = new QLineEdit; - _sizeY->setValidator(new QIntValidator(10, MaxWindowSizePixels, this)); + _sizeY = new QSpinBox; + _sizeY->setMinimum(0); + _sizeY->setMaximum(MaxWindowSizePixels); _sizeY->setFixedWidth(LineEditWidthFixedWindowSize); - _sizeY->setToolTip("The window's height (pixels)."); + _sizeY->setToolTip("The window's height (pixels)"); layout->addWidget(_sizeY, 3, 3, Qt::AlignLeft); - connect(_sizeY, &QLineEdit::textChanged, this, &WindowControl::onSizeYChanged); + connect( + _sizeY, QOverload::of(&QSpinBox::valueChanged), + this, &WindowControl::onSizeYChanged + ); QLabel* unit = new QLabel("px"); unit->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum)); @@ -179,7 +189,7 @@ void WindowControl::createWidgets(const QColor& windowColor) { QPushButton* lockAspectRatio = new QPushButton; lockAspectRatio->setIcon(_unlockIcon); lockAspectRatio->setFocusPolicy(Qt::NoFocus); - lockAspectRatio->setToolTip("Locks/Unlocks size aspect ratio."); + lockAspectRatio->setToolTip("Locks/Unlocks the aspect ratio of the window size"); layout->addWidget(lockAspectRatio, 3, 5, Qt::AlignLeft); connect( lockAspectRatio, &QPushButton::released, @@ -201,18 +211,17 @@ void WindowControl::createWidgets(const QColor& windowColor) { offset->setFixedWidth(55); layout->addWidget(offset, 4, 0); - _offsetX = new QLineEdit; - _offsetX->setValidator( - new QIntValidator(-MaxWindowSizePixels, MaxWindowSizePixels, this) - ); + _offsetX = new QSpinBox; + _offsetX->setMinimum(0); + _offsetX->setMaximum(MaxWindowSizePixels); _offsetX->setToolTip( "The x location of the window's upper left corner from monitor's left side " - "(pixels)." + "(pixels)" ); _offsetX->setFixedWidth(LineEditWidthFixedWindowSize); layout->addWidget(_offsetX, 4, 1); connect( - _offsetX, &QLineEdit::textChanged, + _offsetX, QOverload::of(&QSpinBox::valueChanged), this, &WindowControl::onOffsetXChanged ); @@ -220,18 +229,17 @@ void WindowControl::createWidgets(const QColor& windowColor) { comma->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum)); layout->addWidget(comma, 4, 2); - _offsetY = new QLineEdit; - _offsetY->setValidator( - new QIntValidator(-MaxWindowSizePixels, MaxWindowSizePixels, this) - ); + _offsetY = new QSpinBox; + _offsetY->setMinimum(0); + _offsetY->setMaximum(MaxWindowSizePixels); _offsetY->setToolTip( "The y location of the window's upper left corner from monitor's top edge " - "(pixels)." + "(pixels)" ); _offsetY->setFixedWidth(LineEditWidthFixedWindowSize); layout->addWidget(_offsetY, 4, 3, Qt::AlignLeft); connect( - _offsetY, &QLineEdit::textChanged, + _offsetY, QOverload::of(&QSpinBox::valueChanged), this, &WindowControl::onOffsetYChanged ); @@ -240,14 +248,23 @@ void WindowControl::createWidgets(const QColor& windowColor) { layout->addWidget(unit, 4, 4, Qt::AlignLeft); } { - QPushButton* setFullscreen = new QPushButton("Set to Fullscreen"); + QBoxLayout* holderLayout = new QHBoxLayout; + + QPushButton* setFullscreen = new QPushButton("Set Window\nto Fullscreen"); setFullscreen->setToolTip( "If enabled, the window will be created in an exclusive fullscreen mode. The " "size of this\nwindow will be set to the screen resolution, and the window " - "decoration automatically disabled." + "decoration automatically disabled" ); setFullscreen->setFocusPolicy(Qt::NoFocus); - layout->addWidget(setFullscreen, 5, 0, 1, 7); + setFullscreen->setSizePolicy( + QSizePolicy::MinimumExpanding, + QSizePolicy::MinimumExpanding + ); + holderLayout->addStretch(); + holderLayout->addWidget(setFullscreen); + holderLayout->addStretch(); + layout->addLayout(holderLayout, 3, 6, 2, 2); connect( setFullscreen, &QPushButton::released, this, &WindowControl::onFullscreenClicked @@ -257,17 +274,17 @@ void WindowControl::createWidgets(const QColor& windowColor) { _windowDecoration->setChecked(true); _windowDecoration->setToolTip( "If disabled, the window will not have a border frame or title bar, and no\n " - "controls for minimizing/maximizing, resizing, or closing the window." + "controls for minimizing/maximizing, resizing, or closing the window" ); - layout->addWidget(_windowDecoration, 6, 0, 1, 7); + layout->addWidget(_windowDecoration, 5, 0, 1, 8); - _webGui = new QCheckBox("UI only in this window"); + _webGui = new QCheckBox("Show user interface only in this window"); _webGui->setToolTip( "If enabled, the window will be dedicated solely to displaying the GUI " "controls, and will not\nrender any other content. All other window(s) will " - "render normally but will not have GUI controls." + "render normally but will not have GUI controls" ); - layout->addWidget(_webGui, 7, 0, 1, 7); + layout->addWidget(_webGui, 6, 0, 1, 8); connect( _webGui, &QCheckBox::stateChanged, [this]() { @@ -285,12 +302,18 @@ void WindowControl::createWidgets(const QColor& windowColor) { // // Projection combobox QBoxLayout* projectionLayout = new QVBoxLayout(projectionGroup); + projectionLayout->setContentsMargins(0, 0, 0, 0); + projectionLayout->setSpacing(0); _projectionType = new QComboBox; _projectionType->addItems({ - "Planar", "Fisheye", "Spherical Mirror", "Cylindrical", "Equirectangular" + "Planar Projection", + "Fisheye", + "Spherical Mirror Projection", + "Cylindrical Projection", + "Equirectangular Projection" }); - _projectionType->setToolTip("Select from the supported window projection types."); + _projectionType->setToolTip("Select from the supported window projection types"); _projectionType->setCurrentIndex(0); projectionLayout->addWidget(_projectionType); connect( @@ -316,51 +339,75 @@ void WindowControl::createWidgets(const QColor& windowColor) { // We need to trigger this once to ensure that all of the defaults are correct onProjectionChanged(0); - layout->addWidget(projectionGroup, 8, 0, 1, 7); + layout->addWidget(projectionGroup, 7, 0, 1, 8); } } QWidget* WindowControl::createPlanarWidget() { // Column 0 Column 1 Column 2 // *----------*----------*----------* - // | HFOV * [oooooo] * Lock * Row 0 - // | VFOV * [oooooo] * Button * Row 1 + // | { Informational text } | Row 0 + // | HFOV * [oooooo] * Lock | Row 1 + // | VFOV * [oooooo] * Button | Row 2 // *----------*----------*----------* QWidget* widget = new QWidget; QGridLayout* layout = new QGridLayout(widget); + layout->setColumnStretch(1, 1); + + QLabel* info = new QLabel( + "This projection type is the 'regular' projection with a horizontal and a " + "vertical field of view, given in degrees. The wider the field of view, the " + "more content is shown at the same time, but everything becomes smaller. Very " + "large values will introduce distorions on the corners" + ); + info->setObjectName("info"); + info->setWordWrap(true); + layout->addWidget(info, 0, 0, 1, 3); QLabel* fovH = new QLabel("Horizontal FOV"); - QString hfovTip = "The total horizontal field of view of the viewport (degrees)."; + QString hfovTip = "The total horizontal field of view of the viewport (degrees)"; fovH->setToolTip(hfovTip); - layout->addWidget(fovH, 0, 0); + layout->addWidget(fovH, 1, 0); - _planar.fovH = new QLineEdit(QString::number(DefaultFovH)); + _planar.fovH = new QDoubleSpinBox; + _planar.fovH->setMinimum(0.0); + _planar.fovH->setMaximum(180.0); + _planar.fovH->setValue(DefaultFovH); _planar.fovH->setEnabled(false); - _planar.fovH->setValidator(new QDoubleValidator(-180.0, 180.0, 10, this)); _planar.fovH->setToolTip(hfovTip); - layout->addWidget(_planar.fovH, 0, 1); + _planar.fovH->setSizePolicy( + QSizePolicy::MinimumExpanding, + QSizePolicy::MinimumExpanding + ); + layout->addWidget(_planar.fovH, 1, 1); QLabel* fovV = new QLabel("Vertical FOV"); QString vfovTip = "The total vertical field of view of the viewport (degrees). " - "Internally,\nthe values for 'up' & 'down' will each be half this value."; + "Internally,\nthe values for 'up' & 'down' will each be half this value"; fovV->setToolTip(vfovTip); - layout->addWidget(fovV, 1, 0); + layout->addWidget(fovV, 2, 0); - _planar.fovV = new QLineEdit(QString::number(DefaultFovV)); + _planar.fovV = new QDoubleSpinBox; + _planar.fovH->setMinimum(0.0); + _planar.fovH->setMaximum(90.0); + _planar.fovH->setValue(DefaultFovV); _planar.fovV->setEnabled(false); - _planar.fovV->setValidator(new QDoubleValidator(-90.0, 90.0, 10, this)); _planar.fovV->setToolTip(vfovTip); - layout->addWidget(_planar.fovV, 1, 1); + _planar.fovH->setSizePolicy( + QSizePolicy::MinimumExpanding, + QSizePolicy::MinimumExpanding + ); + layout->addWidget(_planar.fovV, 2, 1); QPushButton* lockFov = new QPushButton; lockFov->setIcon(_lockIcon); lockFov->setToolTip( "Locks and scales the Horizontal & Vertical field-of-view to the ideal settings " - "based on the provided aspect ratio." + "based on the provided aspect ratio" ); lockFov->setFocusPolicy(Qt::NoFocus); - layout->addWidget(lockFov, 0, 2, 2, 1); + layout->addWidget(lockFov, 1, 2, 2, 1); connect( lockFov, &QPushButton::released, [this, lockFov]() { @@ -368,134 +415,189 @@ QWidget* WindowControl::createPlanarWidget() { } ); connect(lockFov, &QPushButton::released, this, &WindowControl::onFovLockClicked); + return widget; } QWidget* WindowControl::createFisheyeWidget() { // Column 0 Column 1 - // *----------*----------* - // | Quality * [DDDDD>] * Row 0 - // | [] Spout Output * Row 1 - // *----------*----------* + // *------------*-----------* + // | { Informational text } | Row 0 + // | Quality * [DDDDD>] | Row 1 + // | [] Spout Output | Row 2 + // *------------*-----------* QWidget* widget = new QWidget; QGridLayout* layout = new QGridLayout(widget); + layout->setColumnStretch(1, 1); + + QLabel* info = new QLabel( + "This projection provides a rendering in a format that is suitable for " + "planetariums and other immersive environments. A field-of-view of 180 degrees " + "is presented as a circular image in the center of the screen. For this " + "projection a square window is suggested, but not necessary." + ); + info->setObjectName("info"); + info->setWordWrap(true); + layout->addWidget(info, 0, 0, 1, 2); + QLabel* qualityFisheye = new QLabel("Quality"); QString qualityTip = "Determines the pixel resolution of the projection rendering. " "The higher resolution,\nthe better the rendering quality, but at the expense of " - "increased rendering times."; + "increased rendering times"; qualityFisheye->setToolTip(qualityTip); - layout->addWidget(qualityFisheye, 0, 0); + layout->addWidget(qualityFisheye, 1, 0); _fisheye.quality = new QComboBox; _fisheye.quality->addItems(QualityTypes); _fisheye.quality->setToolTip(qualityTip); _fisheye.quality->setCurrentIndex(2); - layout->addWidget(_fisheye.quality, 0, 1); + layout->addWidget(_fisheye.quality, 1, 1); _fisheye.spoutOutput = new QCheckBox("Spout Output"); _fisheye.spoutOutput->setToolTip( "This projection method provides the ability to share the reprojected image " "using the Spout library.\nThis library only supports the Windows operating " "system. Spout makes it possible to make the rendered\nimages available to other " - "real-time applications on the same machine for further processing." + "real-time applications on the same machine for further processing" ); - layout->addWidget(_fisheye.spoutOutput, 1, 0, 1, 2); + layout->addWidget(_fisheye.spoutOutput, 2, 0, 1, 2); + return widget; } QWidget* WindowControl::createSphericalMirrorWidget() { // Column 0 Column 1 - // *----------*----------* - // | Quality * [DDDDD>] * Row 0 - // *----------*----------* + // *------------*-----------* + // | { Informational text } | Row 0 + // | Quality * [DDDDD>] | Row 1 + // *------------*-----------* QWidget* widget = new QWidget; QGridLayout* layout = new QGridLayout(widget); + layout->setColumnStretch(1, 1); + + QLabel* info = new QLabel( + "This projection is rendering a image suite for use with a spherical mirror " + "projection as described by Paul Bourke (http://paulbourke.net/dome/mirrordome/) " + "and which is a low-cost yet effective way to provide content for a sphericalal " + "display surface using a regular projector." + ); + info->setObjectName("info"); + info->setWordWrap(true); + layout->addWidget(info, 0, 0, 1, 2); QLabel* qualitySphericalMirror = new QLabel("Quality"); QString qualityTip = "Determines the pixel resolution of the projection rendering. " "The higher resolution,\nthe better the rendering quality, but at the expense of " - "increased rendering times."; + "increased rendering times"; qualitySphericalMirror->setToolTip(qualityTip); - layout->addWidget(qualitySphericalMirror, 0, 0); + layout->addWidget(qualitySphericalMirror, 1, 0); _sphericalMirror.quality = new QComboBox; _sphericalMirror.quality->addItems(QualityTypes); _sphericalMirror.quality->setToolTip(qualityTip); _sphericalMirror.quality->setCurrentIndex(2); - layout->addWidget(_sphericalMirror.quality, 0, 1); + layout->addWidget(_sphericalMirror.quality, 1, 1); + + return widget; } QWidget* WindowControl::createCylindricalWidget() { // Column 0 Column 1 - // *----------*----------* - // | Quality * [DDDDD>] * Row 0 - // | HOffset * [oooooo] * Row 1 - // *----------*----------* + // *------------*-----------* + // | { Informational text } | Row 0 + // | Quality * [DDDDD>] | Row 1 + // | HOffset * [oooooo] | Row 2 + // *------------*-----------* QWidget* widget = new QWidget; QGridLayout* layout = new QGridLayout(widget); + layout->setColumnStretch(1, 1); + + QLabel* info = new QLabel( + "This projection type provides a cylindrical rendering that covers 360 degrees " + "around the camera, which can be useful in immersive environments that are not " + "spherical, but where, for example, all walls of a room are covered with " + "projectors." + ); + info->setObjectName("info"); + info->setWordWrap(true); + layout->addWidget(info, 0, 0, 1, 2); QLabel* qualityCylindrical = new QLabel("Quality"); QString qualityTip = "Determines the pixel resolution of the projection rendering. " "The higher resolution,\nthe better the rendering quality, but at the expense of " - "increased rendering times."; + "increased rendering times"; qualityCylindrical->setToolTip(qualityTip); - layout->addWidget(qualityCylindrical, 0, 0); + layout->addWidget(qualityCylindrical, 1, 0); _cylindrical.quality = new QComboBox; _cylindrical.quality->addItems(QualityTypes); _cylindrical.quality->setToolTip(qualityTip); _cylindrical.quality->setCurrentIndex(2); - layout->addWidget(_cylindrical.quality, 0, 1); + layout->addWidget(_cylindrical.quality, 1, 1); QLabel* heightOffset = new QLabel("Height Offset"); QString heightTip = "Offsets the height from which the cylindrical projection is " "generated.\nThis is, in general, only necessary if the user position is offset " "and\ncountering that offset is desired in order to continue producing\na " - "'standard' cylindrical projection."; + "'standard' cylindrical projection"; heightOffset->setToolTip(heightTip); - layout->addWidget(heightOffset); + layout->addWidget(heightOffset, 2, 0); - _cylindrical.heightOffset = new QLineEdit(QString::number(DefaultHeightOffset)); - _cylindrical.heightOffset->setValidator( - new QDoubleValidator(-1000000.0, 1000000.0, 12, this) - ); + _cylindrical.heightOffset = new QDoubleSpinBox; + _cylindrical.heightOffset->setMinimum(-1000000.0); + _cylindrical.heightOffset->setMaximum(1000000.0); + _cylindrical.heightOffset->setValue(DefaultHeightOffset); _cylindrical.heightOffset->setToolTip(heightTip); - layout->addWidget(_cylindrical.heightOffset); + layout->addWidget(_cylindrical.heightOffset, 2, 1); + return widget; } QWidget* WindowControl::createEquirectangularWidget() { // Column 0 Column 1 - // *----------*----------* - // | Quality * [DDDDD>] * Row 0 - // | [] Spout Output * Row 1 - // *----------*----------* + // *------------*-----------* + // | { Informational text } | Row 0 + // | Quality * [DDDDD>] | Row 1 + // | [] Spout Output | Row 2 + // *------------*-----------* QWidget* widget = new QWidget; QGridLayout* layout = new QGridLayout(widget); + layout->setColumnStretch(1, 1); + + QLabel* info = new QLabel( + "This projection provides the rendering as an image in equirectangular " + "projection, which is a common display type for 360 surround video. When " + "uploading a video in equirectangular projection to YouTube, for example, it " + "will use it as a 360 video." + ); + info->setObjectName("info"); + info->setWordWrap(true); + layout->addWidget(info, 0, 0, 1, 2); + QLabel* qualityEquirectangular = new QLabel("Quality"); QString qualityTip = "Determines the pixel resolution of the projection rendering. " "The higher resolution,\nthe better the rendering quality, but at the expense of " - "increased rendering times."; + "increased rendering times"; qualityEquirectangular->setToolTip(qualityTip); - layout->addWidget(qualityEquirectangular, 0, 0); + layout->addWidget(qualityEquirectangular, 1, 0); _equirectangular.quality = new QComboBox; _equirectangular.quality->addItems(QualityTypes); _equirectangular.quality->setToolTip(qualityTip); _equirectangular.quality->setCurrentIndex(2); - layout->addWidget(_equirectangular.quality, 0, 1); + layout->addWidget(_equirectangular.quality, 1, 1); _equirectangular.spoutOutput = new QCheckBox("Spout Output"); _equirectangular.spoutOutput->setToolTip( "This projection method provides the ability to share the reprojected image " "using the Spout library.\nThis library only supports the Windows operating " "system. Spout makes it possible to make the rendered\nimages available to other " - "real-time applications on the same machine for further processing." + "real-time applications on the same machine for further processing" ); - layout->addWidget(_equirectangular.spoutOutput, 1, 0, 1, 2); + layout->addWidget(_equirectangular.spoutOutput, 2, 0, 1, 2); return widget; } @@ -507,15 +609,15 @@ void WindowControl::resetToDefaults() { constexpr int PrimaryMonitorIdx = 0; _windowDimensions = DefaultWindowSizes[_windowIndex]; - _offsetX->setText(QString::number(_windowDimensions.x())); - _offsetY->setText(QString::number(_windowDimensions.y())); + _offsetX->setValue(_windowDimensions.x()); + _offsetY->setValue(_windowDimensions.y()); float newHeight = _monitorResolutions[PrimaryMonitorIdx].height() * IdealScaleVerticalLines; float newWidth = newHeight * IdealAspectRatio; _windowDimensions.setHeight(newHeight); _windowDimensions.setWidth(newWidth); - _sizeX->setText(QString::number(static_cast(newWidth))); - _sizeY->setText(QString::number(static_cast(newHeight))); + _sizeX->setValue(static_cast(newWidth)); + _sizeY->setValue(static_cast(newHeight)); // // Reset widgets @@ -528,9 +630,9 @@ void WindowControl::resetToDefaults() { _fisheye.spoutOutput->setChecked(false); _equirectangular.spoutOutput->setChecked(false); _projectionType->setCurrentIndex(static_cast(ProjectionIndices::Planar)); - _planar.fovV->setText(QString::number(DefaultFovH)); - _planar.fovV->setText(QString::number(DefaultFovV)); - _cylindrical.heightOffset->setText(QString::number(DefaultHeightOffset)); + _planar.fovV->setValue(DefaultFovH); + _planar.fovV->setValue(DefaultFovV); + _cylindrical.heightOffset->setValue(DefaultHeightOffset); _fisheye.quality->setCurrentIndex(2); _sphericalMirror.quality->setCurrentIndex(2); _cylindrical.quality->setCurrentIndex(2); @@ -640,12 +742,12 @@ sgct::config::Window WindowControl::generateWindowInformation() const { return window; } -void WindowControl::onSizeXChanged(const QString& newText) { - _windowDimensions.setWidth(newText.toInt()); +void WindowControl::onSizeXChanged(int newValue) { + _windowDimensions.setWidth(newValue); if (_aspectRatioLocked) { int updatedHeight = _windowDimensions.width() / _aspectRatioSize; _sizeY->blockSignals(true); - _sizeY->setText(QString::number(updatedHeight)); + _sizeY->setValue(updatedHeight); _sizeY->blockSignals(false); _windowDimensions.setHeight(updatedHeight); } @@ -655,12 +757,12 @@ void WindowControl::onSizeXChanged(const QString& newText) { } } -void WindowControl::onSizeYChanged(const QString& newText) { - _windowDimensions.setHeight(newText.toInt()); +void WindowControl::onSizeYChanged(int newValue) { + _windowDimensions.setHeight(newValue); if (_aspectRatioLocked) { int updatedWidth = _windowDimensions.height() * _aspectRatioSize; _sizeX->blockSignals(true); - _sizeX->setText(QString::number(updatedWidth)); + _sizeX->setValue(updatedWidth); _sizeX->blockSignals(false); _windowDimensions.setWidth(updatedWidth); } @@ -670,39 +772,27 @@ void WindowControl::onSizeYChanged(const QString& newText) { } } -void WindowControl::onOffsetXChanged(const QString& newText) { +void WindowControl::onOffsetXChanged(int newValue) { float prevWidth = _windowDimensions.width(); - try { - _windowDimensions.setX(newText.toInt()); - _windowDimensions.setWidth(prevWidth); - emit windowChanged(_monitor->currentIndex(), _windowIndex, _windowDimensions); - } - catch (const std::exception&) { - // The QIntValidator ensures that the range is a +/- integer. However, it's - // possible to enter only a - character causing an exception, which is ignored - // here (when user enters an integer after the - then the value will be updated) - } + _windowDimensions.setX(newValue); + _windowDimensions.setWidth(prevWidth); + emit windowChanged(_monitor->currentIndex(), _windowIndex, _windowDimensions); } -void WindowControl::onOffsetYChanged(const QString& newText) { +void WindowControl::onOffsetYChanged(int newValue) { float prevHeight = _windowDimensions.height(); - try { - _windowDimensions.setY(newText.toInt()); - _windowDimensions.setHeight(prevHeight); - emit windowChanged(_monitor->currentIndex(), _windowIndex, _windowDimensions); - } - catch (const std::exception&) { - // See comment in onOffsetXChanged - } + _windowDimensions.setY(newValue); + _windowDimensions.setHeight(prevHeight); + emit windowChanged(_monitor->currentIndex(), _windowIndex, _windowDimensions); } void WindowControl::onFullscreenClicked() { QRect resolution = _monitorResolutions[_monitor->currentIndex()]; - _offsetX->setText("0"); - _offsetY->setText("0"); - _sizeX->setText(QString::number(resolution.width())); - _sizeY->setText(QString::number(resolution.height())); + _offsetX->setValue(0); + _offsetY->setValue(0); + _sizeX->setValue(resolution.width()); + _sizeY->setValue(resolution.height()); _windowDecoration->setChecked(false); } @@ -739,12 +829,12 @@ void WindowControl::updatePlanarLockedFov() { const float aspectRatio = _windowDimensions.width() / _windowDimensions.height(); const float ratio = aspectRatio / IdealAspectRatio; if (ratio >= 1.f) { - _planar.fovH->setText(QString::number(std::min(DefaultFovH * ratio, 180.f))); - _planar.fovV->setText(QString::number(DefaultFovV)); + _planar.fovH->setValue(std::min(DefaultFovH * ratio, 180.f)); + _planar.fovV->setValue(DefaultFovV); } else { - _planar.fovH->setText(QString::number(DefaultFovH)); - _planar.fovV->setText(QString::number(std::min(DefaultFovV / ratio, 180.f))); + _planar.fovH->setValue(DefaultFovH); + _planar.fovV->setValue(std::min(DefaultFovV / ratio, 180.f)); } }