Merge pull request #1864 from OpenSpace/feature/sgct-gui

Feature/sgct gui
This commit is contained in:
Gene Payne
2022-03-27 14:45:37 -06:00
committed by GitHub
20 changed files with 2711 additions and 22 deletions

View File

@@ -42,6 +42,13 @@ set(HEADER_FILES
include/profile/timedialog.h
include/profile/profileedit.h
include/profile/propertiesdialog.h
include/sgctedit/displaywindowunion.h
include/sgctedit/filesupport.h
include/sgctedit/monitorbox.h
include/sgctedit/orientation.h
include/sgctedit/orientationdialog.h
include/sgctedit/sgctedit.h
include/sgctedit/windowcontrol.h
)
set(SOURCE_FILES
@@ -62,6 +69,13 @@ set(SOURCE_FILES
src/profile/timedialog.cpp
src/profile/profileedit.cpp
src/profile/propertiesdialog.cpp
src/sgctedit/sgctedit.cpp
src/sgctedit/displaywindowunion.cpp
src/sgctedit/filesupport.cpp
src/sgctedit/monitorbox.cpp
src/sgctedit/orientation.cpp
src/sgctedit/orientationdialog.cpp
src/sgctedit/windowcontrol.cpp
)
set(HEADER_SOURCE
@@ -79,6 +93,13 @@ set(HEADER_SOURCE
include/profile/timedialog.h
include/profile/profileedit.h
include/profile/propertiesdialog.h
include/sgctedit/displaywindowunion.h
include/sgctedit/filesupport.h
include/sgctedit/monitorbox.h
include/sgctedit/orientation.h
include/sgctedit/orientationdialog.h
include/sgctedit/sgctedit.h
include/sgctedit/windowcontrol.h
)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Widgets REQUIRED)
@@ -110,7 +131,13 @@ endif()
add_library(openspace-ui-launcher STATIC ${HEADER_FILES} ${SOURCE_FILES} ${MOC_FILES} ${RESOURCE_FILES})
set_openspace_compile_settings(openspace-ui-launcher)
target_include_directories(openspace-ui-launcher PUBLIC include)
target_include_directories(
openspace-ui-launcher
PUBLIC
include
${OPENSPACE_APPS_DIR}/OpenSpace/ext/sgct/include
${OPENSPACE_APPS_DIR}/OpenSpace/ext/sgct/sgct/ext/glm
)
target_link_libraries(
openspace-ui-launcher
PUBLIC

View File

@@ -27,7 +27,9 @@
#include <QMainWindow>
#include "sgctedit/sgctedit.h"
#include <openspace/scene/profile.h>
#include <QApplication>
#include <optional>
namespace openspace::configuration { struct Configuration; }
@@ -82,6 +84,7 @@ private:
void setBackgroundImage(const std::string& syncPath);
void openProfileEditor(const std::string& profile, bool isUserProfile);
void openWindowEditor();
void populateProfilesList(std::string preset);
void populateWindowConfigsList(std::string preset);

View File

@@ -0,0 +1,101 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___DISPLAYWINDOWUNION___H__
#define __OPENSPACE_UI_LAUNCHER___DISPLAYWINDOWUNION___H__
#include <QWidget>
#include "windowcontrol.h"
#include "monitorbox.h"
#include <QCheckBox>
#include <QComboBox>
#include <QIntValidator>
#include <QLabel>
#include <QLayout>
#include <QLineEdit>
#include <QPainter>
#include <QPainterPath>
#include <QPoint>
#include <QPushButton>
#include <QTextBrowser>
#include <QVector>
#include <vector>
class DisplayWindowUnion : public QWidget {
Q_OBJECT
public:
/**
* Constructor for DisplayWindowUnion class, which manages the overall control layout
* including monitorBox, multiple WindowControl columns, and additional controls
*
* \param monitorRenderBox pointer to the MonitorBox object
* \param monitorSizeList A vector containing QRect objects containing pixel dims
* of each monitor
* \param nMaxWindows The maximum number of windows allowed (depends on the number
* of monitors in the system)
* \param winColors An array of QColor objects for window colors. The indexing of
* this array matches the window indexing used elsewhere in the
* class. This allows for a unique color for each window.
*/
DisplayWindowUnion(std::shared_ptr<MonitorBox> monitorRenderBox,
std::vector<QRect>& monitorSizeList, unsigned int nMaxWindows,
const std::array<QColor, 4>& winColors);
/**
* Returns a vector of pointers to all WindowControl objects for all windows
*
* \return vector of pointers of WindowControl objects
*/
std::vector<std::shared_ptr<WindowControl>> windowControls() const;
/**
* Returns the current number of windows
*
* \return the currently-selected number of windows in unsigned int
*/
unsigned int nWindows() const;
private slots:
void addWindow();
void removeWindow();
private:
void initializeWindowControl();
void initializeLayout();
void showWindows();
std::shared_ptr<MonitorBox> _monBox;
std::vector<QRect>& _monitorResolutions;
unsigned int _nWindowsAllocated = 0;
unsigned int _nWindowsDisplayed = 0;
unsigned int _nMaxWindows = 3;
const std::array<QColor, 4>& _winColors;
std::vector<std::shared_ptr<WindowControl>> _windowControl;
QPushButton* _addWindowButton = nullptr;
QPushButton* _removeWindowButton = nullptr;
unsigned int _monitorIdx = 0;
std::vector<QVBoxLayout*> _winCtrlLayouts;
std::vector<QWidget*> _layoutWindowWrappers;
std::vector<QFrame*> _frameBorderLines;
QFrame* _borderFrame = nullptr;
};
#endif // __OPENSPACE_UI_LAUNCHER___DISPLAYWINDOWUNION___H__

View File

@@ -0,0 +1,119 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___FILESUPPORT___H__
#define __OPENSPACE_UI_LAUNCHER___FILESUPPORT___H__
#include <QWidget>
#include <ghoul/filesystem/filesystem.h>
#include <sgctedit/displaywindowunion.h>
#include <sgctedit/orientation.h>
#include <sgct/config.h>
#include <QFileDialog>
#include <QFrame>
#include <QLabel>
#include <QLayout>
#include <QPushButton>
#include <QVector>
#include <filesystem>
#include <memory>
#include <vector>
using ProjectionOptions = std::variant<
sgct::config::NoProjection,
sgct::config::CylindricalProjection,
sgct::config::EquirectangularProjection,
sgct::config::FisheyeProjection,
sgct::config::PlanarProjection,
sgct::config::ProjectionPlane,
sgct::config::SphericalMirrorProjection,
sgct::config::SpoutOutputProjection,
sgct::config::SpoutFlatProjection
>;
struct SgctConfigElements {
std::vector<sgct::config::Window>& windowList;
sgct::config::Cluster& cluster;
};
struct UserConfigurationElements {
std::vector<QRect>& monitorList;
std::shared_ptr<DisplayWindowUnion> display;
Orientation* orientation;
const std::string configSavePath;
};
class FileSupport : public QWidget {
Q_OBJECT
public:
/**
* Constructor for FileSupport class, which saves the window configuration settings
* into the SGCT json structure according to the sgct code
*
* \param parentLayout Qt vertical (QVBoxLayout) layout where controls are added
* \param cfgElements struct of elements needed to read user settings from GUI
* \param sgctElements struct of the window and cluster objects needed for saving
* \param finishedCallback function to be called when user has selected to either
* save changes to file, apply and run without saving, or cancel
*/
FileSupport(QVBoxLayout* parentLayout, UserConfigurationElements& cfgElements,
SgctConfigElements& sgctElements, std::function<void(bool)> finishedCallback);
std::string saveFilename();
private slots:
void cancel();
void save();
void apply();
private:
bool isWindowFullscreen(unsigned int monitorIdx, sgct::ivec2 wDims);
std::optional<unsigned int> findGuiWindow();
void saveConfigToSgctFormat();
void saveCluster();
void saveWindows();
void saveUser();
ProjectionOptions saveProjectionInformation(
std::shared_ptr<WindowControl> winControl);
ProjectionOptions saveProjectionSpout(std::shared_ptr<WindowControl> winControl);
ProjectionOptions saveProjectionNoSpout(std::shared_ptr<WindowControl> winControl);
sgct::config::Viewport generateViewport();
sgct::config::Window saveWindowsDimensions(std::shared_ptr<WindowControl> wCtrl);
void saveWindowsWebGui(unsigned int wIdx, sgct::config::Window& win);
QHBoxLayout* _layoutButtonBox = nullptr;
QPushButton* _saveButton = nullptr;
QPushButton* _cancelButton = nullptr;
QPushButton* _applyButton = nullptr;
std::shared_ptr<DisplayWindowUnion> _displayWidget;
Orientation* _orientationWidget;
std::vector<QRect>& _monitors;
sgct::config::Cluster& _cluster;
std::vector<sgct::config::Window>& _windowList;
std::function<void(bool)> _finishedCallback;
const std::string _userConfigPath;
std::string _saveTarget;
};
#endif // __OPENSPACE_UI_LAUNCHER___FILESUPPORT___H__

View File

@@ -0,0 +1,126 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___MONITORBOX___H__
#define __OPENSPACE_UI_LAUNCHER___MONITORBOX___H__
#include <QWidget>
#include "windowcontrol.h"
#include <QColor>
#include <QIntValidator>
#include <QLineEdit>
#include <QPainter>
#include <QPainterPath>
#include <QPoint>
#include <QVector>
#include <algorithm>
#include <array>
#include <vector>
#include <iostream>
class MonitorBox : public QWidget {
Q_OBJECT
public:
/**
* Constructor for MonitorBox class, which displays the system's monitor(s),
* their relative position and size, and window(s) that they contain
*
* \param widgetDims The size of the display widget in pixels, stored in QRect
* \param monitorResolution A vector containing the monitor's maximum display
* size in pixels in a QRect object
* \param nWindows The current number of windows that has been selected by the user
* \param winColors An array of QColor objects for window colors. The indexing of
* this array matches the window indexing used elsewhere in the
* class. This allows for a unique color for each window.
*/
MonitorBox(QRect widgetDims, std::vector<QRect> monitorResolution,
unsigned int nWindows, const std::array<QColor, 4>& winColors);
/**
* Maps window resolution into the scaled resolution of the display widget
*
* \param mIdx The zero-based monitor index (primary monitor is 0)
* \param wIdx The zero-based window index
* \param winDimensions Dimensions (pixels) of window to be mapped in QRect
*/
void mapWindowResolutionToWidgetCoordinates(unsigned int mIdx, unsigned int wIdx,
const QRectF& winDimensions);
/**
* Sets the number of windows to be displayed
*
* \param nWindows Number of windows to be displayed
*/
void setNumWindowsDisplayed(unsigned int nWindows);
/**
* Called when window dimensions or monitor location have changed, requiring redraw
*
* \param mIdx The zero-based monitor index (primary monitor is 0)
* \param wIdx The zero-based window index
* \param newDimensions Dimensions (pixels) of window to be mapped in QRect
*/
void windowDimensionsChanged(unsigned int mIdx, unsigned int wIdx,
const QRectF& newDimensions);
protected:
void paintEvent(QPaintEvent* event) override;
private:
void determineMonitorArrangement();
void mapMonitorResolutionToWidgetCoordinates();
void paintWidgetBorder(QPainter& painter, int width, int height);
void paintMonitorBackgrounds(QPainter& painter);
void paintWindow(QPainter& painter, size_t winIdx);
void paintWindowBeyondBounds(QPainter& painter, unsigned int winIdx);
void paintWindowNumber(QPainter& painter, unsigned int winIdx);
void setPenSpecificToWindow(QPainter& painter, unsigned int windowIdx,
bool visibleBorder);
void computeScaledResolutionLandscape(float aspectRatio, float maxWidth);
void computeScaledResolutionPortrait(float aspectRatio, float maxHeight);
unsigned int _maxNumMonitors = 2;
QRectF _monitorWidgetSize;
QRectF _monitorBoundaryRect;
unsigned int _nMonitors = 1;
float _monitorArrangementAspectRatio = 1.f;
QSizeF _monitorArrangementDimensions = { 0.0, 0.0 };
std::vector<QRect> _monitorResolution;
std::vector<QRectF> _monitorDimensionsScaled;
QRectF _negativeCorrectionOffsets = {0.f, 0.f, 0.f, 0.f};
std::vector<QRectF> _windowResolutions;
std::vector<QRectF> _windowRendering = {
{0.f, 0.f, 0.f, 0.f},
{0.f, 0.f, 0.f, 0.f},
{0.f, 0.f, 0.f, 0.f},
{0.f, 0.f, 0.f, 0.f}
};
unsigned int _nWindows = 1;
const std::array<QColor, 4> _colorsForWindows;
int _alphaWindowOpacity = 170;
float _monitorScaleFactor = 1.0;
bool _showLabel = false;
float _marginWidget = 5.0;
std::vector<QSizeF> _monitorOffsets;
};
#endif // __OPENSPACE_UI_LAUNCHER___MONITORBOX___H__

View File

@@ -0,0 +1,83 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___ORIENTATION___H__
#define __OPENSPACE_UI_LAUNCHER___ORIENTATION___H__
#include <QWidget>
#include <sgctedit/orientationdialog.h>
#include <sgct/config.h>
#include <sgct/math.h>
#include <QCheckBox>
#include <QLayout>
#include <QPushButton>
class Orientation : public QWidget {
Q_OBJECT
public:
/**
* Constructor for Orientation class, which manages the overall control layout
* including monitorBox, multiple WindowControl columns, and additional controls
*
* \param monitorRenderBox pointer to the MonitorBox object
* \param monitorSizeList A vector containing QRect objects containing pixel dims
* of each monitor
* \param nMaxWindows The maximum number of windows allowed (depends on the number
* of monitors in the system)
* \param winColors An array of QColor objects for window colors. The indexing of
* this array matches the window indexing used elsewhere in the
* class. This allows for a unique color for each window.
*/
Orientation();
/**
* Add Orientation controls to the parent layout
*
* \param parentLayout the layout to which the Orientation's controls will be added
*/
void addControlsToParentLayout(QVBoxLayout* parentLayout);
/**
* Gets the user-provided x,y,z orientation values (degrees)
*
* \return the orientation angles provided in sgct::quat object
*/
sgct::quat orientationValue() const;
/**
* Gets the value for if VSync is enabled
*
* \return true if the VSync option is checked/enabled
*/
bool vsyncValue() const;
private slots:
void orientationDialog();
private:
sgct::quat _orientationValue = {0.f, 0.f, 0.f, 0.f};
OrientationDialog _orientationDialog;
QHBoxLayout* _layoutOrientationFull = nullptr;
QCheckBox* _checkBoxVsync = nullptr;
};
#endif // __OPENSPACE_UI_LAUNCHER___ORIENTATION___H__

View File

@@ -0,0 +1,59 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___ORIENTATIONDIALOG___H__
#define __OPENSPACE_UI_LAUNCHER___ORIENTATIONDIALOG___H__
#include <QDialog>
#include <sgct/config.h>
#include <QLineEdit>
#include <glm/gtc/constants.hpp>
class QWidget;
class OrientationDialog : public QDialog {
Q_OBJECT
public:
/**
* Constructor for OrientationDialog object which contains the input text boxes for
* orientation x,y,z values
*
* \param orientation x,y,z angles in degrees contained in sgct::quat object
* \param parent pointer to Qt QWidget parent object
*/
OrientationDialog(sgct::quat& orientation, QWidget* parent);
private slots:
void cancel();
void ok();
private:
QLineEdit* _linePitch = nullptr;
QLineEdit* _lineRoll = nullptr;
QLineEdit* _lineYaw = nullptr;
sgct::quat& _orientationValue;
};
#endif // __OPENSPACE_UI_LAUNCHER___ORIENTATIONDIALOG___H__

View File

@@ -0,0 +1,105 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___SGCTEDIT___H__
#define __OPENSPACE_UI_LAUNCHER___SGCTEDIT___H__
#include <QDialog>
#include <sgctedit/displaywindowunion.h>
#include <sgctedit/filesupport.h>
#include <sgctedit/monitorbox.h>
#include <sgctedit/orientation.h>
#include <QApplication>
#include <QColor>
#include <QLayout>
#include <QScreen>
#include <memory>
#include <string>
#include <vector>
class QWidget;
class SgctEdit final : public QDialog {
Q_OBJECT
public:
/**
* Constructor for SgctEdit class, the underlying class for the full window
* configuration editor
*
* \param parent The Qt QWidget parent object
* \param windowList vector of sgct::config::Window objects which will be modified
* by the user settings, and then used for writing to file in
* the launcher code
* \param cluster reference to sgct::config::Cluster object that contains sgct
* objects that will be modified by the window configuration settings
* \param screenList A QList containing a QScreen object for each monitor in the
* system
* \param userConfigPath A string containing the file path of the user config
* directory where all window configs are stored
*/
SgctEdit(QWidget* parent, std::vector<sgct::config::Window>& windowList,
sgct::config::Cluster& cluster, const QList<QScreen*>& screenList,
const std::string userConfigPath);
~SgctEdit();
/**
* Used to determine if the window configuration was saved to file, or canceled
*
* \return true if configuration was saved to file
*/
bool wasSaved() const;
/**
* Returns the saved filename
*
* \return saved filename in std::string
*/
std::string saveFilename();
private:
void addDisplayLayout(QHBoxLayout* layout);
void createWidgets();
void systemMonitorConfiguration(const QList<QScreen*>& screenList);
std::shared_ptr<MonitorBox> _monBox = nullptr;
std::vector<QRect> _monitorSizeList;
QVBoxLayout* _displayLayout = nullptr;
QFrame* _displayFrame = nullptr;
std::shared_ptr<DisplayWindowUnion> _displayWidget = nullptr;
QRect _monitorWidgetSize = {0, 0, 500, 500};
FileSupport* _fileSupportWidget = nullptr;
Orientation* _orientationWidget = nullptr;
sgct::config::Cluster& _cluster;
std::vector<sgct::config::Window>& _windowList;
const std::string _userConfigPath;
bool _saveSelected = false;
unsigned int _nMaxWindows = 3;
const std::array<QColor, 4> _colorsForWindows = {
QColor(0x2B, 0x9E, 0xC3),
QColor(0xFC, 0xAB, 0x10),
QColor(0x44, 0xAF, 0x69),
QColor(0xF8, 0x33, 0x3C)
};
};
#endif // __OPENSPACE_UI_LAUNCHER___SGCTEDIT___H__

View File

@@ -0,0 +1,251 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___WINDOWCONTROL___H__
#define __OPENSPACE_UI_LAUNCHER___WINDOWCONTROL___H__
#include <QWidget>
#include <sgct/config.h>
#include <QCheckBox>
#include <QComboBox>
#include <QLabel>
#include <QLayout>
#include <QLineEdit>
#include <QPushButton>
#include <vector>
class WindowControl : public QWidget {
Q_OBJECT
public:
/**
* Constructor for WindowControl class, which contains settings and configuration
* for individual windows
*
* \param monitorIndex The zero-based index for monitor number that this window
* resides in
* \param windowIndex The zero-based window index
* \param monitorDims Vector of monitor dimensions in QRect form
* \param winColor A QColor object for this window's unique color
*/
WindowControl(unsigned int monitorIndex, unsigned int windowIndex,
std::vector<QRect>& monitorDims, const QColor& winColor,
QWidget *parent);
~WindowControl();
/**
* Sets callback function to be invoked when a window's setting changes
*
* \param cb Callback function that accepts the listed arg types, in order of
* monitorIndex, windowIndex, and windowDims (that were just changed)
*/
void setWindowChangeCallback(std::function<void(int, int, const QRectF&)> cb);
/**
* Sets callback function to be invoked when a window gets its GUI checkbox selected
*
* \param cb Callback function that accepts the index of the window that has its
* WebGUI option selected
*/
void setWebGuiChangeCallback(std::function<void(unsigned int)> cb);
/**
* Makes the window label at top of a window control column visible
*
* \param bool Shows the window label if true
*/
void showWindowLabel(bool show);
/**
* Initializes the layout of a window controls column, returning the Qt layout object
*
* \return the QVBoxLayout object that contains the entire windows control column
*/
QVBoxLayout* initializeLayout();
/**
* Returns the dimensions of the window
*
* \return the QRectF object that contains the windows dimensions
*/
QRectF& dimensions();
/**
* Returns the title name of the window
*
* \return the std::string of the window name
*/
std::string windowName() const;
/**
* Returns the user-entered window size width, height from the text line objects
*
* \return the user-entered window size in sgct::ivec2 object
*/
sgct::ivec2 windowSize() const;
/**
* Returns the user-entered window position in x,y pixles from the text line objects
*
* \return the user-entered window position in sgct::ivec2 object
*/
sgct::ivec2 windowPos() const;
/**
* Returns bool for if the window control checkbox is set to be decorated
*
* \return bool for if window decoration is enabled
*/
bool isDecorated() const;
/**
* Returns bool for if the window control checkbox spout selection is enabled
*
* \return bool for if window has spout enabled
*/
bool isSpoutSelected() const;
/**
* Returns bool for if the window control checkbox for WebGUI is enabled
*
* \return bool for if window has WebGUI enabled
*/
bool isGuiWindow() const;
/**
* Function called in order to disable/uncheck the WebGUI checkbox option
*/
void uncheckWebGuiOption();
/**
* Returns index number of the selected window quality value. This is an index into
* the QualityValues array
*
* \return index int into the QualityValues array
*/
int qualitySelectedValue() const;
/**
* Returns index number of the monitor that this window is assigned to
*
* \return int index of monitor
*/
unsigned int monitorNum() const;
/**
* Returns the user-entered horizontal field-of-view (planar projection only)
*
* \return float value of horizontal FOV
*/
float fovH() const;
/**
* Returns the user-entered vertical field-of-view (planar projection only)
*
* \return float value of vertical FOV
*/
float fovV() const;
/**
* Returns the user-entered height offset (cylindrical projection only)
*
* \return float value of height offset
*/
float heightOffset() const;
enum class ProjectionIndeces {
Planar = 0,
Fisheye,
SphericalMirror,
Cylindrical,
Equirectangular
};
/**
* Returns the user-selected window projection type
*
* \return ProjectionIndeces enum of the projection type
*/
ProjectionIndeces projectionSelectedIndex() const;
/**
* Resets all controls for this window to default settings
*/
void resetToDefaults();
private slots:
void onSizeXChanged(const QString& newText);
void onSizeYChanged(const QString& newText);
void onOffsetXChanged(const QString& newText);
void onOffsetYChanged(const QString& newText);
void onMonitorChanged(int newSelection);
void onProjectionChanged(int newSelection);
void onFullscreenClicked();
void onSpoutSelection(int selectionState);
void onWebGuiSelection(int selectionState);
void onAspectRatioLockClicked();
void onFovLockClicked();
private:
void createWidgets(QWidget* parent);
void determineIdealWindowSize();
QString resolutionLabelText(QRect resolution);
void updatePlanarLockedFov();
void updateScaledWindowDimensions();
std::function<void(int, int, const QRectF&)> _windowChangeCallback;
std::function<void(unsigned int)> _windowGuiCheckCallback;
QRectF defaultWindowSizes[4] = {
{50.f, 50.f, 1280.f, 720.f},
{150.f, 150.f, 1280.f, 720.f},
{50.f, 50.f, 1280.f, 720.f},
{150.f, 150.f, 1280.f, 720.f}
};
QList<QString> _monitorNames = { "Primary", "Secondary" };
int QualityValues[10] = { 256, 512, 1024, 1536, 2048, 4096, 8192, 16384,
32768, 65536 };
int _lineEditWidthFixedWinSize = 50;
int _lineEditWidthFixedFov = 80;
const float _idealAspectRatio = 16.f / 9.f;
float _aspectRatioSize = _idealAspectRatio;
float _marginFractionOfWidgetSize = 0.025f;
float _defaultFovH = 80.f;
float _defaultFovV = 50.534f;
float _defaultHeightOffset = 0.f;
unsigned int _nMonitors = 1;
unsigned int _monIndex = 0;
unsigned int _monIndexDefault = 0;
unsigned int _index = 0;
bool _aspectRatioLocked = false;
bool _FovLocked = true;
std::vector<QRect>& _monitorResolutions;
int _maxWindowSizePixels = 10000;
const QColor& _colorForWindow;
QVBoxLayout* _layoutFullWindow = nullptr;
QLabel* _labelWinNum = nullptr;
QLineEdit* _sizeX = nullptr;
QLineEdit* _sizeY = nullptr;
QLineEdit* _offsetX = nullptr;
QLineEdit* _offsetY = nullptr;
QPushButton* _buttonLockAspectRatio = nullptr;
QPushButton* _buttonLockFov = nullptr;
QRectF _windowDims;
QPushButton* _fullscreenButton = nullptr;
QCheckBox* _checkBoxWindowDecor = nullptr;
QCheckBox* _checkBoxWebGui = nullptr;
QCheckBox* _checkBoxSpoutOutput = nullptr;
QComboBox* _comboMonitorSelect = nullptr;
QComboBox* _comboProjection = nullptr;
QComboBox* _comboQuality = nullptr;
QLabel* _labelQuality = nullptr;
QLabel* _labelFovH = nullptr;
QLineEdit* _lineFovH = nullptr;
QLabel* _labelFovV = nullptr;
QLineEdit* _lineFovV = nullptr;
QLabel* _labelHeightOffset = nullptr;
QLineEdit* _lineHeightOffset = nullptr;
QLineEdit* _windowName = nullptr;
QIcon _lockIcon;
QIcon _unlockIcon;
};
#endif // __OPENSPACE_UI_LAUNCHER___WINDOWCONTROL___H__

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -3,5 +3,7 @@
<file>qss/launcher.qss</file>
<file>images/openspace-horiz-logo-small.png</file>
<file>images/launcher-background.png</file>
<file>images/outline_locked.png</file>
<file>images/outline_unlocked.png</file>
</qresource>
</RCC>

View File

@@ -40,6 +40,7 @@
#include <fstream>
#include <iostream>
#include <random>
#include <sgct/readconfig.h>
using namespace openspace;
@@ -61,18 +62,24 @@ namespace {
constexpr const QRect ProfileBox(
LeftRuler, TopRuler + 110, ItemWidth, ItemHeight
);
constexpr const QRect OptionsLabel(LeftRuler, TopRuler + 180, 151, 24);
constexpr const QRect NewProfileButton(
LeftRuler + 140, TopRuler + 180, SmallItemWidth, SmallItemHeight
);
constexpr const QRect EditProfileButton(
LeftRuler, TopRuler + 180, SmallItemWidth, SmallItemHeight
);
constexpr const QRect OptionsLabel(LeftRuler, TopRuler + 230, 151, 24);
constexpr const QRect WindowConfigBox(
LeftRuler, TopRuler + 210, ItemWidth, ItemHeight
LeftRuler, TopRuler + 260, ItemWidth, ItemHeight
);
constexpr const QRect NewWindowButton(
LeftRuler + 140, TopRuler + 330, SmallItemWidth, SmallItemHeight
);
constexpr const QRect EditWindowButton(
LeftRuler, TopRuler + 330, SmallItemWidth, SmallItemHeight
);
constexpr const QRect StartButton(
LeftRuler, TopRuler + 290, ItemWidth, ItemHeight
);
constexpr const QRect NewButton(
LeftRuler + 140, TopRuler + 380, SmallItemWidth, SmallItemHeight
);
constexpr const QRect EditButton(
LeftRuler, TopRuler + 380, SmallItemWidth, SmallItemHeight
LeftRuler, TopRuler + 400, ItemWidth, ItemHeight
);
} // geometry
@@ -134,6 +141,25 @@ namespace {
);
}
}
void saveWindowConfig(QWidget* parent, const std::string& path,
sgct::config::Cluster& cluster)
{
std::ofstream outFile;
try {
outFile.open(path, std::ofstream::out);
outFile << sgct::serializeConfig(cluster);
}
catch (const std::ofstream::failure& e) {
QMessageBox::critical(
parent,
"Exception",
QString::fromStdString(fmt::format(
"Error writing data to file: {} ({})", path, e.what()
))
);
}
}
} // namespace
using namespace openspace;
@@ -248,20 +274,20 @@ QWidget* LauncherWindow::createCentralWidget() {
startButton->setGeometry(geometry::StartButton);
startButton->setCursor(Qt::PointingHandCursor);
QPushButton* newButton = new QPushButton("New", centralWidget);
QPushButton* newProfileButton = new QPushButton("New", centralWidget);
connect(
newButton, &QPushButton::released,
newProfileButton, &QPushButton::released,
[this]() {
openProfileEditor("", true);
}
);
newButton->setObjectName("small");
newButton->setGeometry(geometry::NewButton);
newButton->setCursor(Qt::PointingHandCursor);
newProfileButton->setObjectName("small");
newProfileButton->setGeometry(geometry::NewProfileButton);
newProfileButton->setCursor(Qt::PointingHandCursor);
QPushButton* editButton = new QPushButton("Edit", centralWidget);
QPushButton* editProfileButton = new QPushButton("Edit", centralWidget);
connect(
editButton, &QPushButton::released,
editProfileButton, &QPushButton::released,
[this]() {
const std::string selection = _profileBox->currentText().toStdString();
int selectedIndex = _profileBox->currentIndex();
@@ -269,9 +295,20 @@ QWidget* LauncherWindow::createCentralWidget() {
openProfileEditor(selection, isUserProfile);
}
);
editButton->setObjectName("small");
editButton->setGeometry(geometry::EditButton);
editButton->setCursor(Qt::PointingHandCursor);
editProfileButton->setObjectName("small");
editProfileButton->setGeometry(geometry::EditProfileButton);
editProfileButton->setCursor(Qt::PointingHandCursor);
QPushButton* newWindowButton = new QPushButton("New", centralWidget);
connect(
newWindowButton, &QPushButton::released,
[this]() {
openWindowEditor();
}
);
newWindowButton->setObjectName("small");
newWindowButton->setGeometry(geometry::NewWindowButton);
newWindowButton->setCursor(Qt::PointingHandCursor);
return centralWidget;
}
@@ -476,6 +513,8 @@ void LauncherWindow::populateWindowConfigsList(std::string preset) {
);
}
//Always add the .cfg sgct default as first item
_windowConfigBox->insertItem(0, QString::fromStdString(_sgctConfigName));
// Try to find the requested configuration file and set it as the current one. As we
// have support for function-generated configuration files that will not be in the
// list we need to add a preset that doesn't exist a file for
@@ -485,8 +524,11 @@ void LauncherWindow::populateWindowConfigsList(std::string preset) {
}
else {
// Add the requested preset at the top
_windowConfigBox->insertItem(0, QString::fromStdString(preset));
_windowConfigBox->setCurrentIndex(0);
_windowConfigBox->insertItem(1, QString::fromStdString(preset));
//Increment the user config count because there is an additional option added
//before the user config options
_userConfigCount++;
_windowConfigBox->setCurrentIndex(1);
}
}
@@ -524,6 +566,44 @@ void LauncherWindow::openProfileEditor(const std::string& profile, bool isUserPr
}
}
void LauncherWindow::openWindowEditor() {
QList<QScreen*> screenList = qApp->screens();
if (screenList.length() == 0) {
LERRORC(
"LauncherWindow",
"Error: Qt reports no screens/monitors available"
);
return;
}
sgct::config::Cluster cluster;
std::vector<sgct::config::Window> windowList;
SgctEdit editor(this, windowList, cluster, screenList, _userConfigPath);
editor.exec();
if (editor.wasSaved()) {
std::string ext = ".json";
std::string savePath = editor.saveFilename();
if (savePath.size() >= ext.size()
&& !(savePath.substr(savePath.size() - ext.size()).compare(ext) == 0))
{
savePath += ext;
}
if (cluster.nodes.size() == 0) {
cluster.nodes.push_back(sgct::config::Node());
}
for (auto w : windowList) {
cluster.nodes[0].windows.push_back(w);
}
saveWindowConfig(this, savePath, cluster);
//Truncate path to convert this back to path relative to _userConfigPath
savePath = savePath.substr(_userConfigPath.size());
populateWindowConfigsList(savePath);
}
else {
const std::string current = _windowConfigBox->currentText().toStdString();
populateWindowConfigsList(current);
}
}
bool LauncherWindow::wasLaunchSelected() const {
return _shouldLaunch;
}

