Use new wxAuiPaneLayoutInfo for serialization

Using wxAuiPaneInfo for serialization was confusing as it has some
fields that must be serialized, some fields that can be serialized but
don't have to be, and some fields which should never be serialized.

Add wxAuiPaneLayoutInfo which contains just the subset of the fields
that always must be serialized to make things more clear.

Update the sample to avoid serializing fields which can never be changed
directly by the user.
This commit is contained in:
Vadim Zeitlin
2024-12-09 13:55:17 +01:00
parent 95b8abe3fe
commit 0abce57a36
5 changed files with 157 additions and 67 deletions
+8
View File
@@ -131,6 +131,8 @@ class wxAuiManagerEvent;
class wxAuiSerializer;
class wxAuiDeserializer;
struct wxAuiPaneLayoutInfo;
using wxAuiDockUIPartArray = wxBaseArray<wxAuiDockUIPart>;
using wxAuiDockInfoArray = wxBaseArray<wxAuiDockInfo>;
using wxAuiDockInfoPtrArray = wxBaseArray<wxAuiDockInfo*>;
@@ -500,6 +502,12 @@ public:
virtual void ShowHint(const wxRect& rect);
virtual void HideHint();
// Internal functions, don't use them outside of wxWidgets itself.
void CopyLayoutFrom(wxAuiPaneLayoutInfo& layoutInfo,
const wxAuiPaneInfo& pane) const;
void CopyLayoutTo(const wxAuiPaneLayoutInfo& layoutInfo,
wxAuiPaneInfo& pane) const;
public:
// deprecated -- please use SetManagedWindow()
+38 -5
View File
@@ -10,10 +10,43 @@
#ifndef _WX_AUI_SERIALIZER_H_
#define _WX_AUI_SERIALIZER_H_
#include <utility>
// ----------------------------------------------------------------------------
// Classes used to save/load wxAuiManager layout.
// ----------------------------------------------------------------------------
// This struct contains the pane name and information about its layout that can
// be manipulated by the user interactively.
struct wxAuiPaneLayoutInfo
{
// Ctor sets the name, which is always required.
explicit wxAuiPaneLayoutInfo(wxString name_) : name{std::move(name_)} { }
// Unique name of the pane.
wxString name;
// Identifies the dock containing the pane.
int dock_direction = wxAUI_DOCK_LEFT;
int dock_layer = 0;
int dock_row = 0;
int dock_pos = 0;
int dock_proportion = 0;
// Floating pane geometry, may be invalid.
wxPoint floating_pos = wxDefaultPosition;
wxSize floating_size = wxDefaultSize;
// True if the pane is currently maximized.
//
// Note that it's the only field of this struct which doesn't directly
// correspond to a field of wxAuiPaneInfo.
bool is_maximized = false;
};
// wxAuiSerializer is used with wxAuiManager::SaveLayout().
//
// This is an abstract base class, you need to inherit from it and override its
@@ -40,7 +73,7 @@ public:
virtual void BeforeSavePanes() { }
// Save information about the given pane.
virtual void SavePane(const wxAuiPaneInfo& pane) = 0;
virtual void SavePane(const wxAuiPaneLayoutInfo& pane) = 0;
// Called after the last call to SavePane(), does nothing by default.
virtual void AfterSavePanes() { }
@@ -82,7 +115,7 @@ public:
virtual void BeforeLoad() { }
// Load information about all the panes previously saved with SavePane().
virtual std::vector<wxAuiPaneInfo> LoadPanes() = 0;
virtual std::vector<wxAuiPaneLayoutInfo> LoadPanes() = 0;
// Create the window to be managed by the given pane: this is called if any
// of the panes returned by LoadPanes() doesn't exist in the existing
@@ -90,9 +123,9 @@ public:
//
// If this function returns nullptr, the pane is not added to the manager.
//
// Note that the pane may (and usually will, if a window is created) be
// modified, to set fields such as caption or icon that wouldn't normally
// be serialized.
// Note that the pane info may (and usually will, if a window is created)
// be modified, to set fields such as caption or icon and any flags other
// "maximized".
virtual wxWindow* CreatePaneWindow(wxAuiPaneInfo& WXUNUSED(pane))
{
return nullptr;
+48 -1
View File
@@ -7,6 +7,53 @@
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
/**
Description of user-modifiable pane layout information.
This struct is used with wxAuiSerializer and wxAuiDeserializer to store the
pane layout. Its fields have the same meaning as the corresponding fields
in wxAuiPaneInfo (with the exception of `is_maximized`), but it doesn't
contain the fields that it wouldn't make sense to serialize.
@since 3.3.0
*/
struct wxAuiPaneLayoutInfo
{
/**
Ctor sets the name, which is always required.
*/
explicit wxAuiPaneLayoutInfo(wxString name);
/// Unique name of the pane.
wxString name;
/// Direction of the dock containing the pane.
int dock_direction = wxAUI_DOCK_LEFT;
/// Layer of the dock containing the pane.
int dock_layer = 0;
/// Row of the dock containing the pane.
int dock_row = 0;
/// Position of the pane in the dock containing it.
int dock_pos = 0;
/// Relative proportion of the dock allocated to this pane.
int dock_proportion = 0;
/// Position of the pane when floating, may be invalid.
wxPoint floating_pos = wxDefaultPosition;
/// Size of the pane when floating, may be invalid.
wxSize floating_size = wxDefaultSize;
/// True if the pane is currently maximized.
bool is_maximized = false;
};
/**
@class wxAuiSerializer
@@ -67,7 +114,7 @@ public:
it does _not_ need to perform any scaling itself to ensure that the
stored values are restored correctly if the resolution changes.
*/
virtual void SavePane(const wxAuiPaneInfo& pane) = 0;
virtual void SavePane(const wxAuiPaneLayoutInfo& pane) = 0;
/**
Called after the last call to SavePane().
+14 -37
View File
@@ -1501,24 +1501,24 @@ public:
m_panes.reset(new wxXmlNode(wxXML_ELEMENT_NODE, "panes"));
}
virtual void SavePane(const wxAuiPaneInfo& pane) override
virtual void SavePane(const wxAuiPaneLayoutInfo& pane) override
{
auto node = new wxXmlNode(wxXML_ELEMENT_NODE, "pane");
node->AddAttribute("name", pane.name);
AddChild(node, "caption", pane.caption);
AddChild(node, "state", pane.state);
AddChild(node, "direction", pane.dock_direction);
AddChild(node, "layer", pane.dock_layer);
AddChild(node, "row", pane.dock_row);
AddChild(node, "position", pane.dock_pos);
AddChild(node, "proportion", pane.dock_proportion);
AddChild(node, "best-size", pane.best_size);
AddChild(node, "min-size", pane.min_size);
AddChild(node, "max-size", pane.max_size);
AddChild(node, "floating-rect",
wxRect(pane.floating_pos, pane.floating_size));
// Don't bother creating many "maximized" nodes with value 0 when we
// can have at most one of them with value 1.
if ( pane.is_maximized )
AddChild(node, "maximized", 1);
m_panes->AddChild(node);
}
@@ -1566,12 +1566,6 @@ private:
AddChild(parent, name, wxString::Format("%u", value));
}
void AddChild(wxXmlNode* parent, const wxString& name, const wxSize& size)
{
if ( size != wxDefaultSize )
AddChild(parent, name, wxString::Format("%dx%d", size.x, size.y));
}
void AddChild(wxXmlNode* parent, const wxString& name, const wxRect& rect)
{
if ( rect.GetPosition() != wxDefaultPosition ||
@@ -1646,9 +1640,9 @@ public:
}
// Implement wxAuiDeserializer methods.
virtual std::vector<wxAuiPaneInfo> LoadPanes() override
virtual std::vector<wxAuiPaneLayoutInfo> LoadPanes() override
{
std::vector<wxAuiPaneInfo> panes;
std::vector<wxAuiPaneLayoutInfo> panes;
for ( wxXmlNode* node = m_panes->GetChildren(); node; node = node->GetNext() )
{
@@ -1656,23 +1650,14 @@ public:
throw std::runtime_error("Unexpected pane node name");
{
wxAuiPaneInfo pane;
pane.name = node->GetAttribute("name");
wxAuiPaneLayoutInfo pane{node->GetAttribute("name")};
for ( wxXmlNode* child = node->GetChildren(); child; child = child->GetNext() )
{
const wxString& name = child->GetName();
const wxString& content = child->GetNodeContent();
if ( name == "caption" )
{
pane.caption = content;
}
else if ( name == "state" )
{
pane.state = wxAuiPaneInfo::wxAuiPaneState(GetInt(content));
}
else if ( name == "direction" )
if ( name == "direction" )
{
pane.dock_direction = GetInt(content);
}
@@ -1692,18 +1677,6 @@ public:
{
pane.dock_proportion = GetInt(content);
}
else if ( name == "best-size" )
{
pane.best_size = GetSize(content);
}
else if ( name == "min-size" )
{
pane.min_size = GetSize(content);
}
else if ( name == "max-size" )
{
pane.max_size = GetSize(content);
}
else if ( name == "floating-rect" )
{
auto rect = GetRect(content);
@@ -1711,6 +1684,10 @@ public:
pane.floating_pos = rect.GetPosition();
pane.floating_size = rect.GetSize();
}
else if ( name == "maximized" )
{
pane.is_maximized = GetInt(content) != 0;
}
else
{
throw std::runtime_error("Unexpected pane child node name");
+49 -24
View File
@@ -1390,6 +1390,39 @@ void MakeLogical(wxWindow* w, wxRect& rect)
} // anonymous namespace
// Copy pane layout information between wxAuiPaneLayoutInfo and wxAuiPaneInfo,
// used when (de)serializing the layout.
void
wxAuiManager::CopyLayoutFrom(wxAuiPaneLayoutInfo& layoutInfo,
const wxAuiPaneInfo& pane) const
{
layoutInfo.dock_direction = pane.dock_direction;
layoutInfo.dock_layer = pane.dock_layer;
layoutInfo.dock_row = pane.dock_row;
layoutInfo.dock_pos = pane.dock_pos;
layoutInfo.dock_proportion = pane.dock_proportion;
layoutInfo.floating_pos = pane.floating_pos;
layoutInfo.floating_size = pane.floating_size;
layoutInfo.is_maximized = pane.HasFlag(wxAuiPaneInfo::optionMaximized);
}
void
wxAuiManager::CopyLayoutTo(const wxAuiPaneLayoutInfo& layoutInfo,
wxAuiPaneInfo& pane) const
{
pane.dock_direction = layoutInfo.dock_direction;
pane.dock_layer = layoutInfo.dock_layer;
pane.dock_row = layoutInfo.dock_row;
pane.dock_pos = layoutInfo.dock_pos;
pane.dock_proportion = layoutInfo.dock_proportion;
pane.floating_pos = layoutInfo.floating_pos;
pane.floating_size = layoutInfo.floating_size;
pane.SetFlag(wxAuiPaneInfo::optionMaximized, layoutInfo.is_maximized);
}
void wxAuiManager::SaveLayout(wxAuiSerializer& serializer) const
{
serializer.BeforeSave();
@@ -1400,18 +1433,13 @@ void wxAuiManager::SaveLayout(wxAuiSerializer& serializer) const
for ( const auto& pane : m_panes )
{
auto paneDIP = pane;
wxAuiPaneLayoutInfo layoutInfo{pane.name};
CopyLayoutFrom(layoutInfo, pane);
MakeDIP(m_frame, paneDIP.best_size);
MakeDIP(m_frame, paneDIP.min_size);
MakeDIP(m_frame, paneDIP.max_size);
MakeDIP(m_frame, layoutInfo.floating_pos);
MakeDIP(m_frame, layoutInfo.floating_size);
MakeDIP(m_frame, paneDIP.floating_pos);
MakeDIP(m_frame, paneDIP.floating_size);
MakeDIP(m_frame, paneDIP.rect);
serializer.SavePane(paneDIP);
serializer.SavePane(layoutInfo);
}
serializer.AfterSavePanes();
@@ -1489,30 +1517,23 @@ void wxAuiManager::LoadLayout(wxAuiDeserializer& deserializer)
};
std::vector<NewPane> newPanes;
for ( const auto& paneDIP : deserializer.LoadPanes() )
auto layoutInfos = deserializer.LoadPanes();
for ( auto& layoutInfo : layoutInfos )
{
auto pane = paneDIP;
MakeLogical(m_frame, layoutInfo.floating_pos);
MakeLogical(m_frame, layoutInfo.floating_size);
MakeLogical(m_frame, pane.best_size);
MakeLogical(m_frame, pane.min_size);
MakeLogical(m_frame, pane.max_size);
MakeLogical(m_frame, pane.floating_pos);
MakeLogical(m_frame, pane.floating_size);
MakeLogical(m_frame, pane.rect);
if ( pane.IsMaximized() )
if ( layoutInfo.is_maximized )
hasMaximized = true;
// Find the pane with the same name in the existing layout.
bool found = false;
for ( auto& existingPane : panes )
{
if ( existingPane.name == pane.name )
if ( existingPane.name == layoutInfo.name )
{
// Update the existing pane with the restored layout.
existingPane.SafeSet(pane);
CopyLayoutTo(layoutInfo, existingPane);
found = true;
break;
@@ -1523,6 +1544,10 @@ void wxAuiManager::LoadLayout(wxAuiDeserializer& deserializer)
// create a new window for it if desired, otherwise just ignore it.
if ( !found )
{
wxAuiPaneInfo pane;
pane.name = layoutInfo.name;
CopyLayoutTo(layoutInfo, pane);
if ( const auto w = deserializer.CreatePaneWindow(pane) )
newPanes.emplace_back(w, pane);
}