mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-05 19:19:39 -06:00
Feature/UI launcher accessibility (#3417)
* update background and foreground colors in launcher * Change tab order and preliminary focus visuals * update focus color Improves on #3091 but does not fixes it, the contrast ratio is 2.4/2.9-3.3 versus the white border/the gray background on each button/dropdown * update focus border width * Update color of error messages fixes #3103 * Enable enter key interaction on ui launcher buttons fixes #3092 * Update accessibility names on buttons and fields where the current readout does not make sense, fixes #3089 * Fixed issue where you could not tab out of multiline textfields * Add overlay to the launcher image to increase contrast * Slightly improves readability of Start button fixes #3096 We decided to keep the all caps to indicate call to action * Add start button to have default focus which enables quick start by pressing enter or space on startup * Removed overriden object name * Update color label text for better clarity fixes #3094 The actual fix is in #9a7e8e1 * Add `esc` keypress to exit the launcher fixes #3097 * add placeholder text for profile name fixes #3101 * Fixed issue with properties, assets, and keybindings multiline readout, fixes #3098 * Change tab order of properties, assets, and keybindings: text area -> edit button, fixes #3099 * Add prompt to user warning of unsaved changes in profile editor * Add error message dialog fixes #3100 * Removed unused code * Remove hardcoded color for information text in cameradialog * Don't compare profile files but profiles instead * Add same focus outline to all buttons in launcher --------- Co-authored-by: Alexander Bock <mail@alexanderbock.eu> Co-authored-by: Alexander Bock <alexander.bock@liu.se>
This commit is contained in:
@@ -88,6 +88,13 @@ public:
|
||||
*/
|
||||
bool isUserConfigSelected() const;
|
||||
|
||||
/**
|
||||
* Handles keypresses while the Qt launcher window is open.
|
||||
*
|
||||
* \param evt QKeyEevent object of the key press event
|
||||
*/
|
||||
void keyPressEvent(QKeyEvent* evt) override;
|
||||
|
||||
private:
|
||||
QWidget* createCentralWidget();
|
||||
void setBackgroundImage(const std::filesystem::path& syncPath);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
class QDialogButtonBox;
|
||||
class QErrorMessage;
|
||||
class QGridLayout;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
@@ -78,7 +79,7 @@ private:
|
||||
struct {
|
||||
QListWidget* list = nullptr;
|
||||
QLineEdit* identifier = nullptr;
|
||||
QLabel* infoText = nullptr;
|
||||
QErrorMessage* infoText = nullptr;
|
||||
QLineEdit* name = nullptr;
|
||||
QLineEdit* guiPath = nullptr;
|
||||
QLineEdit* documentation = nullptr;
|
||||
|
||||
@@ -48,8 +48,6 @@ private:
|
||||
|
||||
QBoxLayout* _layout = nullptr;
|
||||
QLineEdit* _nameEdit = nullptr;
|
||||
|
||||
QLabel* _errorMsg = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___ASSETEDIT___H__
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QMessageBox;
|
||||
class QTabWidget;
|
||||
|
||||
class CameraDialog final : public QDialog {
|
||||
@@ -88,7 +89,7 @@ private:
|
||||
QLineEdit* altitude = nullptr;
|
||||
} _geoState;
|
||||
|
||||
QLabel* _errorMsg = nullptr;
|
||||
QMessageBox* _errorMsg = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___CAMERA___H__
|
||||
|
||||
@@ -97,8 +97,6 @@ private:
|
||||
QPushButton* _saveButton = nullptr;
|
||||
QPushButton* _discardButton = nullptr;
|
||||
QDialogButtonBox* _buttonBox = nullptr;
|
||||
|
||||
QLabel* _errorMsg = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___DELTATIMESDIALOG___H__
|
||||
|
||||
@@ -121,7 +121,6 @@ private:
|
||||
QLabel* _downloadLabel = nullptr;
|
||||
QPlainTextEdit* _log = nullptr;
|
||||
|
||||
QLabel* _errorMsg = nullptr;
|
||||
std::string _latestHorizonsError;
|
||||
};
|
||||
|
||||
|
||||
@@ -86,8 +86,6 @@ private:
|
||||
QPushButton* _buttonSave = nullptr;
|
||||
QPushButton* _buttonCancel = nullptr;
|
||||
QDialogButtonBox* _buttonBox = nullptr;
|
||||
|
||||
QLabel* _errorMsg = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___MODULESDIALOG___H__
|
||||
|
||||
@@ -79,6 +79,13 @@ public:
|
||||
*/
|
||||
virtual void keyPressEvent(QKeyEvent* evt) override;
|
||||
|
||||
void reject() override;
|
||||
void closeWithoutSaving();
|
||||
void promptUserOfUnsavedChanges();
|
||||
|
||||
signals:
|
||||
void raiseExitWindow();
|
||||
|
||||
private slots:
|
||||
void duplicateProfile();
|
||||
void openMeta();
|
||||
@@ -91,7 +98,6 @@ private slots:
|
||||
void openDeltaTimes();
|
||||
void openCamera();
|
||||
void openMarkNodes();
|
||||
void cancel();
|
||||
void approved();
|
||||
|
||||
private:
|
||||
@@ -119,8 +125,6 @@ private:
|
||||
QLabel* _timeLabel = nullptr;
|
||||
QLabel* _metaLabel = nullptr;
|
||||
QLabel* _additionalScriptsLabel = nullptr;
|
||||
|
||||
QLabel* _errorMsg = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___PROFILEEDIT___H__
|
||||
|
||||
@@ -34,6 +34,7 @@ class QDialogButtonBox;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QListWidget;
|
||||
class QMessageBox;
|
||||
class QPushButton;
|
||||
|
||||
class PropertiesDialog final : public QDialog {
|
||||
@@ -93,7 +94,7 @@ private:
|
||||
QPushButton* _cancelButton = nullptr;
|
||||
QDialogButtonBox* _buttonBox = nullptr;
|
||||
|
||||
QLabel* _errorMsg = nullptr;
|
||||
QMessageBox* _errorMsg = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___PROPERTIESDIALOG___H__
|
||||
|
||||
@@ -9,8 +9,13 @@ QLabel#heading {
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
QLabel#error-message {
|
||||
color: rgb(221, 17, 17);
|
||||
QPushButton:focus,
|
||||
QTextEdit:focus,
|
||||
QTabWidget:focus,
|
||||
QCheckBox:focus,
|
||||
QComboBox:focus {
|
||||
outline: none;
|
||||
border: 2px solid rgb(61, 189, 238);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -22,7 +27,7 @@ LauncherWindow QLabel {
|
||||
}
|
||||
|
||||
LauncherWindow QLabel#label_choose, QLabel#label_options {
|
||||
color: #dddddd;
|
||||
color: rgb(255, 255, 255);
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
@@ -36,10 +41,9 @@ LauncherWindow QLabel#version-info {
|
||||
}
|
||||
|
||||
LauncherWindow QComboBox#config {
|
||||
background: rgb(96, 96, 96);
|
||||
border: 1px solid rgb(128, 128, 128);
|
||||
border-radius: 3px;
|
||||
border-color: rgb(225, 225, 225);
|
||||
background: rgb(86, 86, 86);
|
||||
border: 1px solid rgb(225, 225, 225);
|
||||
border-radius: 2px;
|
||||
padding: 1px 18px 1px 3px;
|
||||
min-width: 14em;
|
||||
font-size: 10pt;
|
||||
@@ -49,7 +53,7 @@ LauncherWindow QComboBox#config {
|
||||
}
|
||||
|
||||
LauncherWindow QComboBox#config:hover {
|
||||
background: rgb(120, 120, 120);
|
||||
background: rgb(110, 110, 110);
|
||||
}
|
||||
|
||||
LauncherWindow QComboBox#config:disabled {
|
||||
@@ -57,26 +61,25 @@ LauncherWindow QComboBox#config:disabled {
|
||||
color: rgb(225, 225, 225);
|
||||
}
|
||||
|
||||
LauncherWindow QPushButton#large {
|
||||
background: rgb(128, 128, 128);
|
||||
LauncherWindow QPushButton#start {
|
||||
background: rgb(96, 96, 96);
|
||||
border: 2px solid rgb(225, 225, 225);
|
||||
border-radius: 2px;
|
||||
border-style: outset;
|
||||
border-width: 2px;
|
||||
border-color: rgb(225, 225, 225);
|
||||
font-size: 16pt;
|
||||
font-weight: bold;
|
||||
color: rgb(239, 239, 239);
|
||||
letter-spacing: 1px;
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
LauncherWindow QPushButton#large:hover {
|
||||
background: rgb(150, 150, 150);
|
||||
LauncherWindow QPushButton#start:hover {
|
||||
background: rgb(120, 120, 120);
|
||||
}
|
||||
|
||||
LauncherWindow QPushButton#small {
|
||||
background: rgb(96, 96, 96);
|
||||
background: rgb(86, 86, 86);
|
||||
border: 1px solid rgb(225, 225, 225);
|
||||
border-radius: 2px;
|
||||
border-style: outset;
|
||||
border-width: 1px;
|
||||
border-color: rgb(225, 225, 225);
|
||||
min-height: 1em;
|
||||
font-size: 10pt;
|
||||
font-weight: bold;
|
||||
@@ -84,12 +87,12 @@ LauncherWindow QPushButton#small {
|
||||
}
|
||||
|
||||
LauncherWindow QPushButton#small:hover {
|
||||
background: rgb(120, 120, 120);
|
||||
background: rgb(110, 110, 110);
|
||||
}
|
||||
|
||||
LauncherWindow QPushButton#small:disabled {
|
||||
color: rgb(180, 180, 180);
|
||||
background: rgb(160, 160, 160);
|
||||
background: rgb(204, 204, 204);
|
||||
color: rgb(86, 86, 86);
|
||||
}
|
||||
|
||||
LauncherWindow QPushButton#settings {
|
||||
@@ -101,7 +104,17 @@ LauncherWindow QPushButton#settings:hover {
|
||||
border-image: url(:/images/cogwheel-highlight);
|
||||
}
|
||||
|
||||
LauncherWindow QPushButton#small:focus,
|
||||
LauncherWindow QPushButton#start:focus,
|
||||
LauncherWindow QComboBox#config:focus
|
||||
{
|
||||
outline: none;
|
||||
border: 2px solid rgb(61, 189, 238);
|
||||
}
|
||||
|
||||
LauncherWindow QPushButton#settings:focus {
|
||||
outline: 2px solid rgb(61, 189, 238);
|
||||
}
|
||||
/*
|
||||
* ProfileEdit
|
||||
*/
|
||||
@@ -165,12 +178,7 @@ DeltaTimesDialog QListWidget {
|
||||
/*
|
||||
* Camera
|
||||
*/
|
||||
CameraDialog QLabel#error-message {
|
||||
min-width: 10em;
|
||||
}
|
||||
|
||||
CameraDialog QLabel#camera-description {
|
||||
color:rgb(96, 96, 96);
|
||||
margin: 1em;
|
||||
margin-top: 0.2em;
|
||||
margin-bottom: 0.4em;
|
||||
@@ -198,10 +206,6 @@ HorizonsDialog QLabel#thin {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
HorizonsDialog QLabel#error {
|
||||
color: rgb(221, 17, 17);
|
||||
}
|
||||
|
||||
HorizonsDialog QLabel#normal {
|
||||
color: rgb(0, 0, 0);
|
||||
}
|
||||
@@ -223,8 +227,13 @@ WindowControl QLabel#notice {
|
||||
/*
|
||||
* Settings
|
||||
*/
|
||||
SettingsWidget QLabel#information {
|
||||
SettingsDialog QLabel#information {
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
SettingsDialog QComboBox#dropdown:focus {
|
||||
outline: none;
|
||||
border: 2px solid rgb(61, 189, 238);
|
||||
}
|
||||
|
||||
@@ -34,9 +34,12 @@
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <sgct/readconfig.h>
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFile>
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QPainter>
|
||||
#include <QPushButton>
|
||||
#include <QStandardItemModel>
|
||||
#include <filesystem>
|
||||
@@ -51,6 +54,8 @@
|
||||
using namespace openspace;
|
||||
|
||||
namespace {
|
||||
constexpr std::string_view _loggerCat = "LauncherWindow";
|
||||
|
||||
constexpr int ScreenWidth = 480;
|
||||
constexpr int ScreenHeight = 640;
|
||||
|
||||
@@ -66,7 +71,7 @@ namespace {
|
||||
namespace geometry {
|
||||
constexpr QRect BackgroundImage(0, 0, ScreenWidth, ScreenHeight);
|
||||
constexpr QRect LogoImage(LeftRuler, TopRuler, ItemWidth, ItemHeight);
|
||||
constexpr QRect ChooseLabel(LeftRuler, TopRuler + 80, 151, 24);
|
||||
constexpr QRect ChooseLabel(LeftRuler + 10, TopRuler + 80, 151, 24);
|
||||
constexpr QRect ProfileBox(LeftRuler, TopRuler + 110, ItemWidth, ItemHeight);
|
||||
constexpr QRect NewProfileButton(
|
||||
LeftRuler + 160, TopRuler + 180, SmallItemWidth, SmallItemHeight
|
||||
@@ -74,7 +79,7 @@ namespace {
|
||||
constexpr QRect EditProfileButton(
|
||||
LeftRuler, TopRuler + 180, SmallItemWidth, SmallItemHeight
|
||||
);
|
||||
constexpr QRect OptionsLabel(LeftRuler, TopRuler + 230, 151, 24);
|
||||
constexpr QRect OptionsLabel(LeftRuler + 10, TopRuler + 230, 151, 24);
|
||||
constexpr QRect WindowConfigBox(LeftRuler, TopRuler + 260, ItemWidth, ItemHeight);
|
||||
constexpr QRect NewWindowButton(
|
||||
LeftRuler + 160, TopRuler + 330, SmallItemWidth, SmallItemHeight
|
||||
@@ -242,6 +247,10 @@ LauncherWindow::LauncherWindow(bool profileEnabled,
|
||||
}
|
||||
|
||||
setCentralWidget(createCentralWidget());
|
||||
QPushButton* startButton = centralWidget()->findChild<QPushButton*>("start");
|
||||
if (startButton) {
|
||||
startButton->setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
|
||||
populateProfilesList(globalConfig.profile);
|
||||
_profileBox->setEnabled(profileEnabled);
|
||||
@@ -277,43 +286,29 @@ QWidget* LauncherWindow::createCentralWidget() {
|
||||
logoImage->setPixmap(QPixmap(":/images/openspace-horiz-logo-small.png"));
|
||||
|
||||
QLabel* labelChoose = new QLabel("Choose Profile", centralWidget);
|
||||
labelChoose->setObjectName("clear");
|
||||
labelChoose->setGeometry(geometry::ChooseLabel);
|
||||
labelChoose->setObjectName("label_choose");
|
||||
|
||||
_profileBox = new QComboBox(centralWidget);
|
||||
_profileBox->setObjectName("config");
|
||||
_profileBox->setGeometry(geometry::ProfileBox);
|
||||
_profileBox->setAccessibleName("Choose profile");
|
||||
|
||||
QLabel* optionsLabel = new QLabel("Window Options", centralWidget);
|
||||
optionsLabel->setObjectName("clear");
|
||||
optionsLabel->setGeometry(geometry::OptionsLabel);
|
||||
optionsLabel->setObjectName("label_options");
|
||||
|
||||
_windowConfigBox = new QComboBox(centralWidget);
|
||||
_windowConfigBox->setObjectName("config");
|
||||
_windowConfigBox->setGeometry(geometry::WindowConfigBox);
|
||||
|
||||
QPushButton* startButton = new QPushButton("START", centralWidget);
|
||||
QPushButton* editProfileButton = new QPushButton("Edit", centralWidget);
|
||||
connect(
|
||||
startButton, &QPushButton::released,
|
||||
editProfileButton, &QPushButton::released,
|
||||
[this]() {
|
||||
if (_profileBox->currentText().isEmpty()) {
|
||||
QMessageBox::critical(
|
||||
this,
|
||||
"Empty Profile",
|
||||
"Cannot launch with an empty profile"
|
||||
);
|
||||
}
|
||||
else {
|
||||
_shouldLaunch = true;
|
||||
close();
|
||||
}
|
||||
}
|
||||
const std::string selection = _profileBox->currentText().toStdString();
|
||||
const int selectedIndex = _profileBox->currentIndex();
|
||||
const bool isUserProfile = selectedIndex < _userAssetCount;
|
||||
openProfileEditor(selection, isUserProfile);
|
||||
}
|
||||
);
|
||||
startButton->setObjectName("large");
|
||||
startButton->setGeometry(geometry::StartButton);
|
||||
startButton->setCursor(Qt::PointingHandCursor);
|
||||
editProfileButton->setObjectName("small");
|
||||
editProfileButton->setGeometry(geometry::EditProfileButton);
|
||||
editProfileButton->setCursor(Qt::PointingHandCursor);
|
||||
editProfileButton->setAutoDefault(true);
|
||||
editProfileButton->setAccessibleName("Edit profile");
|
||||
|
||||
QPushButton* newProfileButton = new QPushButton("New", centralWidget);
|
||||
connect(
|
||||
@@ -325,31 +320,17 @@ QWidget* LauncherWindow::createCentralWidget() {
|
||||
newProfileButton->setObjectName("small");
|
||||
newProfileButton->setGeometry(geometry::NewProfileButton);
|
||||
newProfileButton->setCursor(Qt::PointingHandCursor);
|
||||
newProfileButton->setAutoDefault(true);
|
||||
newProfileButton->setAccessibleName("New profile");
|
||||
|
||||
QPushButton* editProfileButton = new QPushButton("Edit", centralWidget);
|
||||
connect(
|
||||
editProfileButton, &QPushButton::released,
|
||||
[this]() {
|
||||
const std::string selection = _profileBox->currentText().toStdString();
|
||||
const int selectedIndex = _profileBox->currentIndex();
|
||||
const bool isUserProfile = selectedIndex < _userAssetCount;
|
||||
openProfileEditor(selection, isUserProfile);
|
||||
}
|
||||
);
|
||||
editProfileButton->setObjectName("small");
|
||||
editProfileButton->setGeometry(geometry::EditProfileButton);
|
||||
editProfileButton->setCursor(Qt::PointingHandCursor);
|
||||
QLabel* optionsLabel = new QLabel("Window Options", centralWidget);
|
||||
optionsLabel->setGeometry(geometry::OptionsLabel);
|
||||
optionsLabel->setObjectName("label_options");
|
||||
|
||||
QPushButton* newWindowButton = new QPushButton("New", centralWidget);
|
||||
connect(
|
||||
newWindowButton, &QPushButton::released,
|
||||
[this]() {
|
||||
openWindowEditor("", true);
|
||||
}
|
||||
);
|
||||
newWindowButton->setObjectName("small");
|
||||
newWindowButton->setGeometry(geometry::NewWindowButton);
|
||||
newWindowButton->setCursor(Qt::PointingHandCursor);
|
||||
_windowConfigBox = new QComboBox(centralWidget);
|
||||
_windowConfigBox->setObjectName("config");
|
||||
_windowConfigBox->setGeometry(geometry::WindowConfigBox);
|
||||
_windowConfigBox->setAccessibleName("Select window configuration");
|
||||
|
||||
_editWindowButton = new QPushButton("Edit", centralWidget);
|
||||
connect(
|
||||
@@ -368,7 +349,44 @@ QWidget* LauncherWindow::createCentralWidget() {
|
||||
_editWindowButton->setObjectName("small");
|
||||
_editWindowButton->setGeometry(geometry::EditWindowButton);
|
||||
_editWindowButton->setCursor(Qt::PointingHandCursor);
|
||||
_editWindowButton->setAutoDefault(true);
|
||||
_editWindowButton->setAccessibleName("Edit window configuration");
|
||||
|
||||
QPushButton* newWindowButton = new QPushButton("New", centralWidget);
|
||||
connect(
|
||||
newWindowButton, &QPushButton::released,
|
||||
[this]() {
|
||||
openWindowEditor("", true);
|
||||
}
|
||||
);
|
||||
newWindowButton->setObjectName("small");
|
||||
newWindowButton->setGeometry(geometry::NewWindowButton);
|
||||
newWindowButton->setCursor(Qt::PointingHandCursor);
|
||||
newWindowButton->setAutoDefault(true);
|
||||
newWindowButton->setAccessibleName("New window configuration");
|
||||
|
||||
QPushButton* startButton = new QPushButton("START", centralWidget);
|
||||
connect(
|
||||
startButton, &QPushButton::released,
|
||||
[this]() {
|
||||
if (_profileBox->currentText().isEmpty()) {
|
||||
QMessageBox::critical(
|
||||
this,
|
||||
"Empty Profile",
|
||||
"Cannot launch with an empty profile"
|
||||
);
|
||||
}
|
||||
else {
|
||||
_shouldLaunch = true;
|
||||
close();
|
||||
}
|
||||
}
|
||||
);
|
||||
startButton->setObjectName("start");
|
||||
startButton->setGeometry(geometry::StartButton);
|
||||
startButton->setCursor(Qt::PointingHandCursor);
|
||||
startButton->setAutoDefault(true);
|
||||
startButton->setAccessibleName("Start OpenSpace");
|
||||
|
||||
QLabel* versionLabel = new QLabel(centralWidget);
|
||||
versionLabel->setVisible(true);
|
||||
@@ -379,9 +397,6 @@ QWidget* LauncherWindow::createCentralWidget() {
|
||||
versionLabel->setGeometry(geometry::VersionString);
|
||||
|
||||
QPushButton* settingsButton = new QPushButton(centralWidget);
|
||||
settingsButton->setObjectName("settings");
|
||||
settingsButton->setGeometry(geometry::SettingsButton);
|
||||
settingsButton->setIconSize(QSize(SettingsIconSize, SettingsIconSize));
|
||||
connect(
|
||||
settingsButton,
|
||||
&QPushButton::released,
|
||||
@@ -410,6 +425,11 @@ QWidget* LauncherWindow::createCentralWidget() {
|
||||
dialog.exec();
|
||||
}
|
||||
);
|
||||
settingsButton->setObjectName("settings");
|
||||
settingsButton->setGeometry(geometry::SettingsButton);
|
||||
settingsButton->setIconSize(QSize(SettingsIconSize, SettingsIconSize));
|
||||
settingsButton->setAutoDefault(true);
|
||||
settingsButton->setAccessibleName("Settings");
|
||||
|
||||
return centralWidget;
|
||||
}
|
||||
@@ -454,27 +474,33 @@ void LauncherWindow::setBackgroundImage(const std::filesystem::path& syncPath) {
|
||||
// We know there has to be at least one folder, so it's fine to just pick the first
|
||||
while (!files.empty()) {
|
||||
const std::filesystem::path& p = files.front();
|
||||
if (p.extension() == ".png") {
|
||||
// If the top path starts with the png extension, we have found our candidate
|
||||
break;
|
||||
if (p.extension() != ".png" || p.filename() == "overlay.png") {
|
||||
files.erase(files.begin());
|
||||
}
|
||||
else {
|
||||
// There shouldn't be any non-png images in here, but you never know. So we
|
||||
// just remove non-image files here
|
||||
files.erase(files.begin());
|
||||
// If the top path starts with the png extension, we have found our candidate
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// There better be at least one file left, but just in in case
|
||||
if (!files.empty()) {
|
||||
// Take the selected image and overpaint the overlay increasing the contrast
|
||||
std::string image = files.front().string();
|
||||
_backgroundImage->setPixmap(QPixmap(QString::fromStdString(image)));
|
||||
QPixmap pixmap = QPixmap(QString::fromStdString(image));
|
||||
QPainter painter = QPainter(&pixmap);
|
||||
painter.setOpacity(0.7);
|
||||
QPixmap overlay = QPixmap(QString::fromStdString(
|
||||
std::format("{}/overlay.png", latest.path.path())
|
||||
));
|
||||
painter.drawPixmap(pixmap.rect(), overlay);
|
||||
_backgroundImage->setPixmap(pixmap);
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherWindow::populateProfilesList(const std::string& preset) {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
|
||||
_profileBox->clear();
|
||||
_userAssetCount = 0;
|
||||
|
||||
@@ -745,7 +771,7 @@ void LauncherWindow::onNewWindowConfigSelection(int newIndex) {
|
||||
versionMin.versionString()
|
||||
)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::runtime_error&) {
|
||||
// Ignore an exception here because clicking the edit button will
|
||||
@@ -781,6 +807,29 @@ void LauncherWindow::openProfileEditor(const std::string& profile, bool isUserPr
|
||||
savePath,
|
||||
this
|
||||
);
|
||||
|
||||
// Check whether there are unsaved changes from the profile editor
|
||||
connect(
|
||||
&editor,
|
||||
&ProfileEdit::raiseExitWindow,
|
||||
[this, &editor, &savePath, &p, &profile]() {
|
||||
const std::string origPath = std::format("{}{}.profile", savePath, profile);
|
||||
// If this is a new profile we want to prompt the user
|
||||
if (!std::filesystem::exists(origPath)) {
|
||||
editor.promptUserOfUnsavedChanges();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the profile is the same as current existing file
|
||||
if (*p != Profile(origPath)) {
|
||||
editor.promptUserOfUnsavedChanges();
|
||||
}
|
||||
else {
|
||||
editor.closeWithoutSaving();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
editor.exec();
|
||||
if (editor.wasSaved()) {
|
||||
if (editor.specifiedFilename() != profile) {
|
||||
@@ -932,3 +981,12 @@ bool LauncherWindow::isUserConfigSelected() const {
|
||||
const int selectedIndex = _windowConfigBox->currentIndex();
|
||||
return (selectedIndex <= _userConfigCount);
|
||||
}
|
||||
|
||||
void LauncherWindow::keyPressEvent(QKeyEvent* evt) {
|
||||
if (evt->key() == Qt::Key_Escape) {
|
||||
_shouldLaunch = false;
|
||||
close();
|
||||
return;
|
||||
}
|
||||
QMainWindow::keyPressEvent(evt);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QErrorMessage>
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
@@ -103,7 +104,7 @@ void ActionDialog::createWidgets() {
|
||||
// *----------------------*---------------*-----------------*
|
||||
|
||||
QGridLayout* layout = new QGridLayout(this);
|
||||
|
||||
|
||||
createActionWidgets(layout);
|
||||
clearActionFields();
|
||||
|
||||
@@ -161,25 +162,17 @@ void ActionDialog::createActionWidgets(QGridLayout* layout) {
|
||||
[this]() {
|
||||
// Check if the identifier is legal
|
||||
const std::string id = _actionWidgets.identifier->text().toStdString();
|
||||
const bool isLegal = id.find_first_of("\t\n. ") == std::string::npos;
|
||||
if (isLegal) {
|
||||
_actionWidgets.infoText->clear();
|
||||
_actionWidgets.infoText->setHidden(true);
|
||||
}
|
||||
else {
|
||||
_actionWidgets.infoText->setText(
|
||||
"Identifier must not contain whitespace or ."
|
||||
const bool isLegal = id.find_first_of("\t\n ") == std::string::npos;
|
||||
if (!isLegal) {
|
||||
_actionWidgets.infoText->showMessage(
|
||||
"Identifier must not contain whitespace"
|
||||
);
|
||||
_actionWidgets.infoText->setHidden(false);
|
||||
}
|
||||
}
|
||||
);
|
||||
layout->addWidget(_actionWidgets.identifier, 1, 2);
|
||||
|
||||
_actionWidgets.infoText = new QLabel;
|
||||
_actionWidgets.infoText->setHidden(true);
|
||||
_actionWidgets.infoText->setObjectName("error-message");
|
||||
layout->addWidget(_actionWidgets.infoText, 1, 3);
|
||||
_actionWidgets.infoText = new QErrorMessage(this);
|
||||
|
||||
layout->addWidget(new QLabel("Name"), 2, 1);
|
||||
_actionWidgets.name = new QLineEdit;
|
||||
@@ -243,6 +236,7 @@ void ActionDialog::createActionWidgets(QGridLayout* layout) {
|
||||
"`args` variable when this script executes. If no arguments are passed, this "
|
||||
"variable does not exist"
|
||||
);
|
||||
_actionWidgets.script->setTabChangesFocus(true);
|
||||
_actionWidgets.script->setEnabled(false);
|
||||
layout->addWidget(_actionWidgets.script, 6, 2, 1, 2);
|
||||
|
||||
@@ -612,7 +606,6 @@ void ActionDialog::actionSaved() {
|
||||
}
|
||||
action->identifier = newIdentifier;
|
||||
}
|
||||
|
||||
|
||||
action->name = _actionWidgets.name->text().toStdString();
|
||||
std::string guiPath = _actionWidgets.guiPath->text().toStdString();
|
||||
@@ -643,8 +636,6 @@ void ActionDialog::clearActionFields() const {
|
||||
_actionWidgets.list->setCurrentRow(-1);
|
||||
_actionWidgets.identifier->clear();
|
||||
_actionWidgets.identifier->setEnabled(false);
|
||||
_actionWidgets.infoText->clear();
|
||||
_actionWidgets.infoText->setHidden(true);
|
||||
_actionWidgets.name->clear();
|
||||
_actionWidgets.name->setEnabled(false);
|
||||
_actionWidgets.guiPath->clear();
|
||||
@@ -701,7 +692,7 @@ void ActionDialog::keybindingAdd() {
|
||||
void ActionDialog::keybindingRemove() {
|
||||
const Profile::Keybinding* keybinding = selectedKeybinding();
|
||||
ghoul_assert(keybinding, "A keybinding must be selected at this point");
|
||||
|
||||
|
||||
for (size_t i = 0; i < _keybindingsData.size(); i++) {
|
||||
if (_keybindingsData[i].key == keybinding->key &&
|
||||
_keybindingsData[i].action == keybinding->action)
|
||||
|
||||
@@ -64,6 +64,7 @@ void AdditionalScriptsDialog::createWidgets() {
|
||||
|
||||
_textScripts = new QTextEdit;
|
||||
_textScripts->setAcceptRichText(false);
|
||||
_textScripts->setTabChangesFocus(true);
|
||||
layout->addWidget(_textScripts, 1);
|
||||
|
||||
_chooseScriptsButton = new QPushButton("Choose Scripts");
|
||||
|
||||
@@ -72,40 +72,10 @@ void AssetEdit::createWidgets() {
|
||||
|
||||
_layout->addWidget(generateButton);
|
||||
}
|
||||
//{
|
||||
// QBoxLayout* container = new QHBoxLayout(this);
|
||||
// QLabel* assetLabel = new QLabel("Asset Name:");
|
||||
// assetLabel->setObjectName("profile");
|
||||
// container->addWidget(assetLabel);
|
||||
|
||||
// _nameEdit = new QLineEdit();
|
||||
// container->addWidget(_nameEdit);
|
||||
|
||||
// _layout->addLayout(container);
|
||||
//}
|
||||
//_layout->addWidget(new Line);
|
||||
//{
|
||||
// QBoxLayout* container = new QHBoxLayout(this);
|
||||
// _components = new QComboBox(this);
|
||||
// _components->addItems(_supportedComponents);
|
||||
// _components->setCurrentIndex(0);
|
||||
// container->addWidget(_components);
|
||||
|
||||
// QPushButton* addButton = new QPushButton("Add", this);
|
||||
// connect(addButton, &QPushButton::clicked, this, &AssetEdit::openComponent);
|
||||
// addButton->setCursor(Qt::PointingHandCursor);
|
||||
// container->addWidget(addButton);
|
||||
|
||||
// _layout->addLayout(container);
|
||||
//}
|
||||
_layout->addWidget(new Line);
|
||||
{
|
||||
QBoxLayout* footer = new QHBoxLayout;
|
||||
_errorMsg = new QLabel;
|
||||
_errorMsg->setObjectName("error-message");
|
||||
_errorMsg->setWordWrap(true);
|
||||
footer->addWidget(_errorMsg);
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox;
|
||||
buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &AssetEdit::approved);
|
||||
@@ -115,93 +85,14 @@ void AssetEdit::createWidgets() {
|
||||
}
|
||||
}
|
||||
|
||||
//void AssetEdit::openComponent() {
|
||||
// switch (_components->currentIndex()) {
|
||||
// case 0:
|
||||
// _errorMsg->setText("Choose a component to add to the asset");
|
||||
// break;
|
||||
// case 1: {
|
||||
// QBoxLayout* horizonsLayout = new QVBoxLayout(this);
|
||||
// {
|
||||
// QLabel* label = new QLabel("Horizons Translation:", this);
|
||||
// label->setObjectName("heading");
|
||||
// horizonsLayout->addWidget(label);
|
||||
// }
|
||||
// {
|
||||
// QBoxLayout* container = new QHBoxLayout(this);
|
||||
// QLabel* fileLabel = new QLabel("File path:", this);
|
||||
// container->addWidget(fileLabel);
|
||||
//
|
||||
// _horizonsFileEdit = new QLineEdit(this);
|
||||
// container->addWidget(_horizonsFileEdit);
|
||||
//
|
||||
// QPushButton* fileButton = new QPushButton("Browse", this);
|
||||
// connect(
|
||||
// fileButton,
|
||||
// &QPushButton::released,
|
||||
// this,
|
||||
// &AssetEdit::openHorizonsFile
|
||||
// );
|
||||
// fileButton->setCursor(Qt::PointingHandCursor);
|
||||
// container->addWidget(fileButton);
|
||||
//
|
||||
// QPushButton* generateButton = new QPushButton("Generate", this);
|
||||
// connect(
|
||||
// generateButton,
|
||||
// &QPushButton::released,
|
||||
// this,
|
||||
// &AssetEdit::openHorizons
|
||||
// );
|
||||
//
|
||||
// // In order to generate a Horizons File the Space module is required
|
||||
// #ifndef OPENSPACE_MODULE_SPACE_ENABLED
|
||||
// generateButton->setEnabled(false);
|
||||
// generateButton->setToolTip(
|
||||
// "Connot generate Horizons file without the space module enabled"
|
||||
// );
|
||||
// #else
|
||||
// generateButton->setCursor(Qt::PointingHandCursor);
|
||||
// #endif // OPENSPACE_MODULE_SPACE_ENABLED
|
||||
//
|
||||
// container->addWidget(generateButton);
|
||||
// horizonsLayout->addLayout(container);
|
||||
// }
|
||||
// horizonsLayout->addWidget(new Line);
|
||||
// _layout->insertLayout(_layout->count() - 3, horizonsLayout);
|
||||
// break;
|
||||
// }
|
||||
// default:
|
||||
// _errorMsg->setText("Unkown component");
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void AssetEdit::openHorizonsFile() {
|
||||
// std::string filePath = QFileDialog::getOpenFileName(
|
||||
// this,
|
||||
// tr("Open Horizons file"),
|
||||
// "",
|
||||
// tr("Horiozons file (*.dat)")
|
||||
// ).toStdString();
|
||||
// _horizonsFile = std::filesystem::absolute(filePath);
|
||||
// _horizonsFileEdit->setText(QString(_horizonsFile.string().c_str()));
|
||||
//}
|
||||
|
||||
void AssetEdit::openHorizons() {
|
||||
_errorMsg->clear();
|
||||
#ifdef OPENSPACE_MODULE_SPACE_ENABLED
|
||||
HorizonsDialog* horizonsDialog = new HorizonsDialog(this);
|
||||
horizonsDialog->exec();
|
||||
//_horizonsFile = horizonsDialog->file();
|
||||
//_horizonsFileEdit->setText(QString(_horizonsFile.string().c_str()));
|
||||
#endif // OPENSPACE_MODULE_SPACE_ENABLED
|
||||
}
|
||||
|
||||
void AssetEdit::approved() {
|
||||
// std::string assetName = _nameEdit->text().toStdString();
|
||||
// if (assetName.empty()) {
|
||||
// _errorMsg->setText("Asset name must be specified");
|
||||
// return;
|
||||
// }
|
||||
accept();
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QPushButton>
|
||||
#include <QTabWidget>
|
||||
@@ -173,10 +174,9 @@ void CameraDialog::createWidgets() {
|
||||
{
|
||||
QBoxLayout* footerLayout = new QHBoxLayout;
|
||||
|
||||
_errorMsg = new QLabel;
|
||||
_errorMsg->setObjectName("error-message");
|
||||
_errorMsg->setWordWrap(true);
|
||||
footerLayout->addWidget(_errorMsg);
|
||||
_errorMsg = new QMessageBox(this);
|
||||
_errorMsg->setIcon(QMessageBox::Critical);
|
||||
_errorMsg->setText("Invalid input data");
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox;
|
||||
buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
@@ -352,6 +352,9 @@ QWidget* CameraDialog::createNavStateWidget() {
|
||||
this,
|
||||
"Select navigate state file"
|
||||
);
|
||||
if (file.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::ifstream f = std::ifstream(file.toStdString());
|
||||
const std::string contents = std::string(
|
||||
@@ -441,7 +444,7 @@ QWidget* CameraDialog::createGeoWidget() {
|
||||
|
||||
bool CameraDialog::areRequiredFormsFilledAndValid() {
|
||||
bool allFormsOk = true;
|
||||
_errorMsg->clear();
|
||||
_errorMsg->setInformativeText("");
|
||||
|
||||
if (_tabWidget->currentIndex() == CameraTypeNode) {
|
||||
if (_nodeState.anchor->text().isEmpty()) {
|
||||
@@ -525,16 +528,17 @@ bool CameraDialog::areRequiredFormsFilledAndValid() {
|
||||
}
|
||||
|
||||
void CameraDialog::addErrorMsg(const QString& errorDescription) {
|
||||
QString contents = _errorMsg->text();
|
||||
QString contents = _errorMsg->informativeText();
|
||||
if (!contents.isEmpty()) {
|
||||
contents += ", ";
|
||||
}
|
||||
contents += errorDescription;
|
||||
_errorMsg->setText(contents);
|
||||
_errorMsg->setInformativeText(contents);
|
||||
}
|
||||
|
||||
void CameraDialog::approved() {
|
||||
if (!areRequiredFormsFilledAndValid()) {
|
||||
_errorMsg->exec();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -597,7 +601,7 @@ void CameraDialog::approved() {
|
||||
}
|
||||
|
||||
void CameraDialog::tabSelect(int tabIndex) {
|
||||
_errorMsg->clear();
|
||||
_errorMsg->setInformativeText("");
|
||||
|
||||
if (tabIndex == CameraTypeNode) {
|
||||
_nodeState.anchor->setFocus(Qt::OtherFocusReason);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QListWidget>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <array>
|
||||
@@ -107,7 +108,7 @@ void DeltaTimesDialog::createWidgets() {
|
||||
_listWidget->setAutoScroll(true);
|
||||
_listWidget->setLayoutMode(QListView::SinglePass);
|
||||
layout->addWidget(_listWidget);
|
||||
|
||||
|
||||
{
|
||||
QBoxLayout* buttonLayout = new QHBoxLayout;
|
||||
_addButton = new QPushButton("Add Entry");
|
||||
@@ -128,14 +129,15 @@ void DeltaTimesDialog::createWidgets() {
|
||||
layout->addLayout(buttonLayout);
|
||||
}
|
||||
|
||||
_adjustLabel = new QLabel("Set Simulation Time Increment for key");
|
||||
_adjustLabel = new QLabel("Set Simulation Time Increment (in seconds) for key");
|
||||
layout->addWidget(_adjustLabel);
|
||||
|
||||
|
||||
{
|
||||
QBoxLayout* box = new QHBoxLayout;
|
||||
_seconds = new QLineEdit;
|
||||
_seconds->setValidator(new QDoubleValidator);
|
||||
connect(_seconds, &QLineEdit::textChanged, this, &DeltaTimesDialog::valueChanged);
|
||||
_seconds->setAccessibleName("Set simulation time increment in seconds for key");
|
||||
box->addWidget(_seconds);
|
||||
|
||||
_value = new QLabel;
|
||||
@@ -165,11 +167,6 @@ void DeltaTimesDialog::createWidgets() {
|
||||
layout->addWidget(new Line);
|
||||
{
|
||||
QBoxLayout* footer = new QHBoxLayout;
|
||||
_errorMsg = new QLabel;
|
||||
_errorMsg->setObjectName("error-message");
|
||||
_errorMsg->setWordWrap(true);
|
||||
footer->addWidget(_errorMsg);
|
||||
|
||||
_buttonBox = new QDialogButtonBox;
|
||||
_buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
connect(
|
||||
@@ -230,7 +227,7 @@ void DeltaTimesDialog::listItemSelected() {
|
||||
}
|
||||
|
||||
void DeltaTimesDialog::setLabelForKey(int index, bool editMode, std::string_view color) {
|
||||
std::string labelS = "Set Simulation Time Increment for key";
|
||||
std::string labelS = "Set Simulation Time Increment (in seconds) for key";
|
||||
if (index >= static_cast<int>(_deltaTimesData.size())) {
|
||||
index = static_cast<int>(_deltaTimesData.size()) - 1;
|
||||
}
|
||||
@@ -243,15 +240,9 @@ void DeltaTimesDialog::setLabelForKey(int index, bool editMode, std::string_view
|
||||
}
|
||||
|
||||
void DeltaTimesDialog::valueChanged(const QString& text) {
|
||||
if (text.isEmpty()) {
|
||||
_errorMsg->setText("");
|
||||
}
|
||||
else {
|
||||
const double value = text.toDouble();
|
||||
if (value != 0.0) {
|
||||
_value->setText(QString::fromStdString(timeDescription(value)));
|
||||
_errorMsg->setText("");
|
||||
}
|
||||
const double value = text.toDouble();
|
||||
if (value != 0.0) {
|
||||
_value->setText(QString::fromStdString(timeDescription(value)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,7 +273,11 @@ void DeltaTimesDialog::addDeltaTimeValue() {
|
||||
_listWidget->addItem(new QListWidgetItem(messageAddValue));
|
||||
}
|
||||
else {
|
||||
_errorMsg->setText("Exceeded maximum amount of simulation time increments");
|
||||
QMessageBox::critical(
|
||||
this,
|
||||
"Error",
|
||||
"Exceeded maximum amount of simulation time increments"
|
||||
);
|
||||
}
|
||||
_listWidget->setCurrentRow(_listWidget->count() - 1);
|
||||
_seconds->setFocus(Qt::OtherFocusReason);
|
||||
@@ -337,7 +332,6 @@ void DeltaTimesDialog::transitionEditMode(int index, bool state) {
|
||||
_discardButton->setEnabled(state);
|
||||
_adjustLabel->setEnabled(state);
|
||||
_seconds->setEnabled(state);
|
||||
_errorMsg->clear();
|
||||
|
||||
if (state) {
|
||||
_seconds->setFocus(Qt::OtherFocusReason);
|
||||
@@ -348,7 +342,6 @@ void DeltaTimesDialog::transitionEditMode(int index, bool state) {
|
||||
setLabelForKey(index, false, "light gray");
|
||||
_value->clear();
|
||||
}
|
||||
_errorMsg->clear();
|
||||
}
|
||||
|
||||
void DeltaTimesDialog::parseSelections() {
|
||||
|
||||
@@ -125,7 +125,7 @@ void HorizonsDialog::typeOnChange(int index) {
|
||||
_timeTypeCombo->insertItem(0, TimeVarying.data());
|
||||
}
|
||||
else {
|
||||
_errorMsg->setText("Invalid Horizons type");
|
||||
QMessageBox::critical(this, "Error", "Invalid Horizons type");
|
||||
styleLabel(_typeLabel, IsDirty::Yes);
|
||||
}
|
||||
}
|
||||
@@ -162,12 +162,11 @@ void HorizonsDialog::importTimeRange() {
|
||||
_validTimeRange = std::pair<std::string, std::string>();
|
||||
return;
|
||||
}
|
||||
|
||||
_errorMsg->setText("Could not import time range");
|
||||
const std::string msg = std::format(
|
||||
"Could not import time range '{}' to '{}'",
|
||||
_validTimeRange.first, _validTimeRange.second
|
||||
);
|
||||
QMessageBox::critical(this, "Error", QString::fromStdString(msg));
|
||||
appendLog(msg, LogLevel::Error);
|
||||
return;
|
||||
}
|
||||
@@ -296,6 +295,7 @@ void HorizonsDialog::createWidgets() {
|
||||
_startEdit = new QDateTimeEdit;
|
||||
_startEdit->setDisplayFormat("yyyy-MM-dd T hh:mm:ss");
|
||||
_startEdit->setDate(QDate::currentDate().addYears(-1));
|
||||
_startEdit->setAccessibleName("Set start time");
|
||||
_startEdit->setToolTip("Enter the start date and time for the data");
|
||||
layout->addWidget(_startEdit, 8, 2);
|
||||
}
|
||||
@@ -306,6 +306,7 @@ void HorizonsDialog::createWidgets() {
|
||||
_endEdit = new QDateTimeEdit(this);
|
||||
_endEdit->setDisplayFormat("yyyy-MM-dd T hh:mm:ss");
|
||||
_endEdit->setDate(QDate::currentDate());
|
||||
_endEdit->setAccessibleName("Set end time");
|
||||
_endEdit->setToolTip("Enter the end date and time for the data");
|
||||
layout->addWidget(_endEdit, 9, 2);
|
||||
}
|
||||
@@ -375,11 +376,6 @@ void HorizonsDialog::createWidgets() {
|
||||
}
|
||||
{
|
||||
QBoxLayout* footer = new QHBoxLayout;
|
||||
_errorMsg = new QLabel;
|
||||
_errorMsg->setObjectName("error-message");
|
||||
_errorMsg->setWordWrap(true);
|
||||
footer->addWidget(_errorMsg);
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox;
|
||||
buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &HorizonsDialog::approved);
|
||||
@@ -392,7 +388,8 @@ void HorizonsDialog::createWidgets() {
|
||||
bool HorizonsDialog::isValidInput() {
|
||||
// File
|
||||
if (_fileEdit->text().isEmpty()) {
|
||||
_errorMsg->setText("File path not selected");
|
||||
QMessageBox::critical(this, "Error", "File path not selected");
|
||||
_fileEdit->setFocus();
|
||||
styleLabel(_fileLabel, IsDirty::Yes);
|
||||
return false;
|
||||
}
|
||||
@@ -401,13 +398,15 @@ bool HorizonsDialog::isValidInput() {
|
||||
if (_targetEdit->text().isEmpty() && ((_chooseTargetCombo->count() > 0 &&
|
||||
_chooseTargetCombo->currentIndex() == 0) || _chooseTargetCombo->count() == 0))
|
||||
{
|
||||
_errorMsg->setText("Target not selected");
|
||||
QMessageBox::critical(this, "Error", "Target not selected");
|
||||
_targetEdit->setFocus();
|
||||
styleLabel(_targetLabel, IsDirty::Yes);
|
||||
return false;
|
||||
}
|
||||
if (_targetEdit->text().toStdString().find_first_of("¤<>§£´¨€") != std::string::npos)
|
||||
{
|
||||
_errorMsg->setText("Target includes illegal characters");
|
||||
QMessageBox::critical(this, "Error", "Target includes illegal characters");
|
||||
_targetEdit->setFocus();
|
||||
styleLabel(_targetLabel, IsDirty::Yes);
|
||||
return false;
|
||||
}
|
||||
@@ -416,13 +415,15 @@ bool HorizonsDialog::isValidInput() {
|
||||
if (_centerEdit->text().isEmpty() && ((_chooseObserverCombo->count() > 0 &&
|
||||
_chooseObserverCombo->currentIndex() == 0) || _chooseObserverCombo->count() == 0))
|
||||
{
|
||||
_errorMsg->setText("Observer not selected");
|
||||
QMessageBox::critical(this, "Error", "Observer not selected");
|
||||
_centerEdit->setFocus();
|
||||
styleLabel(_centerLabel, IsDirty::Yes);
|
||||
return false;
|
||||
}
|
||||
if (_centerEdit->text().toStdString().find_first_of("¤<>§£´¨€") != std::string::npos)
|
||||
{
|
||||
_errorMsg->setText("Observer includes illegal characters");
|
||||
QMessageBox::critical(this, "Error", "Observer includes illegal characters");
|
||||
_centerEdit->setFocus();
|
||||
styleLabel(_centerLabel, IsDirty::Yes);
|
||||
return false;
|
||||
}
|
||||
@@ -430,7 +431,8 @@ bool HorizonsDialog::isValidInput() {
|
||||
// Step size
|
||||
// Empty
|
||||
if (_stepEdit->text().isEmpty()) {
|
||||
_errorMsg->setText("Step size not selected");
|
||||
QMessageBox::critical(this, "Error", "Step size is not selected");
|
||||
_stepEdit->setFocus();
|
||||
styleLabel(_stepLabel, IsDirty::Yes);
|
||||
return false;
|
||||
}
|
||||
@@ -438,17 +440,26 @@ bool HorizonsDialog::isValidInput() {
|
||||
bool couldConvert = false;
|
||||
const int32_t step = _stepEdit->text().toInt(&couldConvert);
|
||||
if (!couldConvert) {
|
||||
_errorMsg->setText(QString::fromStdString(std::format(
|
||||
"Step size needs to be a number in range 1 to {}",
|
||||
std::numeric_limits<int32_t>::max()
|
||||
)));
|
||||
QMessageBox::critical(
|
||||
this, "Error",
|
||||
QString::fromStdString(std::format(
|
||||
"Step size needs to be a number in range 1 to {}",
|
||||
std::numeric_limits<int32_t>::max()
|
||||
))
|
||||
);
|
||||
_stepEdit->setFocus();
|
||||
styleLabel(_stepLabel, IsDirty::Yes);
|
||||
return false;
|
||||
}
|
||||
// In the case of arcseconds range is different
|
||||
if (_timeTypeCombo->currentText().toStdString() == TimeVarying) {
|
||||
if (step < 60 || step > 3600) {
|
||||
_errorMsg->setText("Angular step size needs to be in range 60 to 3600");
|
||||
QMessageBox::critical(
|
||||
this,
|
||||
"Error",
|
||||
"Angular step size needs to be in range 60 to 3600"
|
||||
);
|
||||
_stepEdit->setFocus();
|
||||
styleLabel(_stepLabel, IsDirty::Yes);
|
||||
return false;
|
||||
}
|
||||
@@ -458,10 +469,11 @@ bool HorizonsDialog::isValidInput() {
|
||||
// website as a uint32_t. If step size over 32 bit int is sent, this error message is
|
||||
// received: Cannot read numeric value -- re-enter
|
||||
if (step < 1) {
|
||||
_errorMsg->setText(QString::fromStdString(std::format(
|
||||
QMessageBox::critical(this, "Error", QString::fromStdString(std::format(
|
||||
"Step size is outside valid range 1 to '{}'",
|
||||
std::numeric_limits<int32_t>::max()
|
||||
)));
|
||||
_stepEdit->setFocus();
|
||||
styleLabel(_stepLabel, IsDirty::Yes);
|
||||
return false;
|
||||
}
|
||||
@@ -658,14 +670,14 @@ std::pair<std::string, std::string> HorizonsDialog::readTimeRange() {
|
||||
|
||||
if (!start.isValid() || !end.isValid()) {
|
||||
if (timeRange.first.empty() || timeRange.second.empty()) {
|
||||
_errorMsg->setText("Could not find time range");
|
||||
QMessageBox::critical(this, "Error", "Could not find time range");
|
||||
appendLog(
|
||||
"Could not find time range in Horizons file",
|
||||
LogLevel::Error
|
||||
);
|
||||
}
|
||||
else {
|
||||
_errorMsg->setText("Could not parse time range");
|
||||
QMessageBox::critical(this, "Error", "Could not parse time range");
|
||||
const std::string msg = std::format(
|
||||
"Could not read time range '{}' to '{}'",
|
||||
timeRange.first, timeRange.second
|
||||
@@ -693,10 +705,6 @@ bool HorizonsDialog::handleRequest() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reset
|
||||
_errorMsg->clear();
|
||||
|
||||
//
|
||||
// Clean all widgets
|
||||
styleLabel(_typeLabel, IsDirty::No);
|
||||
styleLabel(_fileLabel, IsDirty::No);
|
||||
@@ -719,7 +727,7 @@ bool HorizonsDialog::handleRequest() {
|
||||
|
||||
nlohmann::json answer = sendRequest(url);
|
||||
if (answer.empty()) {
|
||||
_errorMsg->setText("Connection error");
|
||||
QMessageBox::critical(this, "Errpr", "Connection error");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -762,7 +770,7 @@ std::string HorizonsDialog::constructUrl() {
|
||||
type = HorizonsType::Observer;
|
||||
}
|
||||
else {
|
||||
_errorMsg->setText("Invalid Horizons type");
|
||||
QMessageBox::critical(this, "Error", "Invalid Horizons type");
|
||||
styleLabel(_typeLabel, IsDirty::Yes);
|
||||
return "";
|
||||
}
|
||||
@@ -829,7 +837,7 @@ std::string HorizonsDialog::constructUrl() {
|
||||
unit = "";
|
||||
}
|
||||
else {
|
||||
_errorMsg->setText("Invalid time unit type");
|
||||
QMessageBox::critical(this, "Error", "Invalid time unit type");
|
||||
styleLabel(_stepLabel, IsDirty::Yes);
|
||||
return "";
|
||||
}
|
||||
@@ -894,11 +902,15 @@ openspace::HorizonsFile HorizonsDialog::handleAnswer(nlohmann::json& answer) {
|
||||
break;
|
||||
case QMessageBox::No:
|
||||
case QMessageBox::Cancel:
|
||||
_errorMsg->setText("File already exist, try another file path");
|
||||
QMessageBox::critical(
|
||||
this,
|
||||
"Error",
|
||||
"File already exist, try another file path"
|
||||
);
|
||||
styleLabel(_fileLabel, IsDirty::Yes);
|
||||
return openspace::HorizonsFile();
|
||||
default:
|
||||
_errorMsg->setText("Invalid answer");
|
||||
QMessageBox::critical(this, "Error", "Invalid answer");
|
||||
styleLabel(_fileLabel, IsDirty::Yes);
|
||||
return openspace::HorizonsFile();
|
||||
}
|
||||
@@ -927,7 +939,7 @@ bool HorizonsDialog::handleResult(openspace::HorizonsResultCode& result) {
|
||||
break;
|
||||
}
|
||||
case HorizonsResultCode::Empty: {
|
||||
_errorMsg->setText("The horizons file is empty");
|
||||
QMessageBox::critical(this, "Error", "The horizons file is empty");
|
||||
if (!_latestHorizonsError.empty()) {
|
||||
const std::string msg = std::format(
|
||||
"Latest Horizons error: {}", _latestHorizonsError
|
||||
@@ -1172,7 +1184,7 @@ bool HorizonsDialog::handleResult(openspace::HorizonsResultCode& result) {
|
||||
);
|
||||
appendLog(msg, LogLevel::Error);
|
||||
}
|
||||
_errorMsg->setText("An unknown error occured");
|
||||
QMessageBox::critical(this, "Error", "An unknown error occured");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -1182,7 +1194,7 @@ bool HorizonsDialog::handleResult(openspace::HorizonsResultCode& result) {
|
||||
);
|
||||
appendLog(msg, LogLevel::Error);
|
||||
}
|
||||
_errorMsg->setText("Invalid result type");
|
||||
QMessageBox::critical(this, "Error", "Invalid result type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ void MarkNodesDialog::createWidgets() {
|
||||
|
||||
_removeButton = new QPushButton("Remove");
|
||||
connect(_removeButton, &QPushButton::clicked, this, &MarkNodesDialog::listItemRemove);
|
||||
_removeButton->setAccessibleName("Remove node");
|
||||
layout->addWidget(_removeButton);
|
||||
|
||||
{
|
||||
@@ -78,6 +79,7 @@ void MarkNodesDialog::createWidgets() {
|
||||
|
||||
QPushButton* addButton = new QPushButton("Add new");
|
||||
connect(addButton, &QPushButton::clicked, this, &MarkNodesDialog::listItemAdded);
|
||||
addButton->setAccessibleName("Add new node");
|
||||
box->addWidget(addButton);
|
||||
layout->addLayout(box);
|
||||
}
|
||||
|
||||
@@ -68,28 +68,34 @@ void MetaDialog::createWidgets() {
|
||||
QBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->addWidget(new QLabel("Name"));
|
||||
_nameEdit = new QLineEdit;
|
||||
_nameEdit->setAccessibleName("Profile name");
|
||||
layout->addWidget(_nameEdit);
|
||||
|
||||
layout->addWidget(new QLabel("Version"));
|
||||
_versionEdit = new QLineEdit;
|
||||
_versionEdit->setAccessibleName("Profile version number");
|
||||
layout->addWidget(_versionEdit);
|
||||
|
||||
layout->addWidget(new QLabel("Description"));
|
||||
_descriptionEdit = new QTextEdit;
|
||||
_descriptionEdit->setAcceptRichText(false);
|
||||
_descriptionEdit->setTabChangesFocus(true);
|
||||
_descriptionEdit->setAccessibleName("Profile description");
|
||||
layout->addWidget(_descriptionEdit);
|
||||
|
||||
layout->addWidget(new QLabel("Author"));
|
||||
_authorEdit = new QLineEdit;
|
||||
_authorEdit->setAccessibleName("Profile author name");
|
||||
layout->addWidget(_authorEdit);
|
||||
|
||||
layout->addWidget(new QLabel("URL"));
|
||||
_urlEdit = new QLineEdit;
|
||||
_urlEdit->setAccessibleName("Profile url");
|
||||
layout->addWidget(_urlEdit);
|
||||
|
||||
layout->addWidget(new QLabel("License"));
|
||||
_licenseEdit = new QLineEdit;
|
||||
_licenseEdit->setAccessibleName("Profile license");
|
||||
layout->addWidget(_licenseEdit);
|
||||
|
||||
layout->addWidget(new Line);
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <QLabel>
|
||||
#include <QListWidget>
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
@@ -92,11 +93,12 @@ void ModulesDialog::createWidgets() {
|
||||
_list->addItem(new QListWidgetItem(createOneLineSummary(m)));
|
||||
}
|
||||
layout->addWidget(_list);
|
||||
|
||||
|
||||
{
|
||||
QBoxLayout* box = new QHBoxLayout;
|
||||
_buttonAdd = new QPushButton("Add new");
|
||||
connect(_buttonAdd, &QPushButton::clicked, this, &ModulesDialog::listItemAdded);
|
||||
_buttonAdd->setAccessibleName("Add new module");
|
||||
box->addWidget(_buttonAdd);
|
||||
|
||||
_buttonRemove = new QPushButton("Remove");
|
||||
@@ -104,6 +106,7 @@ void ModulesDialog::createWidgets() {
|
||||
_buttonRemove, &QPushButton::clicked,
|
||||
this, &ModulesDialog::listItemRemove
|
||||
);
|
||||
_buttonRemove->setAccessibleName("Remove module");
|
||||
box->addWidget(_buttonRemove);
|
||||
|
||||
box->addStretch();
|
||||
@@ -113,14 +116,14 @@ void ModulesDialog::createWidgets() {
|
||||
{
|
||||
_moduleLabel = new QLabel("Module");
|
||||
layout->addWidget(_moduleLabel);
|
||||
|
||||
|
||||
_moduleEdit = new QLineEdit;
|
||||
_moduleEdit->setToolTip("Name of OpenSpace module related to this profile");
|
||||
layout->addWidget(_moduleEdit);
|
||||
|
||||
_loadedLabel = new QLabel("Command if Module is Loaded");
|
||||
layout->addWidget(_loadedLabel);
|
||||
|
||||
|
||||
_loadedEdit = new QLineEdit;
|
||||
_loadedEdit->setToolTip(
|
||||
"Lua command(s) to execute if OpenSpace has been compiled with the module"
|
||||
@@ -129,7 +132,7 @@ void ModulesDialog::createWidgets() {
|
||||
|
||||
_notLoadedLabel = new QLabel("Command if Module is NOT Loaded");
|
||||
layout->addWidget(_notLoadedLabel);
|
||||
|
||||
|
||||
_notLoadedEdit = new QLineEdit;
|
||||
_notLoadedEdit->setToolTip(
|
||||
"Lua command(s) to execute if the module is not present in the OpenSpace "
|
||||
@@ -159,12 +162,6 @@ void ModulesDialog::createWidgets() {
|
||||
layout->addWidget(new Line);
|
||||
{
|
||||
QBoxLayout* footerLayout = new QHBoxLayout;
|
||||
|
||||
_errorMsg = new QLabel;
|
||||
_errorMsg->setObjectName("error-message");
|
||||
_errorMsg->setWordWrap(true);
|
||||
footerLayout->addWidget(_errorMsg);
|
||||
|
||||
_buttonBox = new QDialogButtonBox;
|
||||
_buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
QObject::connect(
|
||||
@@ -193,7 +190,7 @@ void ModulesDialog::listItemSelected() {
|
||||
else {
|
||||
_loadedEdit->clear();
|
||||
}
|
||||
|
||||
|
||||
if (m.notLoadedInstruction.has_value()) {
|
||||
_notLoadedEdit->setText(QString::fromStdString(*m.notLoadedInstruction));
|
||||
}
|
||||
@@ -227,7 +224,6 @@ void ModulesDialog::listItemAdded() {
|
||||
_list->addItem(new QListWidgetItem(" (Enter details below & click 'Save')"));
|
||||
//Scroll down to that blank line highlighted
|
||||
_list->setCurrentRow(_list->count() - 1);
|
||||
_errorMsg->clear();
|
||||
}
|
||||
|
||||
// Blank-out the 2 text fields, set combo box to index 0
|
||||
@@ -254,7 +250,7 @@ void ModulesDialog::listItemAdded() {
|
||||
|
||||
void ModulesDialog::listItemSave() {
|
||||
if (_moduleEdit->text().isEmpty()) {
|
||||
_errorMsg->setText("Missing module name");
|
||||
QMessageBox::critical(this, "Error", "Missing module name");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -311,7 +307,6 @@ void ModulesDialog::transitionToEditMode() {
|
||||
_loadedLabel->setText("<font color='black'>Command if Module is Loaded</font>");
|
||||
_notLoadedLabel->setText("<font color='black'>Command if Module is NOT Loaded</font>");
|
||||
editBoxDisabled(false);
|
||||
_errorMsg->setText("");
|
||||
}
|
||||
|
||||
void ModulesDialog::transitionFromEditMode() {
|
||||
@@ -326,7 +321,6 @@ void ModulesDialog::transitionFromEditMode() {
|
||||
_moduleLabel->setText("<font color='light gray'>Module</font>");
|
||||
_loadedLabel->setText("<font color='light gray'>Command if Module is Loaded</font>");
|
||||
_notLoadedLabel->setText("<font color='light gray'>Command if Module is NOT Loaded</font>");
|
||||
_errorMsg->setText("");
|
||||
}
|
||||
|
||||
void ModulesDialog::editBoxDisabled(bool disabled) {
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QTextEdit>
|
||||
#include <QVBoxLayout>
|
||||
@@ -65,7 +66,7 @@ namespace {
|
||||
std::string summarizeAssets(const std::vector<std::string>& assets) {
|
||||
std::string results;
|
||||
for (const std::string& a : assets) {
|
||||
results += a + '\n';
|
||||
results += std::format("{}<br>", a);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
@@ -81,7 +82,7 @@ namespace {
|
||||
);
|
||||
|
||||
std::string name = it != actions.end() ? it->name : "Unknown action";
|
||||
results += std::format("{} ({})\n", name, ghoul::to_string(k.key));
|
||||
results += std::format("{} ({})<br>", name, ghoul::to_string(k.key));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
@@ -89,13 +90,13 @@ namespace {
|
||||
std::string summarizeProperties(const std::vector<Profile::Property>& properties) {
|
||||
std::string results;
|
||||
for (openspace::Profile::Property p : properties) {
|
||||
results += std::format("{} = {}\n", p.name, p.value);
|
||||
results += std::format("{} = {}<br>", p.name, p.value);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ProfileEdit::ProfileEdit(Profile& profile, const std::string& profileName,
|
||||
ProfileEdit::ProfileEdit(Profile& profile, const std::string& profileName,
|
||||
std::filesystem::path assetBasePath,
|
||||
std::filesystem::path userAssetBasePath,
|
||||
std::filesystem::path builtInProfileBasePath,
|
||||
@@ -125,6 +126,7 @@ void ProfileEdit::createWidgets(const std::string& profileName) {
|
||||
container->addWidget(profileLabel);
|
||||
|
||||
_profileEdit = new QLineEdit(QString::fromStdString(profileName));
|
||||
_profileEdit->setPlaceholderText("required");
|
||||
container->addWidget(_profileEdit);
|
||||
|
||||
QPushButton* duplicateButton = new QPushButton("Duplicate Profile");
|
||||
@@ -146,17 +148,19 @@ void ProfileEdit::createWidgets(const std::string& profileName) {
|
||||
_propertiesLabel->setWordWrap(true);
|
||||
container->addWidget(_propertiesLabel, 0, 0);
|
||||
|
||||
_propertiesEdit = new QTextEdit;
|
||||
_propertiesEdit->setReadOnly(true);
|
||||
_propertiesEdit->setAccessibleName("Property value settings");
|
||||
container->addWidget(_propertiesEdit, 1, 0, 1, 3);
|
||||
|
||||
QPushButton* editProperties = new QPushButton("Edit");
|
||||
connect(
|
||||
editProperties, &QPushButton::clicked,
|
||||
this, &ProfileEdit::openProperties
|
||||
);
|
||||
editProperties->setAccessibleName("Edit properties");
|
||||
container->addWidget(editProperties, 0, 2);
|
||||
|
||||
_propertiesEdit = new QTextEdit;
|
||||
_propertiesEdit->setReadOnly(true);
|
||||
container->addWidget(_propertiesEdit, 1, 0, 1, 3);
|
||||
|
||||
leftLayout->addLayout(container);
|
||||
}
|
||||
leftLayout->addWidget(new Line);
|
||||
@@ -169,14 +173,16 @@ void ProfileEdit::createWidgets(const std::string& profileName) {
|
||||
_assetsLabel->setWordWrap(true);
|
||||
container->addWidget(_assetsLabel, 0, 0);
|
||||
|
||||
QPushButton* assetsProperties = new QPushButton("Edit");
|
||||
connect(assetsProperties, &QPushButton::clicked, this, &ProfileEdit::openAssets);
|
||||
container->addWidget(assetsProperties, 0, 2);
|
||||
|
||||
_assetsEdit = new QTextEdit;
|
||||
_assetsEdit->setReadOnly(true);
|
||||
_assetsEdit->setAccessibleName("Loaded assets");
|
||||
container->addWidget(_assetsEdit, 1, 0, 1, 3);
|
||||
|
||||
QPushButton* assetsProperties = new QPushButton("Edit");
|
||||
connect(assetsProperties, &QPushButton::clicked, this, &ProfileEdit::openAssets);
|
||||
assetsProperties->setAccessibleName("Edit assets");
|
||||
container->addWidget(assetsProperties, 0, 2);
|
||||
|
||||
leftLayout->addLayout(container);
|
||||
}
|
||||
leftLayout->addWidget(new Line);
|
||||
@@ -188,17 +194,19 @@ void ProfileEdit::createWidgets(const std::string& profileName) {
|
||||
_keybindingsLabel->setObjectName("heading");
|
||||
container->addWidget(_keybindingsLabel, 0, 0);
|
||||
|
||||
_keybindingsEdit = new QTextEdit;
|
||||
_keybindingsEdit->setReadOnly(true);
|
||||
_keybindingsEdit->setAccessibleName("Loaded action and keybindings");
|
||||
container->addWidget(_keybindingsEdit, 1, 0, 1, 3);
|
||||
|
||||
QPushButton* keybindingsProperties = new QPushButton("Edit");
|
||||
connect(
|
||||
keybindingsProperties, &QPushButton::clicked,
|
||||
this, &ProfileEdit::openKeybindings
|
||||
);
|
||||
keybindingsProperties->setAccessibleName("Edit actions and keybindings");
|
||||
container->addWidget(keybindingsProperties, 0, 2);
|
||||
|
||||
_keybindingsEdit = new QTextEdit;
|
||||
_keybindingsEdit->setReadOnly(true);
|
||||
container->addWidget(_keybindingsEdit, 1, 0, 1, 3);
|
||||
|
||||
leftLayout->addLayout(container);
|
||||
}
|
||||
topLayout->addLayout(leftLayout, 3);
|
||||
@@ -216,6 +224,7 @@ void ProfileEdit::createWidgets(const std::string& profileName) {
|
||||
QPushButton* metaEdit = new QPushButton("Edit");
|
||||
connect(metaEdit, &QPushButton::clicked, this, &ProfileEdit::openMeta);
|
||||
metaEdit->setLayoutDirection(Qt::RightToLeft);
|
||||
metaEdit->setAccessibleName("Edit metadata");
|
||||
container->addWidget(metaEdit);
|
||||
rightLayout->addLayout(container);
|
||||
}
|
||||
@@ -233,6 +242,7 @@ void ProfileEdit::createWidgets(const std::string& profileName) {
|
||||
this, &ProfileEdit::openMarkNodes
|
||||
);
|
||||
interestingNodesEdit->setLayoutDirection(Qt::RightToLeft);
|
||||
interestingNodesEdit->setAccessibleName("Edit interesting nodes");
|
||||
container->addWidget(interestingNodesEdit);
|
||||
rightLayout->addLayout(container);
|
||||
}
|
||||
@@ -250,6 +260,7 @@ void ProfileEdit::createWidgets(const std::string& profileName) {
|
||||
this, &ProfileEdit::openDeltaTimes
|
||||
);
|
||||
deltaTimesEdit->setLayoutDirection(Qt::RightToLeft);
|
||||
deltaTimesEdit->setAccessibleName("Edit simulation time increments");
|
||||
container->addWidget(deltaTimesEdit);
|
||||
rightLayout->addLayout(container);
|
||||
}
|
||||
@@ -264,6 +275,7 @@ void ProfileEdit::createWidgets(const std::string& profileName) {
|
||||
QPushButton* cameraEdit = new QPushButton("Edit");
|
||||
connect(cameraEdit, &QPushButton::clicked, this, &ProfileEdit::openCamera);
|
||||
cameraEdit->setLayoutDirection(Qt::RightToLeft);
|
||||
cameraEdit->setAccessibleName("Edit camera");
|
||||
container->addWidget(cameraEdit);
|
||||
rightLayout->addLayout(container);
|
||||
}
|
||||
@@ -278,6 +290,7 @@ void ProfileEdit::createWidgets(const std::string& profileName) {
|
||||
QPushButton* timeEdit = new QPushButton("Edit");
|
||||
connect(timeEdit, &QPushButton::clicked, this, &ProfileEdit::openTime);
|
||||
timeEdit->setLayoutDirection(Qt::RightToLeft);
|
||||
timeEdit->setAccessibleName("Edit time");
|
||||
container->addWidget(timeEdit);
|
||||
rightLayout->addLayout(container);
|
||||
}
|
||||
@@ -292,6 +305,7 @@ void ProfileEdit::createWidgets(const std::string& profileName) {
|
||||
QPushButton* modulesEdit = new QPushButton("Edit");
|
||||
connect(modulesEdit, &QPushButton::clicked, this, &ProfileEdit::openModules);
|
||||
modulesEdit->setLayoutDirection(Qt::RightToLeft);
|
||||
modulesEdit->setAccessibleName("Edit modules");
|
||||
container->addWidget(modulesEdit);
|
||||
rightLayout->addLayout(container);
|
||||
}
|
||||
@@ -309,6 +323,7 @@ void ProfileEdit::createWidgets(const std::string& profileName) {
|
||||
this, &ProfileEdit::openAddedScripts
|
||||
);
|
||||
additionalScriptsEdit->setLayoutDirection(Qt::RightToLeft);
|
||||
additionalScriptsEdit->setAccessibleName("Edit additional scripts");
|
||||
container->addWidget(additionalScriptsEdit);
|
||||
rightLayout->addLayout(container);
|
||||
}
|
||||
@@ -319,11 +334,6 @@ void ProfileEdit::createWidgets(const std::string& profileName) {
|
||||
|
||||
{
|
||||
QBoxLayout* footer = new QHBoxLayout;
|
||||
_errorMsg = new QLabel;
|
||||
_errorMsg->setObjectName("error-message");
|
||||
_errorMsg->setWordWrap(true);
|
||||
footer->addWidget(_errorMsg);
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox;
|
||||
buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &ProfileEdit::approved);
|
||||
@@ -360,7 +370,6 @@ void ProfileEdit::initSummaryTextForEachCategory() {
|
||||
}
|
||||
|
||||
void ProfileEdit::duplicateProfile() {
|
||||
_errorMsg->clear();
|
||||
std::string profile = _profileEdit->text().toStdString();
|
||||
if (profile.empty()) {
|
||||
return;
|
||||
@@ -405,18 +414,15 @@ void ProfileEdit::duplicateProfile() {
|
||||
}
|
||||
|
||||
void ProfileEdit::openMeta() {
|
||||
_errorMsg->clear();
|
||||
MetaDialog(this, &_profile.meta).exec();
|
||||
}
|
||||
|
||||
void ProfileEdit::openModules() {
|
||||
_errorMsg->clear();
|
||||
ModulesDialog(this, &_profile.modules).exec();
|
||||
_modulesLabel->setText(labelText(_profile.modules.size(), "Modules"));
|
||||
}
|
||||
|
||||
void ProfileEdit::openProperties() {
|
||||
_errorMsg->clear();
|
||||
PropertiesDialog(this, &_profile.properties).exec();
|
||||
_propertiesLabel->setText(labelText(_profile.properties.size(), "Properties"));
|
||||
_propertiesEdit->setText(
|
||||
@@ -425,7 +431,6 @@ void ProfileEdit::openProperties() {
|
||||
}
|
||||
|
||||
void ProfileEdit::openKeybindings() {
|
||||
_errorMsg->clear();
|
||||
ActionDialog(this, &_profile.actions, &_profile.keybindings).exec();
|
||||
_keybindingsLabel->setText(labelText(_profile.keybindings.size(), "Keybindings"));
|
||||
_keybindingsEdit->setText(QString::fromStdString(
|
||||
@@ -434,19 +439,16 @@ void ProfileEdit::openKeybindings() {
|
||||
}
|
||||
|
||||
void ProfileEdit::openAssets() {
|
||||
_errorMsg->clear();
|
||||
AssetsDialog(this, &_profile, _assetBasePath, _userAssetBasePath).exec();
|
||||
_assetsLabel->setText(labelText(_profile.assets.size(), "Assets"));
|
||||
_assetsEdit->setText(QString::fromStdString(summarizeAssets(_profile.assets)));
|
||||
}
|
||||
|
||||
void ProfileEdit::openTime() {
|
||||
_errorMsg->clear();
|
||||
TimeDialog(this, &_profile.time).exec();
|
||||
}
|
||||
|
||||
void ProfileEdit::openDeltaTimes() {
|
||||
_errorMsg->clear();
|
||||
DeltaTimesDialog(this, &_profile.deltaTimes).exec();
|
||||
_deltaTimesLabel->setText(
|
||||
labelText(_profile.deltaTimes.size(), "Simulation Time Increments")
|
||||
@@ -454,17 +456,14 @@ void ProfileEdit::openDeltaTimes() {
|
||||
}
|
||||
|
||||
void ProfileEdit::openAddedScripts() {
|
||||
_errorMsg->clear();
|
||||
AdditionalScriptsDialog(this, &_profile.additionalScripts).exec();
|
||||
}
|
||||
|
||||
void ProfileEdit::openCamera() {
|
||||
_errorMsg->clear();
|
||||
CameraDialog(this, &_profile.camera).exec();
|
||||
}
|
||||
|
||||
void ProfileEdit::openMarkNodes() {
|
||||
_errorMsg->clear();
|
||||
MarkNodesDialog(this, &_profile.markNodes).exec();
|
||||
_interestingNodesLabel->setText(
|
||||
labelText(_profile.markNodes.size(), "Mark Interesting Nodes")
|
||||
@@ -479,15 +478,11 @@ std::string ProfileEdit::specifiedFilename() const {
|
||||
return _profileEdit->text().toStdString();
|
||||
}
|
||||
|
||||
void ProfileEdit::cancel() {
|
||||
_saveSelected = false;
|
||||
reject();
|
||||
}
|
||||
|
||||
void ProfileEdit::approved() {
|
||||
std::string profileName = _profileEdit->text().toStdString();
|
||||
if (profileName.empty()) {
|
||||
_errorMsg->setText("Profile name must be specified");
|
||||
QMessageBox::critical(this, "No profile name", "Profile name must be specified");
|
||||
_profileEdit->setFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -497,13 +492,15 @@ void ProfileEdit::approved() {
|
||||
if (std::filesystem::exists(p)) {
|
||||
// The filename exists in the OpenSpace-provided folder, so we don't want to allow
|
||||
// a user to overwrite it
|
||||
_errorMsg->setText(
|
||||
"This is a read-only profile. Click 'Duplicate' or rename & save"
|
||||
QMessageBox::critical(
|
||||
this,
|
||||
"Reserved profile name",
|
||||
"This is a read-only profile. Click 'Duplicate' or rename profile and save"
|
||||
);
|
||||
_profileEdit->setFocus();
|
||||
}
|
||||
else {
|
||||
_saveSelected = true;
|
||||
_errorMsg->setText("");
|
||||
accept();
|
||||
}
|
||||
}
|
||||
@@ -515,3 +512,36 @@ void ProfileEdit::keyPressEvent(QKeyEvent* evt) {
|
||||
QDialog::keyPressEvent(evt);
|
||||
}
|
||||
|
||||
|
||||
void ProfileEdit::reject() {
|
||||
// We hijack the reject (i.e., exit window) and emit the signal. The actual shutdown
|
||||
// of the window comes at a later stage.
|
||||
emit raiseExitWindow();
|
||||
}
|
||||
|
||||
void ProfileEdit::closeWithoutSaving() {
|
||||
_saveSelected = false;
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
void ProfileEdit::promptUserOfUnsavedChanges() {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText("There are unsaved changes");
|
||||
msgBox.setInformativeText("Do you want to save your changes");
|
||||
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
||||
msgBox.setDefaultButton(QMessageBox::Save);
|
||||
int ret = msgBox.exec();
|
||||
|
||||
switch (ret) {
|
||||
case QMessageBox::Save:
|
||||
approved();
|
||||
break;
|
||||
case QMessageBox::Discard:
|
||||
closeWithoutSaving();
|
||||
break;
|
||||
case QMessageBox::Cancel:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QListWidget>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QTextStream>
|
||||
#include <QVBoxLayout>
|
||||
@@ -157,13 +158,11 @@ void PropertiesDialog::createWidgets() {
|
||||
}
|
||||
layout->addWidget(new Line);
|
||||
{
|
||||
_errorMsg = new QMessageBox(this);
|
||||
_errorMsg->setIcon(QMessageBox::Critical);
|
||||
_errorMsg->setText("Invalid input data");
|
||||
|
||||
QBoxLayout* footerLayout = new QHBoxLayout;
|
||||
|
||||
_errorMsg = new QLabel;
|
||||
_errorMsg->setObjectName("error-message");
|
||||
_errorMsg->setWordWrap(true);
|
||||
footerLayout->addWidget(_errorMsg);
|
||||
|
||||
_buttonBox = new QDialogButtonBox;
|
||||
_buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
|
||||
@@ -238,6 +237,7 @@ void PropertiesDialog::listItemAdded() {
|
||||
|
||||
void PropertiesDialog::listItemSave() {
|
||||
if (!areRequiredFormsFilled()) {
|
||||
_errorMsg->exec();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ bool PropertiesDialog::areRequiredFormsFilled() {
|
||||
errors += "Missing value";
|
||||
requiredFormsFilled = false;
|
||||
}
|
||||
_errorMsg->setText("<font color='red'>" + errors + "</font>");
|
||||
_errorMsg->setInformativeText(errors);
|
||||
return requiredFormsFilled;
|
||||
}
|
||||
|
||||
@@ -322,7 +322,6 @@ void PropertiesDialog::transitionToEditMode() {
|
||||
_propertyLabel->setText("<font color='black'>Property</font>");
|
||||
_valueLabel->setText("<font color='black'>Value to set</font>");
|
||||
editBoxDisabled(false);
|
||||
_errorMsg->setText("");
|
||||
}
|
||||
|
||||
void PropertiesDialog::transitionFromEditMode() {
|
||||
@@ -338,7 +337,6 @@ void PropertiesDialog::transitionFromEditMode() {
|
||||
_propertyLabel->setText("<font color='light gray'>Property</font>");
|
||||
_valueLabel->setText("<font color='light gray'>Value to set</font>");
|
||||
editBoxDisabled(true);
|
||||
_errorMsg->setText("");
|
||||
}
|
||||
|
||||
void PropertiesDialog::editBoxDisabled(bool disabled) {
|
||||
|
||||
@@ -75,6 +75,7 @@ void TimeDialog::createWidgets() {
|
||||
{
|
||||
layout->addWidget(new QLabel("Time Type"));
|
||||
_typeCombo = new QComboBox;
|
||||
_typeCombo->setAccessibleName("Time type");
|
||||
_typeCombo->setToolTip("Types: Absolute defined time or Relative to actual time");
|
||||
connect(
|
||||
_typeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
@@ -85,17 +86,19 @@ void TimeDialog::createWidgets() {
|
||||
{
|
||||
_absoluteLabel = new QLabel("Absolute UTC:");
|
||||
layout->addWidget(_absoluteLabel);
|
||||
|
||||
|
||||
_absoluteEdit = new QDateTimeEdit;
|
||||
_absoluteEdit->setDisplayFormat("yyyy-MM-dd T hh:mm:ss");
|
||||
_absoluteEdit->setDateTime(QDateTime::currentDateTime());
|
||||
_absoluteEdit->setAccessibleName("Set absolute time");
|
||||
layout->addWidget(_absoluteEdit);
|
||||
}
|
||||
{
|
||||
_relativeLabel = new QLabel("Relative Time:");
|
||||
layout->addWidget(_relativeLabel);
|
||||
|
||||
|
||||
_relativeEdit = new QLineEdit;
|
||||
_relativeEdit->setAccessibleName("Set relative time");
|
||||
_relativeEdit->setToolTip(
|
||||
"String for relative time to actual (e.g. \"-1d\" for back 1 day)"
|
||||
);
|
||||
|
||||
@@ -230,6 +230,7 @@ void SettingsDialog::createWidgets() {
|
||||
updateSaveButton();
|
||||
}
|
||||
);
|
||||
_propertyVisibility->setObjectName("dropdown");
|
||||
layout->addWidget(_propertyVisibility, 9, 1);
|
||||
|
||||
_bypassLauncher = new QCheckBox("Bypass Launcher");
|
||||
@@ -299,6 +300,7 @@ void SettingsDialog::createWidgets() {
|
||||
updateSaveButton();
|
||||
}
|
||||
);
|
||||
_layerServer->setObjectName("dropdown");
|
||||
layout->addWidget(_layerServer, 14, 1);
|
||||
|
||||
_mrf.isEnabled = new QCheckBox("Enable MRF Caching");
|
||||
|
||||
@@ -2,6 +2,6 @@ local DataPath = asset.resource({
|
||||
Name = "Launcher Images",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "launcher_images",
|
||||
Version = 3
|
||||
Version = 4
|
||||
})
|
||||
asset.export("DataPath", DataPath)
|
||||
|
||||
@@ -55,11 +55,15 @@ public:
|
||||
struct Version {
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
|
||||
auto operator<=>(const Version&) const = default;
|
||||
};
|
||||
struct Module {
|
||||
std::string name;
|
||||
std::optional<std::string> loadedInstruction;
|
||||
std::optional<std::string> notLoadedInstruction;
|
||||
|
||||
auto operator<=>(const Module&) const = default;
|
||||
};
|
||||
struct Meta {
|
||||
std::optional<std::string> name;
|
||||
@@ -68,6 +72,8 @@ public:
|
||||
std::optional<std::string> author;
|
||||
std::optional<std::string> url;
|
||||
std::optional<std::string> license;
|
||||
|
||||
auto operator<=>(const Meta&) const = default;
|
||||
};
|
||||
|
||||
struct Property {
|
||||
@@ -79,6 +85,8 @@ public:
|
||||
SetType setType = SetType::SetPropertyValue;
|
||||
std::string name;
|
||||
std::string value;
|
||||
|
||||
auto operator<=>(const Property&) const = default;
|
||||
};
|
||||
|
||||
struct Action {
|
||||
@@ -88,11 +96,15 @@ public:
|
||||
std::string guiPath;
|
||||
bool isLocal = false;
|
||||
std::string script;
|
||||
|
||||
auto operator<=>(const Action&) const = default;
|
||||
};
|
||||
|
||||
struct Keybinding {
|
||||
KeyWithModifier key;
|
||||
std::string action;
|
||||
|
||||
auto operator<=>(const Keybinding&) const = default;
|
||||
};
|
||||
|
||||
struct Time {
|
||||
@@ -104,6 +116,8 @@ public:
|
||||
Type type = Type::Relative;
|
||||
std::string value;
|
||||
bool startPaused = false;
|
||||
|
||||
auto operator<=>(const Time&) const = default;
|
||||
};
|
||||
|
||||
struct CameraGoToNode {
|
||||
@@ -111,6 +125,8 @@ public:
|
||||
|
||||
std::string anchor;
|
||||
std::optional<double> height;
|
||||
|
||||
auto operator<=>(const CameraGoToNode&) const = default;
|
||||
};
|
||||
|
||||
struct CameraNavState {
|
||||
@@ -123,6 +139,8 @@ public:
|
||||
std::optional<glm::dvec3> up;
|
||||
std::optional<double> yaw;
|
||||
std::optional<double> pitch;
|
||||
|
||||
auto operator<=>(const CameraNavState&) const = default;
|
||||
};
|
||||
|
||||
struct CameraGoToGeo {
|
||||
@@ -132,6 +150,8 @@ public:
|
||||
double latitude = 0.0;
|
||||
double longitude = 0.0;
|
||||
std::optional<double> altitude;
|
||||
|
||||
auto operator<=>(const CameraGoToGeo&) const = default;
|
||||
};
|
||||
|
||||
using CameraType = std::variant<CameraGoToNode, CameraNavState, CameraGoToGeo>;
|
||||
@@ -140,6 +160,8 @@ public:
|
||||
explicit Profile(const std::filesystem::path& path);
|
||||
std::string serialize() const;
|
||||
|
||||
auto operator<=>(const Profile&) const = default;
|
||||
|
||||
/**
|
||||
* Saves all current settings, starting from the profile that was loaded at startup,
|
||||
* and all of the property & asset changes that were made since startup.
|
||||
|
||||
@@ -41,108 +41,7 @@
|
||||
// compiler to agree
|
||||
// NOLINTBEGIN(modernize-use-emplace)
|
||||
|
||||
namespace openspace {
|
||||
bool operator==(const openspace::Profile::Version& lhs,
|
||||
const openspace::Profile::Version& rhs) noexcept
|
||||
{
|
||||
return lhs.major == rhs.major && lhs.minor == rhs.minor;
|
||||
}
|
||||
|
||||
bool operator==(const openspace::Profile::Module& lhs,
|
||||
const openspace::Profile::Module& rhs) noexcept
|
||||
{
|
||||
return lhs.name == rhs.name &&
|
||||
lhs.loadedInstruction == rhs.loadedInstruction &&
|
||||
lhs.notLoadedInstruction == rhs.notLoadedInstruction;
|
||||
}
|
||||
|
||||
bool operator==(const openspace::Profile::Meta& lhs,
|
||||
const openspace::Profile::Meta& rhs) noexcept
|
||||
{
|
||||
return lhs.name == rhs.name &&
|
||||
lhs.version == rhs.version &&
|
||||
lhs.description == rhs.description &&
|
||||
lhs.author == rhs.author &&
|
||||
lhs.url == rhs.url &&
|
||||
lhs.license == rhs.license;
|
||||
}
|
||||
|
||||
bool operator==(const openspace::Profile::Property& lhs,
|
||||
const openspace::Profile::Property& rhs) noexcept
|
||||
{
|
||||
return lhs.setType == rhs.setType &&
|
||||
lhs.name == rhs.name &&
|
||||
lhs.value == rhs.value;
|
||||
}
|
||||
|
||||
bool operator==(const openspace::Profile::Action& lhs,
|
||||
const openspace::Profile::Action& rhs) noexcept
|
||||
{
|
||||
return lhs.identifier == rhs.identifier &&
|
||||
lhs.documentation == rhs.documentation &&
|
||||
lhs.name == rhs.name &&
|
||||
lhs.guiPath == rhs.guiPath &&
|
||||
lhs.isLocal == rhs.isLocal &&
|
||||
lhs.script == rhs.script;
|
||||
}
|
||||
|
||||
bool operator==(const openspace::Profile::Keybinding& lhs,
|
||||
const openspace::Profile::Keybinding& rhs) noexcept
|
||||
{
|
||||
return lhs.key == rhs.key && lhs.action == rhs.action;
|
||||
}
|
||||
|
||||
bool operator==(const openspace::Profile::Time& lhs,
|
||||
const openspace::Profile::Time& rhs) noexcept
|
||||
{
|
||||
return lhs.type == rhs.type && lhs.value == rhs.value;
|
||||
}
|
||||
|
||||
bool operator==(const openspace::Profile::CameraGoToNode& lhs,
|
||||
const openspace::Profile::CameraGoToNode& rhs) noexcept
|
||||
{
|
||||
return lhs.anchor == rhs.anchor && lhs.height == rhs.height;
|
||||
}
|
||||
|
||||
bool operator==(const openspace::Profile::CameraNavState& lhs,
|
||||
const openspace::Profile::CameraNavState& rhs) noexcept
|
||||
{
|
||||
return lhs.anchor == rhs.anchor &&
|
||||
lhs.aim == rhs.aim &&
|
||||
lhs.referenceFrame == rhs.referenceFrame &&
|
||||
lhs.position == rhs.position &&
|
||||
lhs.up == rhs.up &&
|
||||
lhs.yaw == rhs.yaw &&
|
||||
lhs.pitch == rhs.pitch;
|
||||
}
|
||||
|
||||
bool operator==(const openspace::Profile::CameraGoToGeo& lhs,
|
||||
const openspace::Profile::CameraGoToGeo& rhs) noexcept
|
||||
{
|
||||
return lhs.anchor == rhs.anchor &&
|
||||
lhs.latitude == rhs.latitude &&
|
||||
lhs.longitude == rhs.longitude &&
|
||||
lhs.altitude == rhs.altitude;
|
||||
}
|
||||
|
||||
bool operator==(const openspace::Profile& lhs,
|
||||
const openspace::Profile& rhs) noexcept
|
||||
{
|
||||
return lhs.version == rhs.version &&
|
||||
lhs.modules == rhs.modules &&
|
||||
lhs.meta == rhs.meta &&
|
||||
lhs.assets == rhs.assets &&
|
||||
lhs.properties == rhs.properties &&
|
||||
lhs.actions == rhs.actions &&
|
||||
lhs.keybindings == rhs.keybindings &&
|
||||
lhs.time == rhs.time &&
|
||||
lhs.deltaTimes == rhs.deltaTimes &&
|
||||
lhs.camera == rhs.camera &&
|
||||
lhs.markNodes == rhs.markNodes &&
|
||||
lhs.additionalScripts == rhs.additionalScripts &&
|
||||
lhs.ignoreUpdates == rhs.ignoreUpdates;
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::ostream& operator<<(std::ostream& os, const openspace::Profile& profile) {
|
||||
os << profile.serialize();
|
||||
return os;
|
||||
|
||||
Reference in New Issue
Block a user