View File

@@ -0,0 +1,179 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "sgctedit/displaywindowunion.h"
#include <ghoul/fmt.h>
#include "sgctedit/monitorbox.h"
#include "sgctedit/windowcontrol.h"
#include <QApplication>
#include <QMainWindow>
#include <QScreen>
#include <string>
DisplayWindowUnion::DisplayWindowUnion(std::shared_ptr<MonitorBox> monitorRenderBox,
std::vector<QRect>& monitorSizeList, unsigned int nMaxWindows,
const std::array<QColor, 4>& winColors)
: _monBox(monitorRenderBox)
, _monitorResolutions(monitorSizeList)
, _nMaxWindows(nMaxWindows)
, _winColors(winColors)
{
_addWindowButton = new QPushButton("Add Window");
_removeWindowButton = new QPushButton("Remove Window");
//Add all window controls (some will be hidden from GUI initially)
for (unsigned int i = 0; i < _nMaxWindows; ++i) {
initializeWindowControl();
}
connect(
_addWindowButton,
&QPushButton::clicked,
this,
&DisplayWindowUnion::addWindow
);
connect(
_removeWindowButton,
&QPushButton::clicked,
this,
&DisplayWindowUnion::removeWindow
);
initializeLayout();
}
void DisplayWindowUnion::initializeLayout() {
QVBoxLayout* layout = new QVBoxLayout(this);
{
QHBoxLayout* layoutMonButton = new QHBoxLayout;
_removeWindowButton->setToolTip(
"Remove window from the configuration (at least one window is required)"
);
std::string addTip = fmt::format(
"Add a window to the configuration (up to {} windows allowed)", _nMaxWindows
);
_addWindowButton->setToolTip(QString::fromStdString(addTip));
_addWindowButton->setFocusPolicy(Qt::NoFocus);
_removeWindowButton->setFocusPolicy(Qt::NoFocus);
layoutMonButton->addWidget(_removeWindowButton);
layoutMonButton->addStretch(1);
layoutMonButton->addWidget(_addWindowButton);
layout->addLayout(layoutMonButton);
}
QHBoxLayout* layoutWindows = new QHBoxLayout;
layout->addStretch();
for (unsigned int i = 0; i < _nMaxWindows; ++i) {
QVBoxLayout* layoutForNextWindow = _windowControl[i]->initializeLayout();
_winCtrlLayouts.push_back(layoutForNextWindow);
QWidget* layoutWrapper = new QWidget();
layoutWrapper->setLayout(layoutForNextWindow);
_layoutWindowWrappers.push_back(layoutWrapper);
layoutWindows->addWidget(layoutWrapper);
if (i < (_nMaxWindows - 1)) {
QFrame* frameForNextWindow = new QFrame();
frameForNextWindow->setFrameShape(QFrame::VLine);
_frameBorderLines.push_back(frameForNextWindow);
layoutWindows->addWidget(frameForNextWindow);
}
}
_nWindowsDisplayed = 1;
showWindows();
layout->addLayout(layoutWindows);
}
std::vector<std::shared_ptr<WindowControl>> DisplayWindowUnion::windowControls() const {
return _windowControl;
}
unsigned int DisplayWindowUnion::nWindows() const {
return _nWindowsDisplayed;
}
void DisplayWindowUnion::addWindow() {
if (_nWindowsDisplayed < _nMaxWindows) {
_windowControl[_nWindowsDisplayed]->resetToDefaults();
_nWindowsDisplayed++;
showWindows();
}
}
void DisplayWindowUnion::removeWindow() {
if (_nWindowsDisplayed > 1) {
_nWindowsDisplayed--;
showWindows();
}
}
void DisplayWindowUnion::showWindows() {
for (size_t i = 0; i < _layoutWindowWrappers.size(); ++i) {
_layoutWindowWrappers[i]->setVisible(i < _nWindowsDisplayed);
}
for (size_t i = 0; i < _frameBorderLines.size(); ++i) {
_frameBorderLines[i]->setVisible(i < (_nWindowsDisplayed - 1));
}
_removeWindowButton->setEnabled(_nWindowsDisplayed > 1);
_addWindowButton->setEnabled(_nWindowsDisplayed != _nMaxWindows);
for (std::shared_ptr<WindowControl> w : _windowControl) {
w->showWindowLabel(_nWindowsDisplayed > 1);
}
_monBox->setNumWindowsDisplayed(_nWindowsDisplayed);
}
void DisplayWindowUnion::initializeWindowControl() {
if (_nWindowsAllocated < _nMaxWindows) {
unsigned int monitorNumForThisWindow = 0;
if (_nMaxWindows > 3 && _nWindowsAllocated >= 2) {
monitorNumForThisWindow = 1;
}
_windowControl.push_back(
std::make_shared<WindowControl>(
monitorNumForThisWindow,
_nWindowsAllocated,
_monitorResolutions,
_winColors[_nWindowsAllocated],
this
)
);
_windowControl.back()->setWindowChangeCallback(
[this](int monIndex, int winIndex, const QRectF& newDims) {
_monBox->windowDimensionsChanged(monIndex, winIndex, newDims);
}
);
_windowControl.back()->setWebGuiChangeCallback(
[this](unsigned int winIndex) {
for (unsigned int w = 0; w < _nMaxWindows; ++w) {
if (w != winIndex) {
_windowControl[w]->uncheckWebGuiOption();
}
}
}
);
_monBox->mapWindowResolutionToWidgetCoordinates(
monitorNumForThisWindow,
_nWindowsAllocated,
_windowControl.back()->dimensions()
);
_nWindowsAllocated++;
}
}

