summaryrefslogtreecommitdiff
path: root/wx+
diff options
context:
space:
mode:
Diffstat (limited to 'wx+')
-rw-r--r--wx+/dc.h2
-rw-r--r--wx+/grid.cpp93
-rw-r--r--wx+/no_flicker.h5
-rw-r--r--wx+/popup_dlg.cpp10
-rw-r--r--wx+/tooltip.cpp17
-rw-r--r--wx+/window_layout.h (renamed from wx+/font_size.h)41
-rw-r--r--wx+/window_tools.h216
7 files changed, 246 insertions, 138 deletions
diff --git a/wx+/dc.h b/wx+/dc.h
index e0cb2c87..a169cffe 100644
--- a/wx+/dc.h
+++ b/wx+/dc.h
@@ -13,7 +13,7 @@
#include <wx/dcbuffer.h> //for macro: wxALWAYS_NATIVE_DOUBLE_BUFFER
#include <wx/dcscreen.h>
#include <wx/bmpbndl.h>
- #include <gtk/gtk.h>
+// #include <gtk/gtk.h>
namespace zen
diff --git a/wx+/grid.cpp b/wx+/grid.cpp
index f997d72c..306d4847 100644
--- a/wx+/grid.cpp
+++ b/wx+/grid.cpp
@@ -152,7 +152,7 @@ void GridData::drawCellText(wxDC& dc, const wxRect& rect, const std::wstring& te
- wxDC::DrawText also calls wxDC::GetTextExtent()!!
=> wxDC::DrawLabel() boils down to 3(!) calls to wxDC::GetTextExtent()!!!
- wxDC::DrawLabel results in GetTextExtent() call even for empty strings!!!
- => skip the wxDC::DrawLabel() cruft and directly call wxDC::DrawText()! */
+ => NEVER EVER call wxDC::DrawLabel() cruft and directly call wxDC::DrawText()! */
assert(!contains(text, L'\n'));
if (rect.width <= 0 || rect.height <= 0 || text.empty())
return;
@@ -284,7 +284,11 @@ public:
Bind(wxEVT_MOUSEWHEEL, [this](wxMouseEvent& event) { onMouseWheel (event); });
Bind(wxEVT_MOUSE_CAPTURE_LOST, [this](wxMouseCaptureLostEvent& event) { onMouseCaptureLost(event); });
- Bind(wxEVT_KEY_DOWN, [this](wxKeyEvent& event) { onKeyDown(event); });
+ Bind(wxEVT_KEY_DOWN, [this](wxKeyEvent& event)
+ {
+ if (!sendEventToParent(event)) //let parent collect all key events
+ event.Skip();
+ });
//Bind(wxEVT_KEY_UP, [this](wxKeyEvent& event) { onKeyUp (event); }); -> superfluous?
assert(GetClientAreaOrigin() == wxPoint()); //generally assumed when dealing with coordinates below
@@ -332,12 +336,6 @@ private:
virtual void onLeaveWindow (wxMouseEvent& event) { event.Skip(); }
virtual void onMouseCaptureLost(wxMouseCaptureLostEvent& event) { event.Skip(); }
- void onKeyDown(wxKeyEvent& event)
- {
- if (!sendEventToParent(event)) //let parent collect all key events
- event.Skip();
- }
-
void onMouseWheel(wxMouseEvent& event)
{
/* MSDN, WM_MOUSEWHEEL: "Sent to the focus window when the mouse wheel is rotated.
@@ -816,13 +814,6 @@ private:
void onMouseRightDown(wxMouseEvent& event) override
{
evalMouseMovement(event.GetPosition()); //update highlight in obscure cases (e.g. right-click while other context menu is open)
- freezeMouseHighlight_ = true; //e.g. while showing context menu
-
- ZEN_ON_SCOPE_EXIT(
- freezeMouseHighlight_ = false;
- //update mouse highlight (e.g. mouse position changed after showing context menu)
- evalMouseMovement(ScreenToClient(wxGetMousePosition()));
- );
const wxPoint mousePos = GetPosition() + event.GetPosition();
@@ -837,6 +828,9 @@ private:
if (fillGapAfterColumns)
sendEventToParent(GridLabelClickEvent(EVENT_GRID_COL_LABEL_MOUSE_RIGHT, ColumnType::none, mousePos));
+ //update mouse highlight (e.g. mouse position changed after showing context menu) => needed on Linux/macOS
+ evalMouseMovement(ScreenToClient(wxGetMousePosition()));
+
event.Skip();
}
@@ -883,7 +877,7 @@ private:
if (action->wantResize)
SetCursor(wxCURSOR_SIZEWE); //window-local only! :)
else
- SetCursor(*wxSTANDARD_CURSOR);
+ SetCursor(*wxSTANDARD_CURSOR); //NOOP when setting same cursor
}
else
{
@@ -926,7 +920,7 @@ private:
void setMouseHighlight(const std::optional<size_t>& hl)
{
- if (highlightCol_ != hl && !freezeMouseHighlight_)
+ if (highlightCol_ != hl)
{
highlightCol_ = hl;
Refresh();
@@ -935,8 +929,7 @@ private:
std::unique_ptr<ColumnResizing> activeResizing_;
std::unique_ptr<ColumnMove> activeClickOrMove_;
- std::optional<size_t> highlightCol_; //column during mouse-over
- bool freezeMouseHighlight_ = false;
+ std::optional<size_t> highlightCol_;
int colLabelHeight_ = 0;
const wxFont labelFont_;
@@ -966,9 +959,19 @@ public:
{
wxMouseCaptureLostEvent evt;
GetEventHandler()->ProcessEvent(evt); //better integrate into event handling rather than calling onMouseCaptureLost() directly!?
+ return;
}
- else
- event.Skip();
+
+ /* using keyboard: => clear distracting mouse highlights
+
+ wxEVT_KEY_DOWN evaluation order:
+ 1. this callback
+ 2. Grid::SubWindow ... sendEventToParent()
+ 3. clients binding to Grid wxEVT_KEY_DOWN
+ 4. Grid::onKeyDown() */
+ setMouseHighlight(std::nullopt);
+
+ event.Skip();
});
}
@@ -1050,8 +1053,11 @@ private:
if (activeSelection_->getFirstClick().row_ == row)
return activeSelection_->getFirstClick().hoverArea_;
}
- else if (highlight_.row == row)
- return highlight_.rowHover;
+ else if (highlight_)
+ {
+ if (makeSigned(highlight_->row) == row)
+ return highlight_->rowHover;
+ }
return HoverArea::none;
}
@@ -1110,13 +1116,6 @@ private:
if (auto prov = refParent().getDataProvider())
{
evalMouseMovement(event.GetPosition()); //update highlight in obscure cases (e.g. right-click while other context menu is open)
- freezeMouseHighlight_ = true; //e.g. while showing context menu
-
- ZEN_ON_SCOPE_EXIT(
- freezeMouseHighlight_ = false;
- //update mouse highlight (e.g. mouse position changed after showing context menu)
- evalMouseMovement(ScreenToClient(wxGetMousePosition()));
- );
const wxPoint mousePos = GetPosition() + event.GetPosition();
const ptrdiff_t rowCount = refParent().getRowCount();
@@ -1166,6 +1165,9 @@ private:
}
}
}
+
+ //update mouse highlight (e.g. mouse position changed after showing context menu) => needed on Linux/macOS
+ evalMouseMovement(ScreenToClient(wxGetMousePosition()));
}
event.Skip(); //allow changing focus
}
@@ -1272,7 +1274,7 @@ private:
if (activeSelection_)
activeSelection_->evalMousePos(); //call on both mouse movement + timer event!
else
- setMouseHighlight({row, rowHover});
+ setMouseHighlight(rowHover != HoverArea::none ? std::make_optional<MouseHighlight>({static_cast<size_t>(row), rowHover}) : std::nullopt);
}
}
@@ -1286,14 +1288,14 @@ private:
activeSelection_.reset();
Refresh();
}
- setMouseHighlight({-1, HoverArea::none});
+ setMouseHighlight(std::nullopt);
//event.Skip(); -> we DID handle it!
}
void onLeaveWindow(wxMouseEvent& event) override
{
if (!activeSelection_) //wxEVT_LEAVE_WINDOW does not respect mouse capture!
- setMouseHighlight({-1, HoverArea::none});
+ setMouseHighlight(std::nullopt);
//CAVEAT: we can get wxEVT_MOTION *after* wxEVT_LEAVE_WINDOW: see RowLabelWin::redirectMouseEvent()
// => therefore we also redirect wxEVT_LEAVE_WINDOW, but user will see a little flicker when moving between RowLabelWin and MainWin
@@ -1433,33 +1435,33 @@ private:
struct MouseHighlight
{
- ptrdiff_t row = -1;
+ size_t row = 0;
HoverArea rowHover = HoverArea::none;
bool operator==(const MouseHighlight&) const = default;
};
- void setMouseHighlight(const MouseHighlight& hl)
+ void setMouseHighlight(const std::optional<MouseHighlight>& hl)
{
- if (highlight_ != hl && !freezeMouseHighlight_)
+ assert(!hl || hl->row < refParent().getRowCount() && hl->rowHover != HoverArea::none);
+ if (highlight_ != hl)
{
- const ptrdiff_t rowCount = refParent().getRowCount();
- if (0 <= highlight_.row && highlight_.row < rowCount && highlight_.rowHover != HoverArea::none) //no highlight_? => NOP!
- refreshRow(highlight_.row);
+ if (highlight_)
+ refreshRow(highlight_->row);
highlight_ = hl;
- if (0 <= highlight_.row && highlight_.row < rowCount && highlight_.rowHover != HoverArea::none) //no highlight_? => NOP!
- refreshRow(highlight_.row);
+ if (highlight_)
+ refreshRow(highlight_->row);
}
}
+
RowLabelWin& rowLabelWin_;
ColLabelWin& colLabelWin_;
std::unique_ptr<MouseSelection> activeSelection_; //bound while user is selecting with mouse
- MouseHighlight highlight_; //current mouse highlight
- bool freezeMouseHighlight_ = false;
+ std::optional<MouseHighlight> highlight_;
size_t cursorRow_ = 0;
size_t selectionAnchor_ = 0;
@@ -1736,10 +1738,7 @@ void Grid::onKeyDown(wxKeyEvent& event)
auto moveCursorTo = [&](ptrdiff_t row)
{
if (rowCount > 0)
- {
- row = std::clamp<ptrdiff_t>(row, 0, rowCount - 1);
- setGridCursor(row, GridEventPolicy::allow);
- }
+ setGridCursor(std::clamp<ptrdiff_t>(row, 0, rowCount - 1), GridEventPolicy::allow);
};
auto selectWithCursorTo = [&](ptrdiff_t row)
diff --git a/wx+/no_flicker.h b/wx+/no_flicker.h
index 1c91bd48..9f91bbdb 100644
--- a/wx+/no_flicker.h
+++ b/wx+/no_flicker.h
@@ -55,9 +55,8 @@ void setTextWithUrls(wxRichTextCtrl& richCtrl, const wxString& newText)
for (auto it = newText.begin();;)
{
- const wchar_t urlPrefix[] = L"https://";
- const auto itUrl = std::search(it, newText.end(),
- urlPrefix, urlPrefix + strLength(urlPrefix));
+ const std::wstring_view urlPrefix = L"https://";
+ const auto itUrl = std::search(it, newText.end(), urlPrefix.begin(), urlPrefix.end());
if (it != itUrl)
blocks.emplace_back(BlockType::text, wxString(it, itUrl));
diff --git a/wx+/popup_dlg.cpp b/wx+/popup_dlg.cpp
index c30426cb..b5a194ad 100644
--- a/wx+/popup_dlg.cpp
+++ b/wx+/popup_dlg.cpp
@@ -13,10 +13,9 @@
#include "app_main.h"
#include "bitmap_button.h"
#include "no_flicker.h"
-#include "font_size.h"
+#include "window_layout.h"
#include "image_resources.h"
#include "popup_dlg_generated.h"
-#include "std_button_layout.h"
#include "taskbar.h"
#include "window_tools.h"
@@ -273,12 +272,17 @@ public:
//set std order after button visibility was set
setStandardButtonLayout(*bSizerStdButtons, stdBtns);
-
updateGui();
+
GetSizer()->SetSizeHints(this); //~=Fit() + SetMinSize()
+#ifdef __WXGTK3__
+ Show(); //GTK3 size calculation requires visible window: https://github.com/wxWidgets/wxWidgets/issues/16088
+ Hide(); //avoid old position flash when Center() moves window (asynchronously?)
+#endif
Center(); //needs to be re-applied after a dialog size change!
+
Raise(); //[!] popup may be triggered by ffs_batch job running in the background!
if (m_buttonAccept->IsEnabled())
diff --git a/wx+/tooltip.cpp b/wx+/tooltip.cpp
index c56d80a1..5ad5da31 100644
--- a/wx+/tooltip.cpp
+++ b/wx+/tooltip.cpp
@@ -13,7 +13,6 @@
#include "image_tools.h"
#include "bitmap_button.h"
#include "dc.h"
- #include <gtk/gtk.h>
using namespace zen;
@@ -77,11 +76,12 @@ void Tooltip::show(const wxString& text, wxPoint mousePos, const wxImage* img)
}
if (imgChanged || txtChanged)
- {
//tipWindow_->Layout(); -> apparently not needed!?
tipWindow_->GetSizer()->SetSizeHints(tipWindow_); //~=Fit() + SetMinSize()
- //Linux: Fit() seems to be broken => call EVERY time inside show, not only if text or bmp change -> still true?!?
- }
+#ifdef __WXGTK3__
+ //GTK3 size calculation requires visible window: https://github.com/wxWidgets/wxWidgets/issues/16088
+ //=> call wxWindow::Show() to "execute"
+#endif
const wxPoint newPos = wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ?
mousePos - wxPoint(fastFromDIP(TIP_WINDOW_OFFSET_DIP) + tipWindow_->GetSize().GetWidth(), 0) :
@@ -101,16 +101,13 @@ void Tooltip::hide()
{
if (tipWindow_)
{
-#if GTK_MAJOR_VERSION == 2 //the tooltip sometimes turns blank or is not shown again after it was hidden: e.g. drag-selection on middle grid
+#ifdef __WXGTK2__ //the tooltip sometimes turns blank or is not shown again after it was hidden: e.g. drag-selection on middle grid
+ //=> no such issues on GTK3!
tipWindow_->Destroy(); //apply brute force:
tipWindow_ = nullptr; //
lastUsedImg_ = wxNullImage;
-
-#elif GTK_MAJOR_VERSION == 3
- tipWindow_->Hide();
#else
-#error unknown GTK version!
+ tipWindow_->Hide();
#endif
-
}
}
diff --git a/wx+/font_size.h b/wx+/window_layout.h
index da74eada..8a86ec86 100644
--- a/wx+/font_size.h
+++ b/wx+/window_layout.h
@@ -4,12 +4,14 @@
// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
// *****************************************************************************
-#ifndef FONT_SIZE_H_23849632846734343234532
-#define FONT_SIZE_H_23849632846734343234532
+#ifndef WINDOW_LAYOUT_H_23849632846734343234532
+#define WINDOW_LAYOUT_H_23849632846734343234532
#include <zen/basic_math.h>
#include <wx/window.h>
+#include <wx/spinctrl.h>
#include <zen/scope_guard.h>
+ #include <gtk/gtk.h>
#include "dc.h"
@@ -19,7 +21,7 @@ namespace zen
void setRelativeFontSize(wxWindow& control, double factor);
void setMainInstructionFont(wxWindow& control); //following Windows/Gnome/OS X guidelines
-
+void setDefaultWidth(wxSpinCtrl& m_spinCtrl);
@@ -47,6 +49,37 @@ void setMainInstructionFont(wxWindow& control)
control.SetFont(font);
}
+
+
+inline
+void setDefaultWidth(wxSpinCtrl& m_spinCtrl)
+{
+#ifdef __WXGTK3__
+ //there's no way to set width using GTK's CSS! =>
+ m_spinCtrl.InvalidateBestSize();
+ ::gtk_entry_set_width_chars(GTK_ENTRY(m_spinCtrl.m_widget), 3);
+
+#if 0 //apparently not needed!?
+ if (::gtk_check_version(3, 12, 0) == NULL)
+ ::gtk_entry_set_max_width_chars(GTK_ENTRY(m_spinCtrl.m_widget), 3);
+#endif
+
+ //get rid of excessive default width on old GTK3 3.14 (Debian);
+ //gtk_entry_set_width_chars() not working => mitigate
+ m_spinCtrl.SetMinSize({fastFromDIP(100), -1}); //must be wider than gtk_entry_set_width_chars(), or it breaks newer GTK e.g. 3.22!
+
+#if 0 //generic property syntax:
+ GValue bval = G_VALUE_INIT;
+ ::g_value_init(&bval, G_TYPE_BOOLEAN);
+ ::g_value_set_boolean(&bval, false);
+ ZEN_ON_SCOPE_EXIT(::g_value_unset(&bval));
+ ::g_object_set_property(G_OBJECT(m_spinCtrl.m_widget), "visibility", &bval);
+#endif
+#else
+ m_spinCtrl.SetMinSize({fastFromDIP(70), -1});
+#endif
+
+}
}
-#endif //FONT_SIZE_H_23849632846734343234532
+#endif //WINDOW_LAYOUT_H_23849632846734343234532
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