summaryrefslogtreecommitdiff
path: root/wx+/window_tools.h
diff options
context:
space:
mode:
Diffstat (limited to 'wx+/window_tools.h')
-rw-r--r--wx+/window_tools.h216
1 files changed, 146 insertions, 70 deletions
diff --git a/wx+/window_tools.h b/wx+/window_tools.h
index 73faf272..179508f8 100644
--- a/wx+/window_tools.h
+++ b/wx+/window_tools.h
@@ -92,96 +92,172 @@ private:
namespace
{
-void setInitialWindowSize(wxTopLevelWindow& topWin, wxSize size, std::optional<wxPoint> pos, bool isMaximized, wxSize defaultSize)
+class WindowLayout
{
- wxSize newSize = defaultSize;
- std::optional<wxPoint> newPos;
- //set dialog size and position:
- // - width/height are invalid if the window is minimized (eg x,y = -32000; width = 160, height = 28)
- // - multi-monitor setup: dialog may be placed on second monitor which is currently turned off
- if (size.GetWidth () > 0 &&
- size.GetHeight() > 0)
+public:
+ struct Layout
{
- if (pos)
+ std::optional<wxSize> size;
+ std::optional<wxPoint> pos;
+ bool isMaximized = false;
+ };
+ static void setInitial(wxTopLevelWindow& topWin, const Layout& layout, wxSize defaultSize)
+ {
+ initialLayouts_[&topWin] = layout;
+
+ wxSize newSize = defaultSize;
+ std::optional<wxPoint> newPos;
+ //set dialog size and position:
+ // - width/height are invalid if the window is minimized (eg x,y = -32000; width = 160, height = 28)
+ // - multi-monitor setup: dialog may be placed on second monitor which is currently turned off
+ if (layout.size &&
+ layout.size->GetWidth () > 0 &&
+ layout.size->GetHeight() > 0)
{
- //calculate how much of the dialog will be visible on screen
- const int dlgArea = size.GetWidth() * size.GetHeight();
- int dlgAreaMaxVisible = 0;
+ if (layout.pos)
+ {
+ //calculate how much of the dialog will be visible on screen
+ const int dlgArea = layout.size->GetWidth() * layout.size->GetHeight();
+ int dlgAreaMaxVisible = 0;
+
+ const int monitorCount = wxDisplay::GetCount();
+ for (int i = 0; i < monitorCount; ++i)
+ {
+ wxRect overlap = wxDisplay(i).GetClientArea().Intersect(wxRect(*layout.pos, *layout.size));
+ dlgAreaMaxVisible = std::max(dlgAreaMaxVisible, overlap.GetWidth() * overlap.GetHeight());
+ }
+
+ if (dlgAreaMaxVisible > 0.1 * dlgArea //at least 10% of the dialog should be visible!
+ )
+ {
+ newSize = *layout.size;
+ newPos = layout.pos;
+ }
+ }
+ else
+ newSize = *layout.size;
+ }
- const int monitorCount = wxDisplay::GetCount();
- for (int i = 0; i < monitorCount; ++i)
+ //old comment: "wxGTK's wxWindow::SetSize seems unreliable and behaves like a wxWindow::SetClientSize
+ // => use wxWindow::SetClientSize instead (for the record: no such issue on Windows/macOS)
+ //2018-10-15: Weird new problem on CentOS/Ubuntu: SetClientSize() + SetPosition() fail to set correct dialog *position*, but SetSize() + SetPosition() do!
+ // => old issues with SetSize() seem to be gone... => revert to SetSize()
+ if (newPos)
+ topWin.SetSize(wxRect(*newPos, newSize));
+ else
+ {
+ topWin.SetSize(newSize);
+ topWin.Center();
+ }
+
+ if (layout.isMaximized) //no real need to support both maximize and full screen functions
+ {
+ topWin.Maximize(true);
+ }
+
+
+#if 0 //wxWidgets alternative: apparently no benefits (not even on Wayland! but strange decisions: why restore the minimized state!???)
+ class GeoSerializer : public wxTopLevelWindow::GeometrySerializer
+ {
+ public:
+ GeoSerializer(const std::string& l)
{
- wxRect overlap = wxDisplay(i).GetClientArea().Intersect(wxRect(*pos, size));
- dlgAreaMaxVisible = std::max(dlgAreaMaxVisible, overlap.GetWidth() * overlap.GetHeight());
+ split(l, ' ', [&](const std::string_view phrase)
+ {
+ assert(phrase.empty() || contains(phrase, '='));
+ if (contains(phrase, '='))
+ valuesByName_[utfTo<wxString>(beforeFirst(phrase, '=', IfNotFoundReturn::none))] =
+ /**/ stringTo<int>(afterFirst(phrase, '=', IfNotFoundReturn::none));
+ });
}
- if (dlgAreaMaxVisible > 0.1 * dlgArea //at least 10% of the dialog should be visible!
- )
+ bool SaveField(const wxString& name, int value) const /*NO, this must not be const!*/ override { return false; }
+
+ bool RestoreField(const wxString& name, int* value) /*const: yes, this MAY(!) be const*/ override
{
- newSize = size;
- newPos = pos;
+ auto it = valuesByName_.find(name);
+ if (it == valuesByName_.end())
+ return false;
+ * value = it->second;
+ return true;
}
- }
- else
- newSize = size;
- }
+ private:
+ std::unordered_map<wxString, int> valuesByName_;
+ } serializer(layout);
- //old comment: "wxGTK's wxWindow::SetSize seems unreliable and behaves like a wxWindow::SetClientSize
- // => use wxWindow::SetClientSize instead (for the record: no such issue on Windows/macOS)
- //2018-10-15: Weird new problem on CentOS/Ubuntu: SetClientSize() + SetPosition() fail to set correct dialog *position*, but SetSize() + SetPosition() do!
- // => old issues with SetSize() seem to be gone... => revert to SetSize()
- if (newPos)
- topWin.SetSize(wxRect(*newPos, newSize));
- else
- {
- topWin.SetSize(newSize);
- topWin.Center();
+ if (!topWin.RestoreToGeometry(serializer)) //apparently no-fail as long as GeometrySerializer::RestoreField is!
+ assert(false);
+#endif
}
- if (isMaximized) //no real need to support both maximize and full screen functions
+ //destructive! changes window size!
+ static Layout getBeforeClose(wxTopLevelWindow& topWin)
{
- topWin.Maximize(true);
- }
-}
-
+ //we need to portably retrieve non-iconized, non-maximized size and position
+ // non-portable: Win32 GetWindowPlacement(); wxWidgets take: wxTopLevelWindow::SaveGeometry/RestoreToGeometry()
+ if (topWin.IsIconized())
+ topWin.Iconize(false);
-struct WindowLayoutWeak
-{
- std::optional<wxSize> size;
- std::optional<wxPoint> pos;
- bool isMaximized = false;
-};
-//destructive! changes window size!
-WindowLayoutWeak getWindowSizeBeforeClose(wxTopLevelWindow& topWin)
-{
- //we need to portably retrieve non-iconized, non-maximized size and position
- // non-portable: Win32 GetWindowPlacement(); wxWidgets take: wxTopLevelWindow::RestoreToGeometry()
- if (topWin.IsIconized())
- topWin.Iconize(false);
+ bool isMaximized = false;
+ if (topWin.IsMaximized()) //evaluate AFTER uniconizing!
+ {
+ topWin.Maximize(false);
+ isMaximized = true;
+ }
- WindowLayoutWeak layout;
- if (topWin.IsMaximized()) //evaluate AFTER uniconizing!
- {
- topWin.Maximize(false);
- layout.isMaximized = true;
- }
+ std::optional<wxSize> size = topWin.GetSize();
+ std::optional<wxPoint> pos = topWin.GetPosition();
- layout.size = topWin.GetSize();
- layout.pos = topWin.GetPosition();
+ if (isMaximized)
+ if (!topWin.IsShown() //=> Win: can't trust size GetSize()/GetPosition(): still at full screen size!
+ //wxGTK: returns full screen size and strange position (65/-4)
+ //OS X 10.9 (but NO issue on 10.11!) returns full screen size and strange position (0/-22)
+ || pos->y < 0
+ )
+ {
+ size = std::nullopt;
+ pos = std::nullopt;
+ }
- if (layout.isMaximized)
- if (!topWin.IsShown() //=> Win: can't trust size GetSize()/GetPosition(): still at full screen size!
- //wxGTK: returns full screen size and strange position (65/-4)
- //OS X 10.9 (but NO issue on 10.11!) returns full screen size and strange position (0/-22)
- || layout.pos->y < 0
- )
+ //reuse previous values if current ones are not available:
+ if (const auto it = initialLayouts_.find(&topWin);
+ it != initialLayouts_.end())
{
- layout.size = std::nullopt;
- layout.pos = std::nullopt;
+ if (!size)
+ size = it->second.size;
+
+ if (!pos)
+ pos = it->second.pos;
}
- return layout;
-}
+ return {size, pos, isMaximized};
+
+#if 0 //wxWidgets alternative: apparently no benefits (not even on Wayland! but strange decisions: why restore the minimized state!???)
+ struct : wxTopLevelWindow::GeometrySerializer
+ {
+ bool SaveField(const wxString& name, int value) const /*NO, this must not be const!*/ override
+ {
+ layout_ += utfTo<std::string>(name) + '=' + numberTo<std::string>(value) + ' ';
+ return true;
+ }
+
+ bool RestoreField(const wxString& name, int* value) /*const: yes, this MAY(!) be const*/ override { return false; }
+
+ mutable //wxWidgets people: 1. learn when and when not to use const for input/output functions! see SaveField/RestoreField()
+ // 2. learn flexible software design: why are input/output tied up in a single GeometrySerializer implementation?
+ std::string layout_;
+ } serializer;
+
+ if (topWin.SaveGeometry(serializer)) //apparently no-fail as long as GeometrySerializer::SaveField is!
+ return serializer.layout_;
+ else
+ assert(false);
+#endif
+ }
+
+private:
+ inline static std::unordered_map<const wxTopLevelWindow* /*don't access! use as key only!*/, Layout> initialLayouts_;
+};
}
}
bgstack15