View File

@@ -0,0 +1,291 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "sgctedit/filesupport.h"
FileSupport::FileSupport(QVBoxLayout* parentLayout,
UserConfigurationElements& cfgElements,
SgctConfigElements& sgctElements,
std::function<void(bool)> finishedCallback)
: _displayWidget(cfgElements.display)
, _orientationWidget(cfgElements.orientation)
, _monitors(cfgElements.monitorList)
, _cluster(sgctElements.cluster)
, _windowList(sgctElements.windowList)
, _finishedCallback(finishedCallback)
, _userConfigPath(cfgElements.configSavePath)
{
QVBoxLayout* layoutFullVertical = new QVBoxLayout;
_saveButton = new QPushButton("Save As");
_saveButton->setToolTip("Save configuration changes (opens file chooser dialog)");
_saveButton->setFocusPolicy(Qt::NoFocus);
connect(_saveButton, &QPushButton::released, this, &FileSupport::save);
_cancelButton = new QPushButton("Cancel");
_cancelButton->setToolTip("Cancel changes");
_cancelButton->setFocusPolicy(Qt::NoFocus);
connect(_cancelButton, &QPushButton::released, this, &FileSupport::cancel);
_applyButton = new QPushButton("Apply Without Saving");
_applyButton->setToolTip("Apply configuration changes without saving to file");
_applyButton->setFocusPolicy(Qt::NoFocus);
connect(_applyButton, &QPushButton::released, this, &FileSupport::apply);
{
QHBoxLayout* layoutButtonBox = new QHBoxLayout;
layoutButtonBox->addStretch(1);
layoutButtonBox->addWidget(_cancelButton);
layoutButtonBox->addWidget(_saveButton);
layoutButtonBox->addWidget(_applyButton);
layoutFullVertical->addLayout(layoutButtonBox);
}
parentLayout->addLayout(layoutFullVertical);
}
void FileSupport::saveCluster() {
if (_orientationWidget) {
sgct::config::Scene initScene;
initScene.orientation = _orientationWidget->orientationValue();
_cluster.nodes.clear();
sgct::config::Node tmpNode;
tmpNode.address = "localhost";
tmpNode.port = 20401;
_cluster.nodes.push_back(tmpNode);
_cluster.masterAddress = "localhost";
_cluster.scene = std::move(initScene);
_cluster.firmSync = _orientationWidget->vsyncValue();
}
}
void FileSupport::saveUser() {
if (_orientationWidget) {
sgct::config::User user;
user.eyeSeparation = 0.065f;
user.position = {0.0f, 0.0f, 4.0f};
_cluster.users.push_back(user);
}
}
bool FileSupport::isWindowFullscreen(unsigned int monitorIdx, sgct::ivec2 wDims) {
return (_monitors[monitorIdx].width() == wDims.x &&
_monitors[monitorIdx].height() == wDims.y);
}
std::optional<unsigned int> FileSupport::findGuiWindow() {
unsigned int windowIndex = 0;
for (unsigned int w = 0; w < _displayWidget->nWindows(); ++w) {
if (_displayWidget->windowControls()[w]->isGuiWindow()) {
return std::optional<unsigned int>(windowIndex);
}
windowIndex++;
}
return std::nullopt;
}
void FileSupport::saveWindows() {
unsigned int windowIndex = 0;
for (unsigned int w = 0; w < _displayWidget->nWindows(); ++w) {
std::shared_ptr<WindowControl> wCtrl = _displayWidget->windowControls()[w];
sgct::config::Window tmpWindow = saveWindowsDimensions(wCtrl);
tmpWindow.viewports.push_back(generateViewport());
tmpWindow.viewports.back().projection = saveProjectionInformation(wCtrl);
tmpWindow.isDecorated = wCtrl->isDecorated();
tmpWindow.isFullScreen = isWindowFullscreen(
wCtrl->monitorNum(),
wCtrl->windowSize()
);
if (tmpWindow.isFullScreen) {
tmpWindow.monitor = wCtrl->monitorNum();
}
saveWindowsWebGui(windowIndex, tmpWindow);
if (!wCtrl->windowName().empty()) {
tmpWindow.name = wCtrl->windowName();
}
tmpWindow.id = windowIndex++;
_windowList.push_back(tmpWindow);
}
}
sgct::config::Viewport FileSupport::generateViewport() {
sgct::config::Viewport vp;
vp.isTracked = true;
vp.position = {0.f, 0.f};
vp.size = {1.f, 1.f};
return vp;
}
sgct::config::Window FileSupport::saveWindowsDimensions(
std::shared_ptr<WindowControl> wCtrl)
{
sgct::config::Window tmpWindow;
tmpWindow.size = wCtrl->windowSize();
tmpWindow.pos = {
_monitors[wCtrl->monitorNum()].x() + wCtrl->windowPos().x,
_monitors[wCtrl->monitorNum()].y() + wCtrl->windowPos().y,
};
return tmpWindow;
}
void FileSupport::saveWindowsWebGui(unsigned int wIdx, sgct::config::Window& win) {
win.viewports.back().isTracked = true;
std::optional<unsigned int> webGuiWindowIndex = findGuiWindow();
bool isOneOfWindowsSetAsWebGui = webGuiWindowIndex.has_value();
if (isOneOfWindowsSetAsWebGui) {
if (wIdx == webGuiWindowIndex.value()) {
win.viewports.back().isTracked = false;
win.tags.push_back("GUI");
}
win.draw2D = (wIdx == webGuiWindowIndex.value());
win.draw3D = !(win.draw2D.value());
}
}
ProjectionOptions FileSupport::saveProjectionInformation(
std::shared_ptr<WindowControl> winControl)
{
if (winControl->isSpoutSelected()) {
return saveProjectionSpout(winControl);
}
else {
return saveProjectionNoSpout(winControl);
}
}
ProjectionOptions FileSupport::saveProjectionSpout(
std::shared_ptr<WindowControl> winControl)
{
sgct::config::SpoutOutputProjection projection;
switch(winControl->projectionSelectedIndex()) {
case WindowControl::ProjectionIndeces::Fisheye:
projection.mapping
= sgct::config::SpoutOutputProjection::Mapping::Fisheye;
break;
case WindowControl::ProjectionIndeces::Equirectangular:
default:
projection.mapping
= sgct::config::SpoutOutputProjection::Mapping::Equirectangular;
break;
}
projection.quality = winControl->qualitySelectedValue();
projection.mappingSpoutName = "OpenSpace";
return projection;
}
ProjectionOptions FileSupport::saveProjectionNoSpout(
std::shared_ptr<WindowControl> winControl)
{
switch(winControl->projectionSelectedIndex()) {
case WindowControl::ProjectionIndeces::Fisheye:
{
sgct::config::FisheyeProjection projection;
projection.quality = winControl->qualitySelectedValue();
projection.fov = 180.f;
projection.tilt = 0.f;
return projection;
}
break;
case WindowControl::ProjectionIndeces::SphericalMirror:
{
sgct::config::SphericalMirrorProjection projection;
projection.quality = winControl->qualitySelectedValue();
return projection;
}
break;
case WindowControl::ProjectionIndeces::Cylindrical:
{
sgct::config::CylindricalProjection projection;
projection.quality = winControl->qualitySelectedValue();
projection.heightOffset = winControl->heightOffset();
return projection;
}
break;
case WindowControl::ProjectionIndeces::Equirectangular:
{
sgct::config::EquirectangularProjection projection;
projection.quality = winControl->qualitySelectedValue();
return projection;
}
break;
case WindowControl::ProjectionIndeces::Planar:
default:
{
// The negative values for left & down are according to sgct's convention
sgct::config::PlanarProjection projection;
projection.fov.right = winControl->fovH() / 2.0;
projection.fov.left = -projection.fov.right;
projection.fov.up = winControl->fovV() / 2.0;
projection.fov.down = -projection.fov.up;
return projection;
}
break;
}
}
std::string FileSupport::saveFilename() {
return _saveTarget;
}
void FileSupport::save() {
QString fileName = QFileDialog::getSaveFileName(
this,
"Save Window Configuration File",
QString::fromStdString(_userConfigPath),
"Window Configuration (*.json);;(*.json)",
nullptr
#ifdef __linux__
, QFileDialog::DontUseNativeDialog
#endif
);
if (fileName.length() != 0) {
_saveTarget = fileName.toStdString();
saveConfigToSgctFormat();
_finishedCallback(true);
}
}
void FileSupport::cancel() {
_finishedCallback(false);
}
void FileSupport::apply() {
std::string userCfgTempDir = _userConfigPath;
if (userCfgTempDir.back() != '/') {
userCfgTempDir += "/";
}
userCfgTempDir += "temp";
if (!std::filesystem::is_directory(userCfgTempDir)) {
std::filesystem::create_directories(absPath(userCfgTempDir));
}
_saveTarget = userCfgTempDir + "/" + "apply-without-saving.json";
saveConfigToSgctFormat();
_finishedCallback(true);
}
void FileSupport::saveConfigToSgctFormat() {
saveCluster();
saveWindows();
saveUser();
}

