From 7258c597b9140f09879db12ffc7334135b2d72d8 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 6 Aug 2018 18:26:29 +0200 Subject: [PATCH] Fix window size persistence Fixes #1116 Fixes #1175 --- lib/Slic3r/GUI.pm | 24 -------- lib/Slic3r/GUI/MainFrame.pm | 4 +- lib/Slic3r/GUI/Plater/ObjectSettingsDialog.pm | 4 +- xs/src/slic3r/GUI/AppConfig.cpp | 8 +++ xs/src/slic3r/GUI/AppConfig.hpp | 8 +++ xs/src/slic3r/GUI/ConfigWizard.cpp | 9 +-- xs/src/slic3r/GUI/GUI.cpp | 57 ++++++++++++++++++- xs/src/slic3r/GUI/GUI.hpp | 8 ++- xs/xsp/GUI.xsp | 6 ++ 9 files changed, 93 insertions(+), 35 deletions(-) diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index 483fd36f9..7510d22af 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -356,28 +356,4 @@ sub set_menu_item_icon { } } -sub save_window_pos { - my ($self, $window, $name) = @_; - - $self->{app_config}->set("${name}_pos", join ',', $window->GetScreenPositionXY); - $self->{app_config}->set("${name}_size", join ',', $window->GetSizeWH); - $self->{app_config}->set("${name}_maximized", $window->IsMaximized); - $self->{app_config}->save; -} - -sub restore_window_pos { - my ($self, $window, $name) = @_; - if ($self->{app_config}->has("${name}_pos")) { - my $size = [ split ',', $self->{app_config}->get("${name}_size"), 2 ]; - $window->SetSize($size); - - my $display = Wx::Display->new->GetClientArea(); - my $pos = [ split ',', $self->{app_config}->get("${name}_pos"), 2 ]; - if (($pos->[0] + $size->[0]/2) < $display->GetRight && ($pos->[1] + $size->[1]/2) < $display->GetBottom) { - $window->Move($pos); - } - $window->Maximize(1) if $self->{app_config}->get("${name}_maximized"); - } -} - 1; diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index 6baefa545..9d2fd19ce 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -88,7 +88,7 @@ sub new { $self->Fit; $self->SetMinSize([760, 490]); $self->SetSize($self->GetMinSize); - wxTheApp->restore_window_pos($self, "main_frame"); + Slic3r::GUI::restore_window_size($self, "main_frame"); $self->Show; $self->Layout; } @@ -101,7 +101,7 @@ sub new { return; } # save window size - wxTheApp->save_window_pos($self, "main_frame"); + Slic3r::GUI::save_window_size($self, "main_frame"); # Save the slic3r.ini. Usually the ini file is saved from "on idle" callback, # but in rare cases it may not have been called yet. wxTheApp->{app_config}->save; diff --git a/lib/Slic3r/GUI/Plater/ObjectSettingsDialog.pm b/lib/Slic3r/GUI/Plater/ObjectSettingsDialog.pm index 3befba708..3ccf1d7f8 100644 --- a/lib/Slic3r/GUI/Plater/ObjectSettingsDialog.pm +++ b/lib/Slic3r/GUI/Plater/ObjectSettingsDialog.pm @@ -33,7 +33,7 @@ sub new { $self->{layers}->Closing; # save window size - wxTheApp->save_window_pos($self, "object_settings"); + Slic3r::GUI::save_window_size($self, "object_settings"); $self->EndModal(wxID_OK); $self->{parts}->Destroy; @@ -49,7 +49,7 @@ sub new { $self->Layout; - wxTheApp->restore_window_pos($self, "object_settings"); + Slic3r::GUI::restore_window_size($self, "object_settings"); return $self; } diff --git a/xs/src/slic3r/GUI/AppConfig.cpp b/xs/src/slic3r/GUI/AppConfig.cpp index 2a33cd733..e66221351 100644 --- a/xs/src/slic3r/GUI/AppConfig.cpp +++ b/xs/src/slic3r/GUI/AppConfig.cpp @@ -60,6 +60,14 @@ void AppConfig::set_defaults() if (get("remember_output_path").empty()) set("remember_output_path", "1"); + + // Remove legacy window positions/sizes + erase("", "main_frame_maximized"); + erase("", "main_frame_pos"); + erase("", "main_frame_size"); + erase("", "object_settings_maximized"); + erase("", "object_settings_pos"); + erase("", "object_settings_size"); } void AppConfig::load() diff --git a/xs/src/slic3r/GUI/AppConfig.hpp b/xs/src/slic3r/GUI/AppConfig.hpp index b742176ed..5af635a12 100644 --- a/xs/src/slic3r/GUI/AppConfig.hpp +++ b/xs/src/slic3r/GUI/AppConfig.hpp @@ -72,6 +72,14 @@ public: bool has(const std::string &key) const { return this->has("", key); } + void erase(const std::string §ion, const std::string &key) + { + auto it = m_storage.find(section); + if (it != m_storage.end()) { + it->second.erase(key); + } + } + void clear_section(const std::string §ion) { m_storage[section].clear(); } diff --git a/xs/src/slic3r/GUI/ConfigWizard.cpp b/xs/src/slic3r/GUI/ConfigWizard.cpp index bd9b9328a..e784d8525 100644 --- a/xs/src/slic3r/GUI/ConfigWizard.cpp +++ b/xs/src/slic3r/GUI/ConfigWizard.cpp @@ -870,10 +870,11 @@ ConfigWizard::ConfigWizard(wxWindow *parent, RunReason reason) : // If the screen is smaller, resize wizrad to match, which will enable scrollbars. auto wizard_size = GetSize(); unsigned width, height; - GUI::get_current_screen_size(width, height); - wizard_size.SetWidth(std::min(wizard_size.GetWidth(), (int)(width - 2 * DIALOG_MARGIN))); - wizard_size.SetHeight(std::min(wizard_size.GetHeight(), (int)(height - 2 * DIALOG_MARGIN))); - SetMinSize(wizard_size); + if (GUI::get_current_screen_size(this, width, height)) { + wizard_size.SetWidth(std::min(wizard_size.GetWidth(), (int)(width - 2 * DIALOG_MARGIN))); + wizard_size.SetHeight(std::min(wizard_size.GetHeight(), (int)(height - 2 * DIALOG_MARGIN))); + SetMinSize(wizard_size); + } Fit(); p->btn_prev->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_prev(); }); diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 8555f0b92..0272aae4e 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #if __APPLE__ #import @@ -974,14 +975,66 @@ int get_export_option(wxFileDialog* dlg) } -void get_current_screen_size(unsigned &width, unsigned &height) +bool get_current_screen_size(wxWindow *window, unsigned &width, unsigned &height) { - wxDisplay display(wxDisplay::GetFromWindow(g_wxMainFrame)); + const auto idx = wxDisplay::GetFromWindow(window); + if (idx == wxNOT_FOUND) { + return false; + } + + wxDisplay display(idx); const auto disp_size = display.GetClientArea(); width = disp_size.GetWidth(); height = disp_size.GetHeight(); + + return true; } +void save_window_size(wxTopLevelWindow *window, const std::string &name) +{ + const wxSize size = window->GetSize(); + const wxPoint pos = window->GetPosition(); + const auto maximized = window->IsMaximized() ? "1" : "0"; + + g_AppConfig->set((boost::format("window_%1%_size") % name).str(), (boost::format("%1%;%2%") % size.GetWidth() % size.GetHeight()).str()); + g_AppConfig->set((boost::format("window_%1%_maximized") % name).str(), maximized); +} + +void restore_window_size(wxTopLevelWindow *window, const std::string &name) +{ + // XXX: This still doesn't behave nicely in some situations (mostly on Linux). + // The problem is that it's hard to obtain window position with respect to screen geometry reliably + // from wxWidgets. Sometimes wxWidgets claim a window is located on a different screen than on which + // it's actually visible. I suspect this has something to do with window initialization (maybe we + // restore window geometry too early), but haven't yet found a workaround. + + const auto display_idx = wxDisplay::GetFromWindow(window); + if (display_idx == wxNOT_FOUND) { return; } + + const auto display = wxDisplay(display_idx).GetClientArea(); + std::vector pair; + + try { + const auto key_size = (boost::format("window_%1%_size") % name).str(); + if (g_AppConfig->has(key_size)) { + if (unescape_strings_cstyle(g_AppConfig->get(key_size), pair) && pair.size() == 2) { + auto width = boost::lexical_cast(pair[0]); + auto height = boost::lexical_cast(pair[1]); + + window->SetSize(width, height); + } + } + } catch(const boost::bad_lexical_cast &) {} + + // Maximizing should be the last thing to do. + // This ensure the size and position are sane when the user un-maximizes the window. + const auto key_maximized = (boost::format("window_%1%_maximized") % name).str(); + if (g_AppConfig->get(key_maximized) == "1") { + window->Maximize(true); + } +} + + void about() { AboutDialog dlg; diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp index 165288819..68dbdfe84 100644 --- a/xs/src/slic3r/GUI/GUI.hpp +++ b/xs/src/slic3r/GUI/GUI.hpp @@ -24,6 +24,7 @@ class wxBoxSizer; class wxFlexGridSizer; class wxButton; class wxFileDialog; +class wxTopLevelWindow; namespace Slic3r { @@ -182,7 +183,12 @@ void add_export_option(wxFileDialog* dlg, const std::string& format); int get_export_option(wxFileDialog* dlg); // Returns the dimensions of the screen on which the main frame is displayed -void get_current_screen_size(unsigned &width, unsigned &height); +bool get_current_screen_size(wxWindow *window, unsigned &width, unsigned &height); + +// Save window size and maximized status into AppConfig +void save_window_size(wxTopLevelWindow *window, const std::string &name); +// Restore the above +void restore_window_size(wxTopLevelWindow *window, const std::string &name); // Display an About dialog extern void about(); diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp index c6eead1ad..8d2efb858 100644 --- a/xs/xsp/GUI.xsp +++ b/xs/xsp/GUI.xsp @@ -111,3 +111,9 @@ void register_on_request_update_callback(SV* callback) void deregister_on_request_update_callback() %code%{ Slic3r::GUI::g_on_request_update_callback.deregister_callback(); %}; +void save_window_size(SV *window, std::string name) + %code%{ Slic3r::GUI::save_window_size((wxTopLevelWindow*)wxPli_sv_2_object(aTHX_ window, "Wx::TopLevelWindow"), name); %}; + +void restore_window_size(SV *window, std::string name) + %code%{ Slic3r::GUI::restore_window_size((wxTopLevelWindow*)wxPli_sv_2_object(aTHX_ window, "Wx::TopLevelWindow"), name); %}; +