Merge branch 'tlw-geom'
Improve saving/restoring TLW geometry under MSW. See https://github.com/wxWidgets/wxWidgets/pull/795
This commit is contained in:
@@ -88,6 +88,7 @@ wxMSW:
|
||||
|
||||
- Fix hang after clearing wxTAB_TRAVERSAL style on a window with children.
|
||||
- Fix handling of AUX2 mouse button events (Trylz).
|
||||
- Fix saving/restoring window position for maximized windows.
|
||||
|
||||
|
||||
3.1.1: (released 2018-02-19)
|
||||
|
77
include/wx/gtk/private/tlwgeom.h
Normal file
77
include/wx/gtk/private/tlwgeom.h
Normal file
@@ -0,0 +1,77 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: wx/gtk/private/tlwgeom.h
|
||||
// Purpose: wxGTK-specific wxTLWGeometry class.
|
||||
// Author: Vadim Zeitlin
|
||||
// Created: 2018-04-29
|
||||
// Copyright: (c) 2018 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _WX_GTK_PRIVATE_TLWGEOM_H_
|
||||
#define _WX_GTK_PRIVATE_TLWGEOM_H_
|
||||
|
||||
class wxTLWGeometry : public wxTLWGeometryGeneric
|
||||
{
|
||||
public:
|
||||
virtual bool Save(const Serializer& ser) const wxOVERRIDE
|
||||
{
|
||||
if ( !wxTLWGeometryGeneric::Save(ser) )
|
||||
return false;
|
||||
|
||||
// Don't save the decoration sizes if we don't really have any values
|
||||
// for them.
|
||||
if ( m_decorSize.left || m_decorSize.right ||
|
||||
m_decorSize.top || m_decorSize.bottom )
|
||||
{
|
||||
ser.SaveField("decor_l", m_decorSize.left);
|
||||
ser.SaveField("decor_r", m_decorSize.right);
|
||||
ser.SaveField("decor_t", m_decorSize.top);
|
||||
ser.SaveField("decor_b", m_decorSize.bottom);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool Restore(Serializer& ser) wxOVERRIDE
|
||||
{
|
||||
if ( !wxTLWGeometryGeneric::Restore(ser) )
|
||||
return false;
|
||||
|
||||
ser.RestoreField("decor_l", &m_decorSize.left);
|
||||
ser.RestoreField("decor_r", &m_decorSize.right);
|
||||
ser.RestoreField("decor_t", &m_decorSize.top);
|
||||
ser.RestoreField("decor_b", &m_decorSize.bottom);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool GetFrom(const wxTopLevelWindow* tlw) wxOVERRIDE
|
||||
{
|
||||
if ( !wxTLWGeometryGeneric::GetFrom(tlw) )
|
||||
return false;
|
||||
|
||||
m_decorSize = tlw->m_decorSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool ApplyTo(wxTopLevelWindow* tlw) wxOVERRIDE
|
||||
{
|
||||
if ( !wxTLWGeometryGeneric::ApplyTo(tlw) )
|
||||
return false;
|
||||
|
||||
// Don't overwrite the current decoration size if we already have it.
|
||||
if ( !tlw->m_decorSize.left && !tlw->m_decorSize.right &&
|
||||
!tlw->m_decorSize.top && !tlw->m_decorSize.bottom )
|
||||
{
|
||||
tlw->m_decorSize = m_decorSize;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
wxTopLevelWindow::DecorSize m_decorSize;
|
||||
};
|
||||
|
||||
#endif // _WX_GTK_PRIVATE_TLWGEOM_H_
|
126
include/wx/msw/private/tlwgeom.h
Normal file
126
include/wx/msw/private/tlwgeom.h
Normal file
@@ -0,0 +1,126 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: wx/msw/private/tlwgeom.h
|
||||
// Purpose: wxMSW-specific wxTLWGeometry class.
|
||||
// Author: Vadim Zeitlin
|
||||
// Created: 2018-04-29
|
||||
// Copyright: (c) 2018 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _WX_MSW_PRIVATE_TLWGEOM_H_
|
||||
#define _WX_MSW_PRIVATE_TLWGEOM_H_
|
||||
|
||||
#include "wx/log.h"
|
||||
|
||||
#include "wx/msw/private.h"
|
||||
|
||||
// names for MSW-specific options
|
||||
#define wxPERSIST_TLW_MAX_X "xmax"
|
||||
#define wxPERSIST_TLW_MAX_Y "ymax"
|
||||
|
||||
class wxTLWGeometry : public wxTLWGeometryBase
|
||||
{
|
||||
public:
|
||||
wxTLWGeometry()
|
||||
{
|
||||
wxZeroMemory(m_placement);
|
||||
m_placement.length = sizeof(m_placement);
|
||||
}
|
||||
|
||||
virtual bool Save(const Serializer& ser) const wxOVERRIDE
|
||||
{
|
||||
// For compatibility with the existing saved positions/sizes, use the
|
||||
// same keys as the generic version (which was previously used under
|
||||
// MSW too).
|
||||
|
||||
// Normal position and size.
|
||||
const RECT& rc = m_placement.rcNormalPosition;
|
||||
if ( !ser.SaveField(wxPERSIST_TLW_X, rc.left) ||
|
||||
!ser.SaveField(wxPERSIST_TLW_Y, rc.top) )
|
||||
return false;
|
||||
|
||||
if ( !ser.SaveField(wxPERSIST_TLW_W, rc.right - rc.left) ||
|
||||
!ser.SaveField(wxPERSIST_TLW_H, rc.bottom - rc.top) )
|
||||
return false;
|
||||
|
||||
// Maximized/minimized state.
|
||||
UINT show = m_placement.showCmd;
|
||||
if ( !ser.SaveField(wxPERSIST_TLW_MAXIMIZED, show == SW_SHOWMAXIMIZED) )
|
||||
return false;
|
||||
|
||||
if ( !ser.SaveField(wxPERSIST_TLW_ICONIZED, show == SW_SHOWMINIMIZED) )
|
||||
return false;
|
||||
|
||||
// Maximized window position.
|
||||
const POINT pt = m_placement.ptMaxPosition;
|
||||
if ( !ser.SaveField(wxPERSIST_TLW_MAX_X, pt.x) ||
|
||||
!ser.SaveField(wxPERSIST_TLW_MAX_Y, pt.y) )
|
||||
return false;
|
||||
|
||||
// We don't currently save the minimized window position, it doesn't
|
||||
// seem useful for anything and is probably just a left over from
|
||||
// Windows 3.1 days, when icons were positioned on the desktop instead
|
||||
// of being located in the taskbar.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool Restore(Serializer& ser) wxOVERRIDE
|
||||
{
|
||||
// Normal position and size.
|
||||
wxRect r;
|
||||
if ( !ser.RestoreField(wxPERSIST_TLW_X, &r.x) ||
|
||||
!ser.RestoreField(wxPERSIST_TLW_Y, &r.y) ||
|
||||
!ser.RestoreField(wxPERSIST_TLW_W, &r.width) ||
|
||||
!ser.RestoreField(wxPERSIST_TLW_H, &r.height) )
|
||||
return false;
|
||||
wxCopyRectToRECT(r, m_placement.rcNormalPosition);
|
||||
|
||||
// Maximized/minimized state.
|
||||
int tmp;
|
||||
UINT& show = m_placement.showCmd;
|
||||
if ( ser.RestoreField(wxPERSIST_TLW_MAXIMIZED, &tmp) && tmp )
|
||||
show = SW_SHOWMAXIMIZED;
|
||||
else if ( ser.RestoreField(wxPERSIST_TLW_ICONIZED, &tmp) && tmp )
|
||||
show = SW_SHOWMINIMIZED;
|
||||
else
|
||||
show = SW_SHOWNORMAL;
|
||||
|
||||
// Maximized window position.
|
||||
if ( ser.RestoreField(wxPERSIST_TLW_MAX_X, &r.x) &&
|
||||
ser.RestoreField(wxPERSIST_TLW_MAX_Y, &r.y) )
|
||||
{
|
||||
m_placement.ptMaxPosition.x = r.x;
|
||||
m_placement.ptMaxPosition.y = r.y;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool GetFrom(const wxTopLevelWindow* tlw) wxOVERRIDE
|
||||
{
|
||||
if ( !::GetWindowPlacement(GetHwndOf(tlw), &m_placement) )
|
||||
{
|
||||
wxLogLastError(wxS("GetWindowPlacement"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool ApplyTo(wxTopLevelWindow* tlw) wxOVERRIDE
|
||||
{
|
||||
if ( !::SetWindowPlacement(GetHwndOf(tlw), &m_placement) )
|
||||
{
|
||||
wxLogLastError(wxS("SetWindowPlacement"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
WINDOWPLACEMENT m_placement;
|
||||
};
|
||||
|
||||
#endif // _WX_MSW_PRIVATE_TLWGEOM_H_
|
@@ -13,7 +13,6 @@
|
||||
#include "wx/persist/window.h"
|
||||
|
||||
#include "wx/toplevel.h"
|
||||
#include "wx/display.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// string constants used by wxPersistentTLW
|
||||
@@ -24,21 +23,13 @@
|
||||
// windows, just persistent controls which have their own specific kind strings
|
||||
#define wxPERSIST_TLW_KIND "Window"
|
||||
|
||||
// names for various persistent options
|
||||
#define wxPERSIST_TLW_X "x"
|
||||
#define wxPERSIST_TLW_Y "y"
|
||||
#define wxPERSIST_TLW_W "w"
|
||||
#define wxPERSIST_TLW_H "h"
|
||||
|
||||
#define wxPERSIST_TLW_MAXIMIZED "Maximized"
|
||||
#define wxPERSIST_TLW_ICONIZED "Iconized"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxPersistentTLW: supports saving/restoring window position and size as well
|
||||
// as maximized/iconized/restore state
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class wxPersistentTLW : public wxPersistentWindow<wxTopLevelWindow>
|
||||
class wxPersistentTLW : public wxPersistentWindow<wxTopLevelWindow>,
|
||||
private wxTopLevelWindow::GeometrySerializer
|
||||
{
|
||||
public:
|
||||
wxPersistentTLW(wxTopLevelWindow *tlw)
|
||||
@@ -50,96 +41,28 @@ public:
|
||||
{
|
||||
const wxTopLevelWindow * const tlw = Get();
|
||||
|
||||
const wxPoint pos = tlw->GetScreenPosition();
|
||||
SaveValue(wxPERSIST_TLW_X, pos.x);
|
||||
SaveValue(wxPERSIST_TLW_Y, pos.y);
|
||||
|
||||
// notice that we use GetSize() here and not GetClientSize() because
|
||||
// the latter doesn't return correct results for the minimized windows
|
||||
// (at least not under Windows)
|
||||
//
|
||||
// of course, it shouldn't matter anyhow usually, the client size
|
||||
// should be preserved as well unless the size of the decorations
|
||||
// changed between the runs
|
||||
const wxSize size = tlw->GetSize();
|
||||
SaveValue(wxPERSIST_TLW_W, size.x);
|
||||
SaveValue(wxPERSIST_TLW_H, size.y);
|
||||
|
||||
SaveValue(wxPERSIST_TLW_MAXIMIZED, tlw->IsMaximized());
|
||||
SaveValue(wxPERSIST_TLW_ICONIZED, tlw->IsIconized());
|
||||
#ifdef __WXGTK20__
|
||||
SaveValue("decor_l", tlw->m_decorSize.left);
|
||||
SaveValue("decor_r", tlw->m_decorSize.right);
|
||||
SaveValue("decor_t", tlw->m_decorSize.top);
|
||||
SaveValue("decor_b", tlw->m_decorSize.bottom);
|
||||
#endif
|
||||
tlw->SaveGeometry(*this);
|
||||
}
|
||||
|
||||
virtual bool Restore() wxOVERRIDE
|
||||
{
|
||||
wxTopLevelWindow * const tlw = Get();
|
||||
|
||||
wxPoint pos;
|
||||
wxSize size;
|
||||
|
||||
const bool hasPos = RestoreValue(wxPERSIST_TLW_X, &pos.x) &&
|
||||
RestoreValue(wxPERSIST_TLW_Y, &pos.y);
|
||||
const bool hasSize = RestoreValue(wxPERSIST_TLW_W, &size.x) &&
|
||||
RestoreValue(wxPERSIST_TLW_H, &size.y);
|
||||
#ifdef __WXGTK20__
|
||||
wxTopLevelWindowGTK::DecorSize decorSize;
|
||||
if (tlw->m_decorSize.top == 0 &&
|
||||
RestoreValue("decor_l", &decorSize.left) &&
|
||||
RestoreValue("decor_r", &decorSize.right) &&
|
||||
RestoreValue("decor_t", &decorSize.top) &&
|
||||
RestoreValue("decor_b", &decorSize.bottom))
|
||||
{
|
||||
tlw->m_decorSize = decorSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( hasPos )
|
||||
{
|
||||
// to avoid making the window completely invisible if it had been
|
||||
// shown on a monitor which was disconnected since the last run
|
||||
// (this is pretty common for notebook with external displays)
|
||||
//
|
||||
// NB: we should allow window position to be (slightly) off screen,
|
||||
// it's not uncommon to position the window so that its upper
|
||||
// left corner has slightly negative coordinate
|
||||
if ( wxDisplay::GetFromPoint(pos) != wxNOT_FOUND ||
|
||||
(hasSize && wxDisplay::GetFromPoint(pos + size) != wxNOT_FOUND) )
|
||||
{
|
||||
tlw->Move(pos, wxSIZE_ALLOW_MINUS_ONE);
|
||||
}
|
||||
//else: should we try to adjust position/size somehow?
|
||||
}
|
||||
|
||||
if ( hasSize )
|
||||
{
|
||||
// a previous version of the program could have saved the window
|
||||
// size which used to be big enough, but which is not big enough
|
||||
// any more for the new version, so check that the size we restore
|
||||
// doesn't cut off parts of the window
|
||||
size.IncTo(tlw->GetBestSize());
|
||||
tlw->SetSize(size);
|
||||
}
|
||||
|
||||
// note that the window can be both maximized and iconized
|
||||
bool maximized;
|
||||
if ( RestoreValue(wxPERSIST_TLW_MAXIMIZED, &maximized) && maximized )
|
||||
tlw->Maximize();
|
||||
|
||||
bool iconized;
|
||||
if ( RestoreValue(wxPERSIST_TLW_ICONIZED, &iconized) && iconized )
|
||||
tlw->Iconize();
|
||||
|
||||
// the most important property of the window that we restore is its
|
||||
// size, so disregard the value of hasPos here
|
||||
return hasSize;
|
||||
return tlw->RestoreToGeometry(*this);
|
||||
}
|
||||
|
||||
virtual wxString GetKind() const wxOVERRIDE { return wxPERSIST_TLW_KIND; }
|
||||
|
||||
private:
|
||||
virtual bool SaveField(const wxString& name, int value) const wxOVERRIDE
|
||||
{
|
||||
return SaveValue(name, value);
|
||||
}
|
||||
|
||||
virtual bool RestoreField(const wxString& name, int* value) wxOVERRIDE
|
||||
{
|
||||
return RestoreValue(name, value);
|
||||
}
|
||||
};
|
||||
|
||||
inline wxPersistentObject *wxCreatePersistentObject(wxTopLevelWindow *tlw)
|
||||
|
184
include/wx/private/tlwgeom.h
Normal file
184
include/wx/private/tlwgeom.h
Normal file
@@ -0,0 +1,184 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: wx/private/tlwgeom.h
|
||||
// Purpose: Declaration of platform-specific and private wxTLWGeometry.
|
||||
// Author: Vadim Zeitlin
|
||||
// Created: 2018-04-29
|
||||
// Copyright: (c) 2018 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _WX_PRIVATE_TLWGEOM_H_
|
||||
#define _WX_PRIVATE_TLWGEOM_H_
|
||||
|
||||
#include "wx/display.h"
|
||||
#include "wx/toplevel.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxTLWGeometryBase: abstract base class for platform-specific classes
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// wxTLWGeometry contains full information about the window geometry, which may
|
||||
// include things other than the obvious ones like its current position and
|
||||
// size (e.g. under MSW it also stores the position of the maximized window,
|
||||
// under GTK the size of non-client decorations etc). It is private to wx and
|
||||
// is only used indirectly, via wxTopLevelWindow::SaveGeometry() and
|
||||
// RestoreToGeometry() methods, in the public API.
|
||||
|
||||
class wxTLWGeometryBase
|
||||
{
|
||||
public:
|
||||
typedef wxTopLevelWindow::GeometrySerializer Serializer;
|
||||
|
||||
wxTLWGeometryBase() {}
|
||||
virtual ~wxTLWGeometryBase() {}
|
||||
|
||||
// Initialize from the given window.
|
||||
virtual bool GetFrom(const wxTopLevelWindow* tlw) = 0;
|
||||
|
||||
// Resize the window to use this geometry.
|
||||
virtual bool ApplyTo(wxTopLevelWindow* tlw) = 0;
|
||||
|
||||
// Serialize or deserialize the object by using the provided object for
|
||||
// writing/reading the values of the different fields of this object.
|
||||
virtual bool Save(const Serializer& ser) const = 0;
|
||||
virtual bool Restore(Serializer& ser) = 0;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxTLWGeometryGeneric: simplest possible generic implementation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// names for various persistent options
|
||||
#define wxPERSIST_TLW_X "x"
|
||||
#define wxPERSIST_TLW_Y "y"
|
||||
#define wxPERSIST_TLW_W "w"
|
||||
#define wxPERSIST_TLW_H "h"
|
||||
|
||||
#define wxPERSIST_TLW_MAXIMIZED "Maximized"
|
||||
#define wxPERSIST_TLW_ICONIZED "Iconized"
|
||||
|
||||
// MSW has its own native implementation and doesn't use this class.
|
||||
#ifndef __WXMSW__
|
||||
|
||||
class wxTLWGeometryGeneric : public wxTLWGeometryBase
|
||||
{
|
||||
public:
|
||||
wxTLWGeometryGeneric()
|
||||
{
|
||||
m_hasPos =
|
||||
m_hasSize =
|
||||
m_iconized =
|
||||
m_maximized = false;
|
||||
}
|
||||
|
||||
virtual bool Save(const Serializer& ser) const wxOVERRIDE
|
||||
{
|
||||
if ( !ser.SaveField(wxPERSIST_TLW_X, m_rectScreen.x) ||
|
||||
!ser.SaveField(wxPERSIST_TLW_Y, m_rectScreen.y) )
|
||||
return false;
|
||||
|
||||
if ( !ser.SaveField(wxPERSIST_TLW_W, m_rectScreen.width) ||
|
||||
!ser.SaveField(wxPERSIST_TLW_H, m_rectScreen.height) )
|
||||
return false;
|
||||
|
||||
if ( !ser.SaveField(wxPERSIST_TLW_MAXIMIZED, m_maximized) )
|
||||
return false;
|
||||
|
||||
if ( !ser.SaveField(wxPERSIST_TLW_ICONIZED, m_iconized) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool Restore(Serializer& ser) wxOVERRIDE
|
||||
{
|
||||
m_hasPos = ser.RestoreField(wxPERSIST_TLW_X, &m_rectScreen.x) &&
|
||||
ser.RestoreField(wxPERSIST_TLW_Y, &m_rectScreen.y);
|
||||
|
||||
m_hasSize = ser.RestoreField(wxPERSIST_TLW_W, &m_rectScreen.width) &&
|
||||
ser.RestoreField(wxPERSIST_TLW_H, &m_rectScreen.height);
|
||||
|
||||
int tmp;
|
||||
if ( ser.RestoreField(wxPERSIST_TLW_MAXIMIZED, &tmp) )
|
||||
m_maximized = tmp != 0;
|
||||
|
||||
if ( ser.RestoreField(wxPERSIST_TLW_ICONIZED, &tmp) )
|
||||
m_iconized = tmp != 0;
|
||||
|
||||
// If we restored at least something, return true.
|
||||
return m_hasPos || m_hasSize || m_maximized || m_iconized;
|
||||
}
|
||||
|
||||
virtual bool GetFrom(const wxTopLevelWindow* tlw) wxOVERRIDE
|
||||
{
|
||||
m_rectScreen = tlw->GetScreenRect();
|
||||
m_hasPos =
|
||||
m_hasSize = true;
|
||||
m_iconized = tlw->IsIconized();
|
||||
m_maximized = tlw->IsMaximized();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool ApplyTo(wxTopLevelWindow* tlw) wxOVERRIDE
|
||||
{
|
||||
if ( m_hasPos )
|
||||
{
|
||||
// to avoid making the window completely invisible if it had been
|
||||
// shown on a monitor which was disconnected since the last run
|
||||
// (this is pretty common for notebook with external displays)
|
||||
//
|
||||
// NB: we should allow window position to be (slightly) off screen,
|
||||
// it's not uncommon to position the window so that its upper
|
||||
// left corner has slightly negative coordinate
|
||||
if ( wxDisplay::GetFromPoint(m_rectScreen.GetTopLeft()) != wxNOT_FOUND ||
|
||||
(m_hasSize &&
|
||||
wxDisplay::GetFromPoint(m_rectScreen.GetBottomRight()) != wxNOT_FOUND) )
|
||||
{
|
||||
tlw->Move(m_rectScreen.GetTopLeft(), wxSIZE_ALLOW_MINUS_ONE);
|
||||
}
|
||||
//else: should we try to adjust position/size somehow?
|
||||
}
|
||||
|
||||
if ( m_hasSize )
|
||||
{
|
||||
// a previous version of the program could have saved the window
|
||||
// size which used to be big enough, but which is not big enough
|
||||
// any more for the new version, so check that the size we restore
|
||||
// doesn't cut off parts of the window
|
||||
wxSize size = m_rectScreen.GetSize();
|
||||
size.IncTo(tlw->GetBestSize());
|
||||
tlw->SetSize(size);
|
||||
}
|
||||
|
||||
// note that the window can be both maximized and iconized
|
||||
if ( m_maximized )
|
||||
tlw->Maximize();
|
||||
|
||||
if ( m_iconized )
|
||||
tlw->Iconize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
wxRect m_rectScreen;
|
||||
bool m_hasPos;
|
||||
bool m_hasSize;
|
||||
bool m_iconized;
|
||||
bool m_maximized;
|
||||
};
|
||||
|
||||
#endif // !__WXMSW__
|
||||
|
||||
#ifdef __WXGTK20__
|
||||
#include "wx/gtk/private/tlwgeom.h"
|
||||
#elif defined(__WXMSW__)
|
||||
#include "wx/msw/private/tlwgeom.h"
|
||||
#else
|
||||
class wxTLWGeometry : public wxTLWGeometryGeneric
|
||||
{
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // _WX_PRIVATE_TLWGEOM_H_
|
@@ -24,8 +24,6 @@
|
||||
// the default names for various classes
|
||||
extern WXDLLIMPEXP_DATA_CORE(const char) wxFrameNameStr[];
|
||||
|
||||
class WXDLLIMPEXP_FWD_CORE wxTopLevelWindowBase;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// constants
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -240,6 +238,35 @@ public:
|
||||
wxWindow *SetTmpDefaultItem(wxWindow *win)
|
||||
{ wxWindow *old = GetDefaultItem(); m_winTmpDefault = win; return old; }
|
||||
|
||||
|
||||
// Class for saving/restoring fields describing the window geometry.
|
||||
//
|
||||
// This class is used by the functions below to allow saving the geometry
|
||||
// of the window and restoring it later. The components describing geometry
|
||||
// are platform-dependent, so there is no struct containing them and
|
||||
// instead the methods of this class are used to save or [try to] restore
|
||||
// whichever components are used under the current platform.
|
||||
class GeometrySerializer
|
||||
{
|
||||
public:
|
||||
virtual ~GeometrySerializer() {}
|
||||
|
||||
// If saving a field returns false, it's fatal error and SaveGeometry()
|
||||
// will return false.
|
||||
virtual bool SaveField(const wxString& name, int value) const = 0;
|
||||
|
||||
// If restoring a field returns false, it just means that the field is
|
||||
// not present and RestoreToGeometry() still continues with restoring
|
||||
// the other values.
|
||||
virtual bool RestoreField(const wxString& name, int* value) = 0;
|
||||
};
|
||||
|
||||
// Save the current window geometry using the provided serializer and
|
||||
// restore the window to the previously saved geometry.
|
||||
bool SaveGeometry(const GeometrySerializer& ser) const;
|
||||
bool RestoreToGeometry(GeometrySerializer& ser);
|
||||
|
||||
|
||||
// implementation only from now on
|
||||
// -------------------------------
|
||||
|
||||
|
@@ -350,6 +350,94 @@ public:
|
||||
*/
|
||||
void Restore();
|
||||
|
||||
/**
|
||||
Class used with SaveGeometry() and RestoreToGeometry().
|
||||
|
||||
This is an abstract base class, i.e. to use it you must define a
|
||||
derived class implementing the pure virtual SaveField() and
|
||||
RestoreField() methods.
|
||||
|
||||
For example, if you wished to store the window geometry in a database,
|
||||
you could derive a class saving fields such as "width" or "height" in a
|
||||
table in this database and restoring them from it later.
|
||||
|
||||
@since 3.1.2
|
||||
*/
|
||||
class GeometrySerializer
|
||||
{
|
||||
/**
|
||||
Save a single field with the given value.
|
||||
|
||||
Note that if this function returns @false, SaveGeometry() supposes
|
||||
that saving the geometry failed and returns @false itself, without
|
||||
even trying to save anything else.
|
||||
|
||||
@param name uniquely identifies the field but is otherwise
|
||||
arbitrary.
|
||||
@param value value of the field (can be positive or negative, i.e.
|
||||
it can't be assumed that a value like -1 is invalid).
|
||||
|
||||
@return @true if the field was saved or @false if saving it failed,
|
||||
resulting in wxTopLevelWindow::SaveGeometry() failure.
|
||||
*/
|
||||
virtual bool SaveField(const wxString& name, int value) const = 0;
|
||||
|
||||
/**
|
||||
Try to restore a single field.
|
||||
|
||||
Unlike for SaveField(), returning @false from this function may
|
||||
indicate that the value simply wasn't present and doesn't prevent
|
||||
RestoreToGeometry() from continuing with trying to restore the
|
||||
other values.
|
||||
|
||||
@param name uniquely identifies the field
|
||||
@param value non-@NULL pointer to the value to be filled by this
|
||||
function
|
||||
|
||||
@return @true if the value was retrieved or @false if it wasn't
|
||||
found or an error occurred.
|
||||
*/
|
||||
virtual bool RestoreField(const wxString& name, int* value) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
Restores the window to the previously saved geometry.
|
||||
|
||||
This is a companion function to SaveGeometry() and can be called later
|
||||
to restore the window to the geometry it had when it was saved.
|
||||
|
||||
@param ser An object implementing GeometrySerializer virtual methods.
|
||||
|
||||
@return @true if any (and, usually, but not necessarily, all) of the
|
||||
window geometry attributes were restored or @false if there was no
|
||||
saved geometry information at all or restoring it failed.
|
||||
|
||||
@since 3.1.2
|
||||
*/
|
||||
bool RestoreToGeometry(GeometrySerializer& ser);
|
||||
|
||||
/**
|
||||
Save the current window geometry to allow restoring it later.
|
||||
|
||||
After calling this function, window geometry is saved in the provided
|
||||
serializer and calling RestoreToGeometry() with the same serializer
|
||||
later (i.e. usually during a subsequent program execution) would
|
||||
restore the window to the same position, size, maximized/minimized
|
||||
state etc.
|
||||
|
||||
This function is used by wxPersistentTLW, so it is not necessary to use
|
||||
it if the goal is to just save and restore window geometry in the
|
||||
simplest possible way. However is more flexibility is required, it can
|
||||
be also used directly with a custom serializer object.
|
||||
|
||||
@param ser An object implementing GeometrySerializer virtual methods.
|
||||
|
||||
@return @true if the geometry was saved, @false if doing it failed
|
||||
|
||||
@since 3.1.2
|
||||
*/
|
||||
bool SaveGeometry(const GeometrySerializer& ser) const;
|
||||
|
||||
/**
|
||||
Changes the default item for the panel, usually @a win is a button.
|
||||
|
||||
|
@@ -31,6 +31,8 @@
|
||||
|
||||
#include "wx/display.h"
|
||||
|
||||
#include "wx/private/tlwgeom.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// event table
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -310,6 +312,28 @@ void wxTopLevelWindowBase::DoCentre(int dir)
|
||||
SetSize(rect, wxSIZE_ALLOW_MINUS_ONE);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Saving/restoring geometry
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool wxTopLevelWindowBase::SaveGeometry(const GeometrySerializer& ser) const
|
||||
{
|
||||
wxTLWGeometry geom;
|
||||
if ( !geom.GetFrom(static_cast<const wxTopLevelWindow*>(this)) )
|
||||
return false;
|
||||
|
||||
return geom.Save(ser);
|
||||
}
|
||||
|
||||
bool wxTopLevelWindowBase::RestoreToGeometry(GeometrySerializer& ser)
|
||||
{
|
||||
wxTLWGeometry geom;
|
||||
if ( !geom.Restore(ser) )
|
||||
return false;
|
||||
|
||||
return geom.ApplyTo(static_cast<wxTopLevelWindow*>(this));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxTopLevelWindow size management: we exclude the areas taken by
|
||||
// menu/status/toolbars from the client area, so the client area is what's
|
||||
|
@@ -101,6 +101,59 @@ TEST_CASE_METHOD(PersistenceTests, "wxPersistTLW", "[persist][tlw]")
|
||||
CHECK(!frame->IsMaximized());
|
||||
CHECK(!frame->IsIconized());
|
||||
|
||||
// Next try that restoring a minimized frame works correctly: for
|
||||
// Iconize() to have effect, we must show the frame first.
|
||||
frame->Iconize();
|
||||
frame->Show();
|
||||
|
||||
delete frame;
|
||||
}
|
||||
|
||||
// Check geometry after restoring the minimized frame.
|
||||
{
|
||||
wxFrame* const frame = CreatePersistenceTestFrame();
|
||||
|
||||
CHECK(wxPersistenceManager::Get().RegisterAndRestore(frame));
|
||||
|
||||
CHECK(!frame->IsMaximized());
|
||||
CHECK(frame->IsIconized());
|
||||
|
||||
frame->Restore();
|
||||
|
||||
CHECK(pos.x == frame->GetPosition().x);
|
||||
CHECK(pos.y == frame->GetPosition().y);
|
||||
CHECK(size.x == frame->GetSize().GetWidth());
|
||||
CHECK(size.y == frame->GetSize().GetHeight());
|
||||
|
||||
// Next try that restoring a maximized frame works correctly: again,
|
||||
// for it to be really maximized, it must be shown.
|
||||
frame->Maximize();
|
||||
frame->Show();
|
||||
|
||||
delete frame;
|
||||
}
|
||||
|
||||
// Check geometry after restoring the maximized frame.
|
||||
//
|
||||
// This test currently fails under non-MSW platforms as they only save the
|
||||
// maximized frame size, and its normal size is lost and can't be restored.
|
||||
#ifdef __WXMSW__
|
||||
{
|
||||
wxFrame* const frame = CreatePersistenceTestFrame();
|
||||
|
||||
CHECK(wxPersistenceManager::Get().RegisterAndRestore(frame));
|
||||
|
||||
CHECK(frame->IsMaximized());
|
||||
CHECK(!frame->IsIconized());
|
||||
|
||||
frame->Restore();
|
||||
|
||||
CHECK(pos.x == frame->GetPosition().x);
|
||||
CHECK(pos.y == frame->GetPosition().y);
|
||||
CHECK(size.x == frame->GetSize().GetWidth());
|
||||
CHECK(size.y == frame->GetSize().GetHeight());
|
||||
|
||||
delete frame;
|
||||
}
|
||||
#endif // __WXMSW__
|
||||
}
|
||||
|
Reference in New Issue
Block a user