View File

@@ -0,0 +1,255 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "sgctedit/monitorbox.h"
constexpr float MarginFractionOfWidgetSize = 0.05f;
MonitorBox::MonitorBox(QRect widgetDims, std::vector<QRect> monitorResolution,
unsigned int nWindows, const std::array<QColor, 4>& winColors)
: _monitorWidgetSize(widgetDims)
, _monitorResolution(monitorResolution)
, _nWindows(nWindows)
, _colorsForWindows(winColors)
{
_nMonitors = static_cast<unsigned int>(monitorResolution.size());
_showLabel = (_nMonitors > 1);
determineMonitorArrangement();
this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
float borderMargin = MarginFractionOfWidgetSize * 2.f;
if (_monitorArrangementAspectRatio > 1.0) {
borderMargin *= _monitorWidgetSize.width();
_monitorWidgetSize.setHeight(_monitorWidgetSize.width()
/ _monitorArrangementAspectRatio + borderMargin);
}
else {
borderMargin *= _monitorWidgetSize.height();
_monitorWidgetSize.setWidth(_monitorWidgetSize.height()
* _monitorArrangementAspectRatio + borderMargin);
}
this->setFixedSize(_monitorWidgetSize.width(), _monitorWidgetSize.height());
mapMonitorResolutionToWidgetCoordinates();
}
void MonitorBox::paintEvent(QPaintEvent* event) {
Q_UNUSED(event)
QPainter painter(this);
QPen pen = painter.pen();
painter.setPen(pen);
paintWidgetBorder(painter, width(), height());
//Draw window out-of-bounds region(s) first
for (unsigned int i = 0; i < _nWindows; ++i) {
paintWindowBeyondBounds(painter, i);
}
//Draw & fill monitors over the out-of-bounds regions
paintMonitorBackgrounds(painter);
//Draw window number(s) first for darker contrast, then window(s) over both
//out-of-bounds and monitors
for (unsigned int i = 0; i < _nWindows; ++i) {
paintWindowNumber(painter, i);
}
for (unsigned int i = 0; i < _nWindows; ++i) {
paintWindow(painter, i);
}
}
void MonitorBox::paintWidgetBorder(QPainter& painter, int width, int height) {
constexpr int Radius = 10;
painter.setPen(QPen(Qt::gray, 4));
painter.drawRoundedRect(0, 0, width - 1, height - 1, Radius, Radius);
}
void MonitorBox::paintMonitorBackgrounds(QPainter& painter) {
painter.setPen(QPen(Qt::black, 2));
QFont f("Arial");
f.setPixelSize(24);
painter.setFont(f);
for (unsigned int i = 0; i < _nMonitors; ++i) {
if (i <= _monitorDimensionsScaled.size()) {
painter.drawRect(_monitorDimensionsScaled[i]);
QColor fillColor("#DDDDDD");
QBrush brush(fillColor);
brush.setStyle(Qt::SolidPattern);
painter.fillRect(_monitorDimensionsScaled[i], brush);
if (_showLabel) {
QPointF textPos = QPointF(
_monitorDimensionsScaled[i].left() + 4,
_monitorDimensionsScaled[i].top() + 24
);
if (i == 0) {
painter.drawText(textPos, "Primary");
}
}
}
}
}
void MonitorBox::paintWindowBeyondBounds(QPainter& painter, unsigned int winIdx) {
painter.setBrush(Qt::BDiagPattern);
setPenSpecificToWindow(painter, winIdx, false);
if (winIdx <= _windowRendering.size()) {
painter.drawRect(_windowRendering[winIdx]);
}
setPenSpecificToWindow(painter, winIdx, true);
painter.setBrush(Qt::NoBrush);
}
void MonitorBox::paintWindow(QPainter& painter, size_t winIdx) {
setPenSpecificToWindow(painter, static_cast<unsigned int>(winIdx), true);
if (winIdx <= _windowRendering.size()) {
painter.drawRect(_windowRendering[winIdx]);
QColor fillColor = _colorsForWindows[winIdx];
fillColor.setAlpha(_alphaWindowOpacity);
QBrush brush(fillColor);
brush.setStyle(Qt::SolidPattern);
painter.fillRect(_windowRendering[winIdx], brush);
}
}
void MonitorBox::paintWindowNumber(QPainter& painter, unsigned int winIdx) {
QPointF textPos = QPointF(_windowRendering[winIdx].left() + 5,
_windowRendering[winIdx].bottom() - 5);
textPos.setX(std::clamp(textPos.x(), 0.0, _monitorWidgetSize.width() - 10));
textPos.setY(std::clamp(textPos.y(), 20.0, _monitorWidgetSize.height()));
painter.drawText(textPos, QString::fromStdString(std::to_string(winIdx + 1)));
}
void MonitorBox::setPenSpecificToWindow(QPainter& painter, unsigned int windowIdx,
bool visibleBorder)
{
int penWidth = (visibleBorder) ? 1 : -1;
painter.setPen(QPen(_colorsForWindows[windowIdx], penWidth));
}
void MonitorBox::windowDimensionsChanged(unsigned int mIdx, unsigned int wIdx,
const QRectF& newDimensions)
{
mapWindowResolutionToWidgetCoordinates(mIdx, wIdx, newDimensions);
}
void MonitorBox::determineMonitorArrangement() {
for (const QRect& m : _monitorResolution) {
if (m.x() < _negativeCorrectionOffsets.x()) {
_negativeCorrectionOffsets.setX(m.x());
}
if (m.y() < _negativeCorrectionOffsets.y()) {
_negativeCorrectionOffsets.setY(m.y());
}
}
for (const QRect& m : _monitorResolution) {
if ((m.x() + m.width() - _negativeCorrectionOffsets.x())
> _monitorArrangementDimensions.width())
{
_monitorArrangementDimensions.setWidth(
m.x() + m.width() - _negativeCorrectionOffsets.x());
}
if ((m.y() + m.height() - _negativeCorrectionOffsets.y())
> _monitorArrangementDimensions.height())
{
_monitorArrangementDimensions.setHeight(
m.y() + m.height() - _negativeCorrectionOffsets.y());
}
}
_monitorArrangementAspectRatio = _monitorArrangementDimensions.width()
/ _monitorArrangementDimensions.height();
}
void MonitorBox::mapMonitorResolutionToWidgetCoordinates() {
if (_monitorArrangementAspectRatio >= 1.0) {
computeScaledResolutionLandscape(
_monitorArrangementAspectRatio,
_monitorArrangementDimensions.width()
);
}
else {
computeScaledResolutionPortrait(
_monitorArrangementAspectRatio,
_monitorArrangementDimensions.height()
);
}
for (size_t m = 0; m < _monitorResolution.size(); ++m) {
_monitorDimensionsScaled.push_back({
_monitorOffsets[m].width(),
_monitorOffsets[m].height(),
_monitorResolution[m].width() * _monitorScaleFactor,
_monitorResolution[m].height() * _monitorScaleFactor,
});
}
update();
}
void MonitorBox::computeScaledResolutionLandscape(float aspectRatio, float maxWidth) {
_marginWidget = _monitorWidgetSize.width() * MarginFractionOfWidgetSize;
float virtualWidth = _monitorWidgetSize.width()
* (1.0 - MarginFractionOfWidgetSize * 2.0);
_monitorScaleFactor = virtualWidth / maxWidth;
float newHeight = virtualWidth / aspectRatio;
for (size_t m = 0; m < _monitorResolution.size(); ++m) {
_monitorOffsets.push_back({
_marginWidget + (_monitorResolution[m].x() - _negativeCorrectionOffsets.x())
* _monitorScaleFactor,
_marginWidget + (_monitorWidgetSize.height() - newHeight - _marginWidget) / 4.0
+ (_monitorResolution[m].y() - _negativeCorrectionOffsets.y())
* _monitorScaleFactor
});
}
}
void MonitorBox::computeScaledResolutionPortrait(float aspectRatio, float maxHeight) {
_marginWidget = _monitorWidgetSize.height() * MarginFractionOfWidgetSize;
float virtualHeight = _monitorWidgetSize.height()
* (1.0 - MarginFractionOfWidgetSize * 2.0);
_monitorScaleFactor = virtualHeight / maxHeight;
float newWidth = virtualHeight * aspectRatio;
for (size_t m = 0; m < _monitorResolution.size(); ++m) {
_monitorOffsets.push_back({
_marginWidget + (_monitorWidgetSize.width() - newWidth - _marginWidget) / 4.0
+ (_monitorResolution[m].x() - _negativeCorrectionOffsets.x())
* _monitorScaleFactor,
_marginWidget + (_monitorResolution[m].y() - _negativeCorrectionOffsets.y())
* _monitorScaleFactor
});
}
}
void MonitorBox::setNumWindowsDisplayed(unsigned int nWindows) {
if (_nWindows != nWindows) {
_nWindows = nWindows;
update();
}
}
void MonitorBox::mapWindowResolutionToWidgetCoordinates(unsigned int mIdx,
unsigned int wIdx,
const QRectF& winDimensions)
{
QRectF wF = winDimensions;
_windowRendering[wIdx] = {
_monitorDimensionsScaled[mIdx].x() + wF.left() * _monitorScaleFactor,
_monitorDimensionsScaled[mIdx].y() + wF.top() * _monitorScaleFactor,
wF.width() * _monitorScaleFactor,
wF.height() * _monitorScaleFactor
};
update();
}

