diff --git a/data/ui/options_dialog.ui b/data/ui/options_dialog.ui
index 19100cd..bcdb7a4 100644
--- a/data/ui/options_dialog.ui
+++ b/data/ui/options_dialog.ui
@@ -39,9 +39,9 @@
0
- -511
+ -555
394
- 850
+ 872
@@ -573,6 +573,23 @@
+ -
+
+
+
+
+
+
+ -
+
+
+ If ticked, some windows restore their last known position where they were closed.
+
+
+ Restore Window Position
+
+
+
diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp
index 20eaaa3..bcc1ad5 100644
--- a/src/aoapplication.cpp
+++ b/src/aoapplication.cpp
@@ -51,10 +51,7 @@ void AOApplication::construct_lobby()
w_lobby = new Lobby(this, net_manager);
- QRect geometry = QGuiApplication::primaryScreen()->geometry();
- int x = (geometry.width() - w_lobby->width()) / 2;
- int y = (geometry.height() - w_lobby->height()) / 2;
- w_lobby->move(x, y);
+ centerOrMoveWidgetOnPrimaryScreen(w_lobby);
if (Options::getInstance().discordEnabled())
{
@@ -96,10 +93,7 @@ void AOApplication::construct_courtroom()
w_courtroom = new Courtroom(this);
- QRect geometry = QGuiApplication::primaryScreen()->geometry();
- int x = (geometry.width() - w_courtroom->width()) / 2;
- int y = (geometry.height() - w_courtroom->height()) / 2;
- w_courtroom->move(x, y);
+ centerOrMoveWidgetOnPrimaryScreen(w_courtroom);
if (demo_server != nullptr)
{
@@ -235,6 +229,34 @@ void AOApplication::initBASS()
}
}
+bool AOApplication::pointExistsOnScreen(QPoint point)
+{
+ for (QScreen *screen : QApplication::screens())
+ {
+ if (screen->availableGeometry().contains(point))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void AOApplication::centerOrMoveWidgetOnPrimaryScreen(QWidget *widget)
+{
+ auto point = Options::getInstance().windowPosition(widget->objectName());
+ if (!Options::getInstance().restoreWindowPositionEnabled() || !point.has_value() || !pointExistsOnScreen(point.value()))
+ {
+ QRect geometry = QGuiApplication::primaryScreen()->geometry();
+ int x = (geometry.width() - widget->width()) / 2;
+ int y = (geometry.height() - widget->height()) / 2;
+ widget->move(x, y);
+ }
+ else
+ {
+ widget->move(point->x(), point->y());
+ }
+}
+
#if (defined(_WIN32) || defined(_WIN64))
void AOApplication::load_bass_plugins()
{
diff --git a/src/aoapplication.h b/src/aoapplication.h
index 953e0db..e90579d 100644
--- a/src/aoapplication.h
+++ b/src/aoapplication.h
@@ -325,6 +325,9 @@ public:
// The file name of the log file in base/logs.
QString log_filename;
+ bool pointExistsOnScreen(QPoint point);
+ void centerOrMoveWidgetOnPrimaryScreen(QWidget *widget);
+
void initBASS();
static void load_bass_plugins();
static void CALLBACK BASSreset(HSTREAM handle, DWORD channel, DWORD data, void *user);
diff --git a/src/charselect.cpp b/src/charselect.cpp
index 8bce410..d36220a 100644
--- a/src/charselect.cpp
+++ b/src/charselect.cpp
@@ -230,9 +230,9 @@ void Courtroom::on_char_button_context_menu_requested(const QPoint &pos)
}
QMenu *menu = new QMenu(this);
- menu->addAction(QString("Edit " + char_name + "/char.ini"), this, [=] { QDesktopServices::openUrl(QUrl::fromLocalFile(char_ini_path)); });
+ menu->addAction(QString("Edit " + char_name + "/char.ini"), this, [=, this] { QDesktopServices::openUrl(QUrl::fromLocalFile(char_ini_path)); });
menu->addSeparator();
- menu->addAction(QString("Open character folder " + char_name), this, [=] {
+ menu->addAction(QString("Open character folder " + char_name), this, [=, this] {
QString p_path = ao_app->get_real_path(VPath("characters/" + char_name + "/"));
if (!dir_exists(p_path))
{
diff --git a/src/courtroom.cpp b/src/courtroom.cpp
index 6350cd9..6def0b5 100644
--- a/src/courtroom.cpp
+++ b/src/courtroom.cpp
@@ -9,13 +9,12 @@
Courtroom::Courtroom(AOApplication *p_ao_app)
: QMainWindow()
+ , ao_app{p_ao_app}
{
- ao_app = p_ao_app;
-
- this->setWindowFlags((this->windowFlags() | Qt::CustomizeWindowHint) & ~Qt::WindowMaximizeButtonHint);
+ setWindowFlags((this->windowFlags() | Qt::CustomizeWindowHint) & ~Qt::WindowMaximizeButtonHint);
+ setObjectName("courtroom");
ao_app->initBASS();
-
keepalive_timer = new QTimer(this);
keepalive_timer->start(45000);
@@ -1920,6 +1919,12 @@ void Courtroom::set_judge_buttons()
show_judge_controls(ao_app->get_pos_is_judge(current_or_default_side()));
}
+void Courtroom::closeEvent(QCloseEvent *event)
+{
+ Options::getInstance().setWindowPosition(objectName(), pos());
+ QMainWindow::closeEvent(event);
+}
+
void Courtroom::on_chat_return_pressed()
{
if (is_muted)
@@ -5204,7 +5209,7 @@ void Courtroom::on_pos_dropdown_context_menu_requested(const QPoint &pos)
QMenu *menu = new QMenu(ui_iniswap_dropdown);
menu->setAttribute(Qt::WA_DeleteOnClose);
- menu->addAction(QString("Open background " + current_background), this, [=] {
+ menu->addAction(QString("Open background " + current_background), this, [=, this] {
QString p_path = ao_app->get_real_path(VPath("background/" + current_background + "/"));
if (!dir_exists(p_path))
{
@@ -5316,7 +5321,7 @@ void Courtroom::on_iniswap_context_menu_requested(const QPoint &pos)
}
menu->addSeparator();
- menu->addAction(QString("Open character folder " + current_char), this, [=] {
+ menu->addAction(QString("Open character folder " + current_char), this, [=, this] {
QString p_path = ao_app->get_real_path(VPath("characters/" + current_char + "/"));
if (!dir_exists(p_path))
{
@@ -6140,7 +6145,7 @@ void Courtroom::on_text_color_context_menu_requested(const QPoint &pos)
QMenu *menu = new QMenu(this);
menu->setAttribute(Qt::WA_DeleteOnClose);
- menu->addAction(QString("Open currently used chat_config.ini"), this, [=] {
+ menu->addAction(QString("Open currently used chat_config.ini"), this, [=, this] {
QString p_path = ao_app->get_asset("chat_config.ini", Options::getInstance().theme(), Options::getInstance().subTheme(), ao_app->default_theme, ao_app->get_chat(current_char));
if (!file_exists(p_path))
{
diff --git a/src/courtroom.h b/src/courtroom.h
index 905fd17..6cae0ff 100644
--- a/src/courtroom.h
+++ b/src/courtroom.h
@@ -300,6 +300,9 @@ public:
void set_judge_state(JudgeState new_state);
void set_judge_buttons();
+protected:
+ virtual void closeEvent(QCloseEvent *event) override;
+
private:
AOApplication *ao_app;
diff --git a/src/lobby.cpp b/src/lobby.cpp
index 5fb0f50..1f37f4b 100644
--- a/src/lobby.cpp
+++ b/src/lobby.cpp
@@ -11,12 +11,12 @@
#include
Lobby::Lobby(AOApplication *p_ao_app, NetworkManager *p_net_manager)
- : QMainWindow()
+ : QMainWindow{}
+ , ao_app{p_ao_app}
+ , net_manager{p_net_manager}
{
- ao_app = p_ao_app;
- net_manager = p_net_manager;
-
reloadUi();
+ setObjectName("lobby");
}
void Lobby::on_tab_changed(int index)
@@ -82,6 +82,12 @@ int Lobby::pageSelected()
return current_page;
}
+void Lobby::closeEvent(QCloseEvent *event)
+{
+ Options::getInstance().setWindowPosition(objectName(), pos());
+ QMainWindow::closeEvent(event);
+}
+
void Lobby::reset_selection()
{
last_index = -1;
@@ -162,7 +168,7 @@ void Lobby::loadUI()
FROM_UI(QTextBrowser, server_description_text);
FROM_UI(QPushButton, connect_button);
connect(ui_connect_button, &QPushButton::released, net_manager, &NetworkManager::join_to_server);
- connect(ui_connect_button, &QPushButton::released, this, [=] { ui_server_player_count_lbl->setText(tr("Joining Server...")); });
+ connect(ui_connect_button, &QPushButton::released, this, [=, this] { ui_server_player_count_lbl->setText(tr("Joining Server...")); });
connect(net_manager, &NetworkManager::server_connected, ui_connect_button, &QPushButton::setEnabled);
FROM_UI(QTextBrowser, motd_text);
diff --git a/src/lobby.h b/src/lobby.h
index 4b4d624..8b894f4 100644
--- a/src/lobby.h
+++ b/src/lobby.h
@@ -31,6 +31,9 @@ public:
int get_selected_server();
int pageSelected();
+protected:
+ void closeEvent(QCloseEvent *event) override;
+
private:
AOApplication *ao_app;
NetworkManager *net_manager;
diff --git a/src/options.cpp b/src/options.cpp
index 9145aa4..fbcf01e 100644
--- a/src/options.cpp
+++ b/src/options.cpp
@@ -763,3 +763,28 @@ QString Options::getUIAsset(QString f_asset_name)
qWarning() << "Unable to locate ui-asset" << f_asset_name << "in theme" << theme() << "Defaulting to embeeded asset.";
return QString(":/data/ui/" + f_asset_name);
}
+
+void Options::setWindowPosition(QString widget, QPoint position)
+{
+ config.setValue("windows/position_" + widget, position);
+}
+
+std::optional Options::windowPosition(QString widget)
+{
+ QPoint point = config.value("windows/position_" + widget, QPoint()).toPoint();
+ if (point.isNull())
+ {
+ return std::nullopt;
+ }
+ return std::optional(point);
+}
+
+bool Options::restoreWindowPositionEnabled() const
+{
+ return config.value("windows/restore", true).toBool();
+}
+
+void Options::setRestoreWindowPositionEnabled(bool state)
+{
+ config.setValue("windows/restore", state);
+}
diff --git a/src/options.h b/src/options.h
index 4ccc301..f28dfcd 100644
--- a/src/options.h
+++ b/src/options.h
@@ -5,6 +5,8 @@
#include
#include
+#include
+
class Options
{
public:
@@ -269,6 +271,12 @@ public:
// Theming Nonesense!
QString getUIAsset(QString f_asset_name);
+ void setWindowPosition(QString widget, QPoint position);
+ std::optional windowPosition(QString widget);
+
+ bool restoreWindowPositionEnabled() const;
+ void setRestoreWindowPositionEnabled(bool state);
+
private:
/**
* @brief QSettings object for config.ini
diff --git a/src/widgets/aooptionsdialog.cpp b/src/widgets/aooptionsdialog.cpp
index 4d55652..db3c878 100644
--- a/src/widgets/aooptionsdialog.cpp
+++ b/src/widgets/aooptionsdialog.cpp
@@ -157,10 +157,10 @@ void AOOptionsDialog::registerOption(const QString &widgetName, V (Options::*get
}
OptionEntry entry;
- entry.load = [=] {
+ entry.load = [=, this] {
setWidgetData(widget, (Options::getInstance().*getter)());
};
- entry.save = [=] {
+ entry.save = [=, this] {
(Options::getInstance().*setter)(widgetData(widget));
};
@@ -323,7 +323,7 @@ void AOOptionsDialog::setupUI()
connect(ui_theme_reload_button, &QPushButton::clicked, this, &::AOOptionsDialog::onReloadThemeClicked);
FROM_UI(QPushButton, theme_folder_button);
- connect(ui_theme_folder_button, &QPushButton::clicked, this, [=] {
+ connect(ui_theme_folder_button, &QPushButton::clicked, this, [=, this] {
QString p_path = ao_app->get_real_path(ao_app->get_theme_path("", ui_theme_combobox->itemText(ui_theme_combobox->currentIndex())));
if (!dir_exists(p_path))
{
@@ -359,6 +359,7 @@ void AOOptionsDialog::setupUI()
FROM_UI(QCheckBox, sfx_on_idle_cb);
FROM_UI(QCheckBox, evidence_double_click_cb);
FROM_UI(QCheckBox, slides_cb);
+ FROM_UI(QCheckBox, restoreposition_cb);
registerOption("theme_scaling_factor_sb", &Options::themeScalingFactor, &Options::setThemeScalingFactor);
registerOption("animated_theme_cb", &Options::animatedThemeEnabled, &Options::setAnimatedThemeEnabled);
@@ -402,6 +403,7 @@ void AOOptionsDialog::setupUI()
registerOption("sfx_on_idle_cb", &Options::playSelectedSFXOnIdle, &Options::setPlaySelectedSFXOnIdle);
registerOption("evidence_double_click_cb", &Options::evidenceDoubleClickEdit, &Options::setEvidenceDoubleClickEdit);
registerOption("slides_cb", &Options::slidesEnabled, &Options::setSlidesEnabled);
+ registerOption("restoreposition_cb", &Options::restoreWindowPositionEnabled, &Options::setRestoreWindowPositionEnabled);
// Callwords tab. This could just be a QLineEdit, but no, we decided to allow
// people to put a billion entries in.
diff --git a/src/widgets/aooptionsdialog.h b/src/widgets/aooptionsdialog.h
index b16be33..eb64a53 100644
--- a/src/widgets/aooptionsdialog.h
+++ b/src/widgets/aooptionsdialog.h
@@ -48,6 +48,7 @@ private:
QPushButton *ui_theme_folder_button;
QCheckBox *ui_evidence_double_click_cb;
QCheckBox *ui_slides_cb;
+ QCheckBox *ui_restoreposition_cb;
QCheckBox *ui_animated_theme_cb;
QSpinBox *ui_stay_time_spinbox;
QCheckBox *ui_instant_objection_cb;