View File

@@ -0,0 +1,73 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "sgctedit/orientation.h"
#include "sgctedit/orientationdialog.h"
Orientation::Orientation()
: _orientationDialog(_orientationValue, this)
{
_layoutOrientationFull = new QHBoxLayout;
{
QVBoxLayout* layoutOrientationControls = new QVBoxLayout;
QPushButton* orientationButton = new QPushButton("Global Orientation");
_checkBoxVsync = new QCheckBox("VSync All Windows", this);
_checkBoxVsync->setToolTip(
"If enabled, the server will frame lock and wait for all client nodes"
);
layoutOrientationControls->addWidget(_checkBoxVsync);
orientationButton->setToolTip(
"Opens a separate dialog for setting the pitch, "
"yaw, and roll of the camera\n(the orientation applies to all viewports)"
);
orientationButton->setFocusPolicy(Qt::NoFocus);
layoutOrientationControls->addWidget(orientationButton);
_layoutOrientationFull->addStretch(1);
_layoutOrientationFull->addLayout(layoutOrientationControls);
_layoutOrientationFull->addStretch(1);
connect(
orientationButton,
&QPushButton::released,
this,
&Orientation::orientationDialog
);
}
}
void Orientation::addControlsToParentLayout(QVBoxLayout* parentLayout) {
parentLayout->addLayout(_layoutOrientationFull);
}
void Orientation::orientationDialog() {
_orientationDialog.exec();
}
sgct::quat Orientation::orientationValue() const {
return _orientationValue;
}
bool Orientation::vsyncValue() const {
return (_checkBoxVsync->checkState() == Qt::Checked);
}

View File

@@ -0,0 +1,119 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "sgctedit/orientationdialog.h"
#include "sgctedit/displaywindowunion.h"
OrientationDialog::OrientationDialog(sgct::quat& orientation, QWidget* parent)
: QDialog(parent)
, _orientationValue(orientation)
{
setWindowTitle("Global Orientation");
QVBoxLayout* layoutWindow = new QVBoxLayout(this);
_linePitch = new QLineEdit;
_lineRoll = new QLineEdit;
_lineYaw = new QLineEdit;
_linePitch->setText(QString::number(_orientationValue.x));
_lineRoll->setText(QString::number(_orientationValue.z));
_lineYaw->setText(QString::number(_orientationValue.y));
{
QDoubleValidator* validatorPitch = new QDoubleValidator(-90.0, 90.0, 15);
QDoubleValidator* validatorRoll = new QDoubleValidator(-360.0, 360.0, 15);
QDoubleValidator* validatorYaw = new QDoubleValidator(-180.0, 180.0, 15);
validatorPitch->setNotation(QDoubleValidator::StandardNotation);
validatorRoll->setNotation(QDoubleValidator::StandardNotation);
validatorYaw->setNotation(QDoubleValidator::StandardNotation);
_linePitch->setValidator(validatorPitch);
_lineRoll->setValidator(validatorRoll);
_lineYaw->setValidator(validatorYaw);
}
{
QLabel* labelPitch = new QLabel;
labelPitch->setText("Pitch: ");
QHBoxLayout* layoutPitch = new QHBoxLayout;
layoutPitch->addStretch(1);
QString pitchTip = "Pitch or elevation: negative numbers tilt the camera "
"downwards; positive numbers tilt upwards.\nThe allowed range is [-90, 90]. "
"Internally, this corresponds to the x value in the quaternion.";
labelPitch->setToolTip(pitchTip);
_linePitch->setToolTip(pitchTip);
layoutPitch->addWidget(labelPitch);
layoutPitch->addWidget(_linePitch);
layoutWindow->addLayout(layoutPitch);
QLabel* labelRoll = new QLabel;
labelRoll ->setText("Roll: ");
QHBoxLayout* layoutRoll = new QHBoxLayout;
layoutRoll->addStretch(1);
QString rollTip = "Roll or bank: negative numbers rotate the camera counter-"
"clockwise; positive numbers clockwise.\nThe allowed range is [-180, 180]. "
"Internally, this corresponds to the z value in the quaternion.";
labelRoll->setToolTip(rollTip);
_lineRoll->setToolTip(rollTip);
layoutRoll->addWidget(labelRoll);
layoutRoll->addWidget(_lineRoll);
layoutWindow->addLayout(layoutRoll);
QLabel* labelYaw = new QLabel;
labelYaw ->setText("Yaw: ");
QHBoxLayout* layoutYaw = new QHBoxLayout;
layoutYaw->addStretch(1);
QString yawTip = "Yaw, heading, or azimuth: negative numbers pan the camera "
"to the left; positive numbers pan to the\nright. The allowed range is "
"[-360, 360]. Internally, this corresponds to the y value in the quaternion.";
labelYaw->setToolTip(yawTip);
_lineYaw->setToolTip(yawTip);
layoutYaw->addWidget(labelYaw);
layoutYaw->addWidget(_lineYaw);
layoutWindow->addLayout(layoutYaw);
}
{
QHBoxLayout* layoutButtonBox = new QHBoxLayout;
QPushButton* buttonSave = new QPushButton("OK");
buttonSave->setToolTip("Save global orientation changes");
buttonSave->setFocusPolicy(Qt::NoFocus);
layoutButtonBox->addStretch(1);
layoutButtonBox->addWidget(buttonSave);
QPushButton* buttonCancel = new QPushButton("Cancel");
buttonCancel->setToolTip("Cancel global orientation changes");
buttonCancel->setFocusPolicy(Qt::NoFocus);
layoutButtonBox->addWidget(buttonCancel);
layoutButtonBox->addStretch(1);
connect(buttonSave, &QPushButton::released, this, &OrientationDialog::ok);
connect(buttonCancel, &QPushButton::released, this, &OrientationDialog::cancel);
layoutWindow->addLayout(layoutButtonBox);
}
}
void OrientationDialog::ok() {
_orientationValue.x = _linePitch->text().toFloat() / 180.0 * glm::pi<float>();
_orientationValue.y = _lineYaw->text().toFloat() / 180.0 * glm::pi<float>();
_orientationValue.z = _lineRoll->text().toFloat() / 180.0 * glm::pi<float>();
_orientationValue.w = 1.0;
accept();
}
void OrientationDialog::cancel() {
reject();
}

View File

@@ -0,0 +1,139 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "sgctedit/sgctedit.h"
#include <QFileDialog>
SgctEdit::SgctEdit(QWidget* parent, std::vector<sgct::config::Window>& windowList,
sgct::config::Cluster& cluster, const QList<QScreen*>& screenList,
const std::string userConfigPath)
: QDialog(parent)
, _cluster(cluster)
, _windowList(windowList)
, _userConfigPath(userConfigPath)
{
systemMonitorConfiguration(screenList);
setWindowTitle("Window Configuration Editor");
createWidgets();
}
void SgctEdit::systemMonitorConfiguration(const QList<QScreen*>& screenList) {
size_t nScreensManaged = std::min(screenList.length(), 2);
for (unsigned int s = 0; s < static_cast<unsigned int>(nScreensManaged); ++s) {
int actualWidth = std::max(
screenList[s]->size().width(),
screenList[s]->availableGeometry().width()
);
int actualHeight = std::max(
screenList[s]->size().height(),
screenList[s]->availableGeometry().height()
);
_monitorSizeList.push_back({
screenList[s]->availableGeometry().x(),
screenList[s]->availableGeometry().y(),
actualWidth,
actualHeight
});
}
_nMaxWindows = (_monitorSizeList.size() == 1) ? 3 : 4;
}
void SgctEdit::createWidgets() {
QVBoxLayout* layoutMainV = new QVBoxLayout(this);
QHBoxLayout* layoutMainH = new QHBoxLayout;
_orientationWidget = new Orientation();
{
_monBox = std::make_shared<MonitorBox>(
_monitorWidgetSize,
_monitorSizeList,
_nMaxWindows,
_colorsForWindows
);
QHBoxLayout* layoutMonBox = new QHBoxLayout;
layoutMonBox->addStretch(1);
layoutMonBox->addWidget(_monBox.get());
layoutMonBox->addStretch(1);
layoutMainV->addLayout(layoutMonBox);
addDisplayLayout(layoutMainH);
}
{
layoutMainV->addLayout(layoutMainH);
_orientationWidget->addControlsToParentLayout(layoutMainV);
QFrame* bottomBorder = new QFrame();
bottomBorder->setFrameShape(QFrame::HLine);
layoutMainV->addWidget(bottomBorder);
SgctConfigElements sgctCfg = {_windowList, _cluster};
UserConfigurationElements userCfg = {
_monitorSizeList,
_displayWidget,
_orientationWidget,
_userConfigPath
};
_fileSupportWidget = new FileSupport(
layoutMainV,
userCfg,
sgctCfg,
[this](bool accepted) {
if (accepted) {
_saveSelected = true;
accept();
}
else {
reject();
}
}
);
}
}
void SgctEdit::addDisplayLayout(QHBoxLayout* layout) {
_displayLayout = new QVBoxLayout;
_displayWidget = std::make_shared<DisplayWindowUnion>(
_monBox,
_monitorSizeList,
_nMaxWindows,
_colorsForWindows
);
_displayFrame = new QFrame;
_displayLayout->addWidget(_displayWidget.get());
_displayFrame->setLayout(_displayLayout);
_displayFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
layout->addWidget(_displayFrame);
}
bool SgctEdit::wasSaved() const {
return _saveSelected;
}
std::string SgctEdit::saveFilename() {
return _fileSupportWidget->saveFilename();
}
SgctEdit::~SgctEdit() {
delete _orientationWidget;
delete _fileSupportWidget;
delete _displayLayout;
}

View File

@@ -0,0 +1,677 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2022 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "sgctedit/windowcontrol.h"
#include <ghoul/fmt.h>
#include "sgctedit/displaywindowunion.h"
#include "sgctedit/monitorbox.h"
const std::string ProjectionTypeNames[5] = {"Planar", "Fisheye", "Spherical Mirror",
"Cylindrical", "Equirectangular"};
QList<QString> ProjectionTypes = {
QString::fromStdString(ProjectionTypeNames[static_cast<int>(
WindowControl::ProjectionIndeces::Planar)]),
QString::fromStdString(ProjectionTypeNames[static_cast<int>(
WindowControl::ProjectionIndeces::Fisheye)]),
QString::fromStdString(ProjectionTypeNames[static_cast<int>(
WindowControl::ProjectionIndeces::SphericalMirror)]),
QString::fromStdString(ProjectionTypeNames[static_cast<int>(
WindowControl::ProjectionIndeces::Cylindrical)]),
QString::fromStdString(ProjectionTypeNames[static_cast<int>(
WindowControl::ProjectionIndeces::Equirectangular)])
};
const QList<QString> QualityTypes = {
"Low (256)",
"Medium (512)",
"High (1K)",
"1.5K (1536)",
"2K (2048)",
"4K (4096)",
"8K (8192)",
"16K (16384)",
"32K (32768)",
"64K (65536)"
};
WindowControl::WindowControl(unsigned int monitorIndex, unsigned int windowIndex,
std::vector<QRect>& monitorDims,
const QColor& winColor, QWidget *parent)
: QWidget(parent)
, _monIndex(monitorIndex)
, _monIndexDefault(monitorIndex)
, _index(windowIndex)
, _monitorResolutions(monitorDims)
, _colorForWindow(winColor)
{
Q_INIT_RESOURCE(resources);
_nMonitors = static_cast<unsigned int>(_monitorResolutions.size());
createWidgets(parent);
resetToDefaults();
}
WindowControl::~WindowControl() {
delete _layoutFullWindow;
}
void WindowControl::resetToDefaults() {
determineIdealWindowSize();
_windowName->setText("");
_monIndex = _monIndexDefault;
if (_nMonitors > 1) {
_comboMonitorSelect->setCurrentIndex(_monIndexDefault);
}
_checkBoxWindowDecor->setCheckState(Qt::CheckState::Checked);
_checkBoxWebGui->setCheckState(Qt::CheckState::Unchecked);
onWebGuiSelection(_checkBoxWebGui->checkState());
_checkBoxSpoutOutput->setCheckState(Qt::CheckState::Unchecked);
onSpoutSelection(_checkBoxSpoutOutput->checkState());
_comboProjection->setCurrentIndex(static_cast<int>(ProjectionIndeces::Planar));
onProjectionChanged(_comboProjection->currentIndex());
_lineFovH->setText(QString::number(_defaultFovH));
_lineFovV->setText(QString::number(_defaultFovV));
_lineHeightOffset->setText(QString::number(_defaultHeightOffset));
_comboQuality->setCurrentIndex(2);
if (_windowChangeCallback) {
_windowChangeCallback(_monIndex, _index, _windowDims);
}
}
void WindowControl::determineIdealWindowSize() {
constexpr float idealAspectRatio = 16.f / 9.f;
constexpr float idealScaleVerticalLines = 2.f / 3.f;
const unsigned int primaryMonitorIdx = 0;
_windowDims = defaultWindowSizes[_index];
_offsetX->setText(QString::number(_windowDims.x()));
_offsetY->setText(QString::number(_windowDims.y()));
float newHeight = static_cast<float>(_monitorResolutions[primaryMonitorIdx].height())
* idealScaleVerticalLines;
float newWidth = newHeight * idealAspectRatio;
_windowDims.setHeight(newHeight);
_windowDims.setWidth(newWidth);
_sizeX->setText(QString::number(static_cast<int>(newWidth)));
_sizeY->setText(QString::number(static_cast<int>(newHeight)));
}
QString WindowControl::resolutionLabelText(QRect resolution) {
return QString::number(resolution.width()) + "x" +
QString::number(resolution.height());
}
void WindowControl::createWidgets(QWidget* parent) {
_windowName = new QLineEdit(parent);
_sizeX = new QLineEdit(parent);
_sizeY = new QLineEdit(parent);
_offsetX = new QLineEdit(parent);
_offsetY = new QLineEdit(parent);
_labelQuality = new QLabel;
_labelFovH = new QLabel;
_labelFovV = new QLabel;
_labelHeightOffset = new QLabel;
_buttonLockAspectRatio = new QPushButton(parent);
_buttonLockFov = new QPushButton(parent);
_lockIcon.addPixmap(QPixmap(":/images/outline_locked.png"));
_unlockIcon.addPixmap(QPixmap(":/images/outline_unlocked.png"));
_buttonLockAspectRatio->setIcon(_unlockIcon);
_buttonLockFov->setIcon(_lockIcon);
{
QIntValidator* validatorSizeX = new QIntValidator(10, _maxWindowSizePixels);
QIntValidator* validatorSizeY = new QIntValidator(10, _maxWindowSizePixels);
QIntValidator* validatorOffsetX = new QIntValidator(
-_maxWindowSizePixels,
_maxWindowSizePixels
);
QIntValidator* validatorOffsetY = new QIntValidator(
-_maxWindowSizePixels,
_maxWindowSizePixels
);
_sizeX->setValidator(validatorSizeX);
_sizeY->setValidator(validatorSizeY);
_offsetX->setValidator(validatorOffsetX);
_offsetY->setValidator(validatorOffsetY);
}
if (_nMonitors > 1) {
_comboMonitorSelect = new QComboBox(this);
for (unsigned int i = 0; i < _nMonitors; ++i) {
_monitorNames[i] += " (" + resolutionLabelText(_monitorResolutions[i]) + ")";
}
_comboMonitorSelect->addItems(_monitorNames);
_comboMonitorSelect->setCurrentIndex(_monIndexDefault);
}
_fullscreenButton = new QPushButton(this);
_fullscreenButton->setText("Set to Fullscreen");
_checkBoxWindowDecor = new QCheckBox("Window Decoration", this);
_checkBoxWindowDecor->setCheckState(Qt::CheckState::Checked);
_checkBoxWebGui = new QCheckBox("WebGUI only this window", this);
_checkBoxSpoutOutput = new QCheckBox("Spout Output", this);
_comboProjection = new QComboBox(this);
_comboProjection->addItems(ProjectionTypes);
_comboQuality = new QComboBox(this);
_comboQuality->addItems(QualityTypes);
{
_lineFovH = new QLineEdit(QString::number(_defaultFovH), parent);
_lineFovV = new QLineEdit(QString::number(_defaultFovV), parent);
QDoubleValidator* validatorFovH = new QDoubleValidator(-180.0, 180.0, 10);
_lineFovH->setValidator(validatorFovH);
QDoubleValidator* validatorFovV = new QDoubleValidator(-90.0, 90.0, 10);
_lineFovV->setValidator(validatorFovV);
_lineHeightOffset = new QLineEdit(QString::number(_defaultHeightOffset), parent);
QDoubleValidator* validatorHtOff= new QDoubleValidator(-1000000.0, 1000000.0, 12);
_lineHeightOffset->setValidator(validatorHtOff);
}
connect(_sizeX, &QLineEdit::textChanged, this, &WindowControl::onSizeXChanged);
connect(_sizeY, &QLineEdit::textChanged, this, &WindowControl::onSizeYChanged);
connect(_offsetX, &QLineEdit::textChanged, this, &WindowControl::onOffsetXChanged);
connect(_offsetY, &QLineEdit::textChanged, this, &WindowControl::onOffsetYChanged);
if (_nMonitors > 1) {
connect(
_comboMonitorSelect,
qOverload<int>(&QComboBox::currentIndexChanged),
this,
&WindowControl::onMonitorChanged
);
}
connect(
_comboProjection,
qOverload<int>(&QComboBox::currentIndexChanged),
this,
&WindowControl::onProjectionChanged
);
connect(
_checkBoxSpoutOutput,
&QCheckBox::stateChanged,
this,
&WindowControl::onSpoutSelection
);
connect(
_checkBoxWebGui,
&QCheckBox::stateChanged,
this,
&WindowControl::onWebGuiSelection
);
connect(
_fullscreenButton,
&QPushButton::released,
this,
&WindowControl::onFullscreenClicked
);
connect(
_buttonLockAspectRatio,
&QPushButton::released,
this,
&WindowControl::onAspectRatioLockClicked
);
connect(
_buttonLockFov,
&QPushButton::released,
this,
&WindowControl::onFovLockClicked
);
}
QVBoxLayout* WindowControl::initializeLayout() {
_layoutFullWindow = new QVBoxLayout;
//Window size
QVBoxLayout* layoutWindowCtrl = new QVBoxLayout;
_labelWinNum = new QLabel;
_labelWinNum->setText("Window " + QString::number(_index + 1));
QString colorStr = QString::fromStdString(
fmt::format("QLabel {{ color : #{:02x}{:02x}{:02x}; }}",
_colorForWindow.red(), _colorForWindow.green(), _colorForWindow.blue()));
_labelWinNum->setStyleSheet(colorStr);
QHBoxLayout* layoutWinNum = new QHBoxLayout;
layoutWinNum->addStretch(1);
layoutWinNum->addWidget(_labelWinNum);
layoutWinNum->addStretch(1);
layoutWindowCtrl->addLayout(layoutWinNum);
{
QHBoxLayout* layoutName = new QHBoxLayout;
QString tip("Enter a name for the window (displayed in title bar)");
QLabel* labelName = new QLabel(this);
labelName->setText("Name: ");
labelName->setToolTip(tip);
_windowName->setFixedWidth(160);
_windowName->setToolTip(tip);
layoutName->addWidget(labelName);
layoutName->addWidget(_windowName);
layoutName->addStretch(1);
layoutWindowCtrl->addLayout(layoutName);
}
if (_nMonitors > 1) {
QHBoxLayout* layoutMonitorNum = new QHBoxLayout;
QLabel* labelLocation = new QLabel(this);
labelLocation->setText("Monitor: ");
QString tip("Select monitor where this window is located");
labelLocation->setToolTip(tip);
_comboMonitorSelect->setToolTip(tip);
layoutMonitorNum->addWidget(labelLocation);
layoutMonitorNum->addWidget(_comboMonitorSelect);
layoutMonitorNum->addStretch(1);
layoutWindowCtrl->addLayout(layoutMonitorNum);
}
_sizeX->setFixedWidth(_lineEditWidthFixedWinSize);
_sizeY->setFixedWidth(_lineEditWidthFixedWinSize);
{
QLabel* labelSize = new QLabel(this);
QLabel* labelDelim = new QLabel(this);
QLabel* labelUnit = new QLabel(this);
QHBoxLayout* layoutSize = new QHBoxLayout;
labelSize->setToolTip("Enter window width & height in pixels");
_sizeX->setToolTip("Enter window width (pixels)");
_sizeY->setToolTip("Enter window height (pixels)");
_buttonLockAspectRatio->setFocusPolicy(Qt::NoFocus);
_buttonLockAspectRatio->setToolTip("Locks/Unlocks size aspect ratio");
layoutSize->addWidget(labelSize);
labelSize->setText("Size:");
labelSize->setFixedWidth(55);
layoutSize->addWidget(_sizeX);
layoutSize->addWidget(labelDelim);
layoutSize->addWidget(_sizeY);
layoutSize->addWidget(labelUnit);
layoutSize->addWidget(_buttonLockAspectRatio);
layoutSize->addStretch(1);
labelDelim->setText("x");
labelDelim->setFixedWidth(9);
labelUnit->setText(" px");
layoutWindowCtrl->addLayout(layoutSize);
}
_offsetX->setFixedWidth(_lineEditWidthFixedWinSize);
_offsetY->setFixedWidth(_lineEditWidthFixedWinSize);
{
QLabel* labelOffset = new QLabel(this);
QLabel* labelComma = new QLabel(this);
QLabel* labelUnit = new QLabel(this);
QHBoxLayout* layoutOffset = new QHBoxLayout;
std::string baseTip = "Enter {} location of window's upper left "
"corner from monitor's {} (pixels)";
labelOffset->setToolTip(QString::fromStdString(fmt::format(
baseTip, "x,y", "upper-left corner origin")));
_offsetX->setToolTip(QString::fromStdString(fmt::format(
baseTip, "x", "left side")));
_offsetY->setToolTip(QString::fromStdString(fmt::format(
baseTip, "y", "top edge")));
layoutOffset->addWidget(labelOffset);
labelOffset->setText("Offset:");
labelOffset->setFixedWidth(55);
layoutOffset->addWidget(_offsetX);
layoutOffset->addWidget(labelComma);
layoutOffset->addWidget(_offsetY);
layoutOffset->addWidget(labelUnit);
layoutOffset->addStretch(1);
labelComma->setText(",");
labelComma->setFixedWidth(9);
labelUnit->setText(" px");
layoutWindowCtrl->addLayout(layoutOffset);
}
{
QHBoxLayout* layoutCheckboxesFull1 = new QHBoxLayout;
QVBoxLayout* layoutCheckboxesFull2 = new QVBoxLayout;
QHBoxLayout* layoutFullscreenButton = new QHBoxLayout;
_fullscreenButton->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.");
_fullscreenButton->setFocusPolicy(Qt::NoFocus);
layoutFullscreenButton->addWidget(_fullscreenButton);
layoutFullscreenButton->addStretch(1);
layoutCheckboxesFull2->addLayout(layoutFullscreenButton);
QHBoxLayout* layoutCBoxWindowDecor = new QHBoxLayout;
_checkBoxWindowDecor->setToolTip("If enabled, the window will not have a border "
"frame or title bar, and no\n controls for minimizing/maximizing, "
"resizing, or closing the window.");
layoutCBoxWindowDecor->addWidget(_checkBoxWindowDecor);
layoutCBoxWindowDecor->addStretch(1);
layoutCheckboxesFull2->addLayout(layoutCBoxWindowDecor);
QHBoxLayout* _layoutCBoxWebGui= new QHBoxLayout;
_checkBoxWebGui->setToolTip("If enabled, the window will be dedicated solely to "
"displaying the GUI controls, and will not\nrender any 3D content. All other "
"window(s) will render in 3D but will not have GUI controls.");
_layoutCBoxWebGui->addWidget(_checkBoxWebGui);
_layoutCBoxWebGui->addStretch(1);
layoutCheckboxesFull2->addLayout(_layoutCBoxWebGui);
QVBoxLayout* layoutProjectionGroup = new QVBoxLayout;
QHBoxLayout* layoutComboProjection = new QHBoxLayout;
_comboProjection->setToolTip("Select from the supported window projection types");
layoutComboProjection->addWidget(_comboProjection);
layoutComboProjection->addWidget(_buttonLockFov);
_buttonLockFov->setToolTip("Locks and scales the Horizontal & Vertical F.O.V. "
"to the ideal settings based on aspect ratio.");
_buttonLockFov->setFocusPolicy(Qt::NoFocus);
layoutComboProjection->addStretch(1);
layoutProjectionGroup->addLayout(layoutComboProjection);
QFrame* borderProjectionGroup = new QFrame;
borderProjectionGroup->setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
borderProjectionGroup->setLayout(layoutProjectionGroup);
borderProjectionGroup->setVisible(true);
QHBoxLayout* layoutCBoxSpoutOutput= new QHBoxLayout;
QString spoutTip = "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\n"
"images available to other real-time applications on the same machine for "
"further processing.\nThe SpoutOutputProjection option can work with either "
"Fisheye or Equirectangular projection.";
_checkBoxSpoutOutput->setToolTip(spoutTip);
layoutCBoxSpoutOutput->addWidget(_checkBoxSpoutOutput);
layoutCBoxSpoutOutput->addStretch(1);
layoutProjectionGroup->addLayout(layoutCBoxSpoutOutput);
QHBoxLayout* layoutComboQuality = new QHBoxLayout;
_labelQuality->setText("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.";
_labelQuality->setToolTip(qualityTip);
_comboQuality->setToolTip(qualityTip);
layoutComboQuality->addWidget(_labelQuality);
layoutComboQuality->addWidget(_comboQuality);
layoutComboQuality->addStretch(1);
layoutProjectionGroup->addLayout(layoutComboQuality);
QHBoxLayout* layoutFovH = new QHBoxLayout;
_labelFovH->setText("Horizontal FOV:");
QString hfovTip = "The total horizontal field of view of the viewport (degrees). "
"Internally,\nthe values for 'left' & 'right' will each be half this value.";
_labelFovH->setToolTip(hfovTip);
_lineFovH->setToolTip(hfovTip);
layoutFovH->addWidget(_labelFovH);
layoutFovH->addStretch(1);
layoutFovH->addWidget(_lineFovH);
QHBoxLayout* layoutFovV = new QHBoxLayout;
_labelFovV->setText("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.";
_labelFovV->setToolTip(vfovTip);
_lineFovV->setToolTip(vfovTip);
layoutFovV->addWidget(_labelFovV);
layoutFovV->addStretch(1);
layoutFovV->addWidget(_lineFovV);
_lineFovH->setFixedWidth(_lineEditWidthFixedFov);
_lineFovV->setFixedWidth(_lineEditWidthFixedFov);
_lineFovH->setEnabled(false);
_lineFovV->setEnabled(false);
layoutProjectionGroup->addLayout(layoutFovH);
layoutProjectionGroup->addLayout(layoutFovV);
QHBoxLayout* layoutHeightOffset = new QHBoxLayout;
_labelHeightOffset->setText("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.";
_labelHeightOffset->setToolTip(heightTip);
_lineHeightOffset->setToolTip(heightTip);
layoutHeightOffset->addWidget(_labelHeightOffset);
layoutHeightOffset->addWidget(_lineHeightOffset);
layoutHeightOffset->addStretch(1);
layoutProjectionGroup->addLayout(layoutHeightOffset);
layoutCheckboxesFull2->addWidget(borderProjectionGroup);
layoutCheckboxesFull1->addLayout(layoutCheckboxesFull2);
layoutCheckboxesFull1->addStretch(1);
layoutWindowCtrl->addLayout(layoutCheckboxesFull1);
}
layoutWindowCtrl->addStretch(1);
_layoutFullWindow->addLayout(layoutWindowCtrl);
_comboProjection->setCurrentIndex(0);
onProjectionChanged(static_cast<unsigned int>(ProjectionIndeces::Planar));
_comboQuality->setCurrentIndex(2);
return _layoutFullWindow;
}
void WindowControl::showWindowLabel(bool show) {
_labelWinNum->setVisible(show);
}
void WindowControl::onSizeXChanged(const QString& newText) {
_windowDims.setWidth(newText.toInt());
if (_aspectRatioLocked) {
int updatedHeight = _windowDims.width() / _aspectRatioSize;
_sizeY->blockSignals(true);
_sizeY->setText(QString::number(updatedHeight));
_sizeY->blockSignals(false);
_windowDims.setHeight(updatedHeight);
}
if (_windowChangeCallback) {
_windowChangeCallback(_monIndex, _index, _windowDims);
}
if (_FovLocked) {
updatePlanarLockedFov();
}
}
void WindowControl::onSizeYChanged(const QString& newText) {
_windowDims.setHeight(newText.toInt());
if (_aspectRatioLocked) {
int updatedWidth = _windowDims.height() * _aspectRatioSize;
_sizeX->blockSignals(true);
_sizeX->setText(QString::number(updatedWidth));
_sizeX->blockSignals(false);
_windowDims.setWidth(updatedWidth);
}
if (_windowChangeCallback) {
_windowChangeCallback(_monIndex, _index, _windowDims);
}
if (_FovLocked) {
updatePlanarLockedFov();
}
}
void WindowControl::onOffsetXChanged(const QString& newText) {
float prevWidth = _windowDims.width();
try {
_windowDims.setX(newText.toInt());
_windowDims.setWidth(prevWidth);
if (_windowChangeCallback) {
_windowChangeCallback(_monIndex, _index, _windowDims);
}
}
catch (std::exception const&) {
//The QIntValidator ensures that the range is a +/- integer
//However, it's possible to enter only a - character which
//causes an exception throw, which is ignored here (when user
//enters an integer after the - then the value will be updated).
}
}
void WindowControl::onOffsetYChanged(const QString& newText) {
float prevHeight = _windowDims.height();
try {
_windowDims.setY(newText.toInt());
_windowDims.setHeight(prevHeight);
if (_windowChangeCallback) {
_windowChangeCallback(_monIndex, _index, _windowDims);
}
}
catch (std::exception const&) {
//See comment in onOffsetXChanged
}
}
void WindowControl::onFullscreenClicked() {
_offsetX->setText("0");
_offsetY->setText("0");
_sizeX->setText(QString::number(_monitorResolutions[_monIndex].width()));
_sizeY->setText(QString::number(_monitorResolutions[_monIndex].height()));
_checkBoxWindowDecor->setCheckState(Qt::Unchecked);
}
void WindowControl::onWebGuiSelection(int selectionState) {
if (_windowGuiCheckCallback && (selectionState == Qt::Checked)) {
_windowGuiCheckCallback(_index);
}
}
void WindowControl::onSpoutSelection(int selectionState) {
if (selectionState == Qt::Checked) {
WindowControl::ProjectionIndeces currentProjectionSelection;
currentProjectionSelection = static_cast<WindowControl::ProjectionIndeces>(
_comboProjection->currentIndex()
);
if ((currentProjectionSelection != ProjectionIndeces::Equirectangular) &&
(currentProjectionSelection != ProjectionIndeces::Fisheye))
{
_comboProjection->setCurrentIndex(
static_cast<int>(ProjectionIndeces::Equirectangular)
);
}
}
}
void WindowControl::onMonitorChanged(int newSelection) {
_monIndex = newSelection;
if (_windowChangeCallback) {
_windowChangeCallback(_monIndex, _index, _windowDims);
}
}
void WindowControl::onProjectionChanged(int newSelection) {
WindowControl::ProjectionIndeces selected
= static_cast<WindowControl::ProjectionIndeces>(newSelection);
_comboQuality->setVisible(selected != ProjectionIndeces::Planar);
_labelQuality->setVisible(selected != ProjectionIndeces::Planar);
_labelFovH->setVisible(selected == ProjectionIndeces::Planar);
_lineFovH->setVisible(selected == ProjectionIndeces::Planar);
_labelFovV->setVisible(selected == ProjectionIndeces::Planar);
_lineFovV->setVisible(selected == ProjectionIndeces::Planar);
_buttonLockFov->setVisible(selected == ProjectionIndeces::Planar);
_labelHeightOffset->setVisible(selected == ProjectionIndeces::Cylindrical);
_lineHeightOffset->setVisible(selected == ProjectionIndeces::Cylindrical);
_checkBoxSpoutOutput->setVisible(selected == ProjectionIndeces::Fisheye
|| selected == ProjectionIndeces::Equirectangular);
}
void WindowControl::onAspectRatioLockClicked() {
_aspectRatioLocked = !_aspectRatioLocked;
_buttonLockAspectRatio->setIcon(_aspectRatioLocked ? _lockIcon : _unlockIcon);
if (_aspectRatioLocked) {
_aspectRatioSize = _windowDims.width() / _windowDims.height();
}
}
void WindowControl::onFovLockClicked() {
_FovLocked = !_FovLocked;
_buttonLockFov->setIcon(_FovLocked ? _lockIcon : _unlockIcon);
if (_FovLocked) {
_lineFovH->setEnabled(false);
_lineFovV->setEnabled(false);
updatePlanarLockedFov();
}
else {
_lineFovH->setEnabled(true);
_lineFovV->setEnabled(true);
}
}
void WindowControl::updatePlanarLockedFov() {
float currentAspectRatio = _windowDims.width() / _windowDims.height();
float relativeRatio = currentAspectRatio / _idealAspectRatio;
if (relativeRatio >= 1.0) {
_lineFovH->setText(QString::number(std::min(_defaultFovH *relativeRatio, 180.f)));
_lineFovV->setText(QString::number(_defaultFovV));
}
else {
_lineFovH->setText(QString::number(_defaultFovH));
_lineFovV->setText(QString::number(std::min(_defaultFovV /relativeRatio, 180.f)));
}
}
void WindowControl::setWindowChangeCallback(
std::function<void(int, int, const QRectF&)> cb)
{
_windowChangeCallback = std::move(cb);
}
void WindowControl::setWebGuiChangeCallback(std::function<void(unsigned int)> cb)
{
_windowGuiCheckCallback = std::move(cb);
}
void WindowControl::uncheckWebGuiOption() {
_checkBoxWebGui->setCheckState(Qt::Unchecked);
}
QRectF& WindowControl::dimensions() {
return _windowDims;
}
std::string WindowControl::windowName() const {
return _windowName->text().toStdString();
}
sgct::ivec2 WindowControl::windowSize() const {
return {
_sizeX->text().toInt(),
_sizeY->text().toInt()
};
}
sgct::ivec2 WindowControl::windowPos() const {
return {
_offsetX->text().toInt(),
_offsetY->text().toInt()
};
}
bool WindowControl::isDecorated() const {
return (_checkBoxWindowDecor->checkState() == Qt::Checked);
}
bool WindowControl::isGuiWindow() const {
return (_checkBoxWebGui->checkState() == Qt::Checked);
}
bool WindowControl::isSpoutSelected() const {
return (_checkBoxSpoutOutput->checkState() == Qt::Checked);
}
WindowControl::ProjectionIndeces WindowControl::projectionSelectedIndex() const {
return
static_cast<WindowControl::ProjectionIndeces>(_comboProjection->currentIndex());
}
int WindowControl::qualitySelectedValue() const {
return QualityValues[_comboQuality->currentIndex()];
}
float WindowControl::fovH() const {
return _lineFovH->text().toFloat();
}
float WindowControl::fovV() const {
return _lineFovV->text().toFloat();
}
float WindowControl::heightOffset() const {
return _lineHeightOffset->text().toFloat();
}
unsigned int WindowControl::monitorNum() const {
return _monIndex;
}