Add wxWindow::BeginRepositioningChildren() and EndRepositioningChildren().
This is just a refactoring of wxMSW code to make it possible to use deferred window positioning from other places in subsequent commits. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74066 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -666,6 +666,7 @@ All (GUI):
|
|||||||
- Allow associating a validator with wxGridCellTextEditor (derEine).
|
- Allow associating a validator with wxGridCellTextEditor (derEine).
|
||||||
- Add more convenient wxFont(wxFontInfo) ctor.
|
- Add more convenient wxFont(wxFontInfo) ctor.
|
||||||
- Pass menu events to the handler in the associated wxMenuBar.
|
- Pass menu events to the handler in the associated wxMenuBar.
|
||||||
|
- Add wxWindow::BeginRepositioningChildren() and EndRepositioningChildren().
|
||||||
|
|
||||||
wxGTK:
|
wxGTK:
|
||||||
|
|
||||||
|
@@ -67,6 +67,9 @@ public:
|
|||||||
virtual void Raise();
|
virtual void Raise();
|
||||||
virtual void Lower();
|
virtual void Lower();
|
||||||
|
|
||||||
|
virtual bool BeginRepositioningChildren();
|
||||||
|
virtual void EndRepositioningChildren();
|
||||||
|
|
||||||
virtual bool Show(bool show = true);
|
virtual bool Show(bool show = true);
|
||||||
virtual bool ShowWithEffect(wxShowEffect effect,
|
virtual bool ShowWithEffect(wxShowEffect effect,
|
||||||
unsigned timeout = 0)
|
unsigned timeout = 0)
|
||||||
|
@@ -555,6 +555,43 @@ public:
|
|||||||
// this is the same as SendSizeEventToParent() but using PostSizeEvent()
|
// this is the same as SendSizeEventToParent() but using PostSizeEvent()
|
||||||
void PostSizeEventToParent() { SendSizeEventToParent(wxSEND_EVENT_POST); }
|
void PostSizeEventToParent() { SendSizeEventToParent(wxSEND_EVENT_POST); }
|
||||||
|
|
||||||
|
// These functions should be used before repositioning the children of
|
||||||
|
// this window to reduce flicker or, in MSW case, even avoid display
|
||||||
|
// corruption in some situations (so they're more than just optimization).
|
||||||
|
//
|
||||||
|
// EndRepositioningChildren() should be called if and only if
|
||||||
|
// BeginRepositioningChildren() returns true. To ensure that this is always
|
||||||
|
// done automatically, use ChildrenRepositioningGuard class below.
|
||||||
|
virtual bool BeginRepositioningChildren() { return false; }
|
||||||
|
virtual void EndRepositioningChildren() { }
|
||||||
|
|
||||||
|
// A simple helper which ensures that EndRepositioningChildren() is called
|
||||||
|
// from its dtor if and only if calling BeginRepositioningChildren() from
|
||||||
|
// the ctor returned true.
|
||||||
|
class ChildrenRepositioningGuard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Notice that window can be NULL here, for convenience. In this case
|
||||||
|
// this class simply doesn't do anything.
|
||||||
|
wxEXPLICIT ChildrenRepositioningGuard(wxWindowBase* win)
|
||||||
|
: m_win(win),
|
||||||
|
m_callEnd(win && win->BeginRepositioningChildren())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~ChildrenRepositioningGuard()
|
||||||
|
{
|
||||||
|
if ( m_callEnd )
|
||||||
|
m_win->EndRepositioningChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
wxWindowBase* const m_win;
|
||||||
|
const bool m_callEnd;
|
||||||
|
|
||||||
|
wxDECLARE_NO_COPY_CLASS(ChildrenRepositioningGuard);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// window state
|
// window state
|
||||||
// ------------
|
// ------------
|
||||||
|
@@ -766,6 +766,70 @@ public:
|
|||||||
*/
|
*/
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
|
/**
|
||||||
|
Helper for ensuring EndRepositioningChildren() is called correctly.
|
||||||
|
|
||||||
|
This class wraps the calls to BeginRepositioningChildren() and
|
||||||
|
EndRepositioningChildren() by performing the former in its constructor
|
||||||
|
and the latter in its destructor if, and only if, the first call
|
||||||
|
returned @true. This is the simplest way to call these methods and if
|
||||||
|
this class is created as a local variable, it also ensures that
|
||||||
|
EndRepositioningChildren() is correctly called (or not) on scope exit,
|
||||||
|
so its use instead of calling these methods manually is highly
|
||||||
|
recommended.
|
||||||
|
|
||||||
|
@since 2.9.5
|
||||||
|
*/
|
||||||
|
class ChildrenRepositioningGuard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
Constructor calls wxWindow::BeginRepositioningChildren().
|
||||||
|
|
||||||
|
@param win The window to call BeginRepositioningChildren() on. If
|
||||||
|
it is @NULL, nothing is done.
|
||||||
|
*/
|
||||||
|
explicit ChildrenRepositioningGuard(wxWindow* win);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Destructor calls wxWindow::EndRepositioningChildren() if necessary.
|
||||||
|
|
||||||
|
EndRepositioningChildren() is called only if a valid window was
|
||||||
|
passed to the constructor and if BeginRepositioningChildren()
|
||||||
|
returned @true.
|
||||||
|
*/
|
||||||
|
~ChildrenRepositioningGuard();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Prepare for changing positions of multiple child windows.
|
||||||
|
|
||||||
|
This method should be called before changing positions of multiple
|
||||||
|
child windows to reduce flicker and, in MSW case, even avoid display
|
||||||
|
corruption in some cases. It is used internally by wxWidgets and called
|
||||||
|
automatically when the window size changes but it can also be useful to
|
||||||
|
call it from outside of the library if a repositioning involving
|
||||||
|
multiple children is done without changing the window size.
|
||||||
|
|
||||||
|
If this method returns @true, then EndRepositioningChildren() must be
|
||||||
|
called after setting all children positions. Use
|
||||||
|
ChildrenRepositioningGuard class to ensure that this requirement is
|
||||||
|
satisfied.
|
||||||
|
|
||||||
|
@since 2.9.5
|
||||||
|
*/
|
||||||
|
bool BeginRepositioningChildren();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Fix child window positions after setting all of them at once.
|
||||||
|
|
||||||
|
This method must be called if and only if the previous call to
|
||||||
|
BeginRepositioningChildren() returned @true.
|
||||||
|
|
||||||
|
@since 2.9.5
|
||||||
|
*/
|
||||||
|
void EndRepositioningChildren();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Sets the cached best size value.
|
Sets the cached best size value.
|
||||||
|
|
||||||
|
@@ -5109,11 +5109,9 @@ bool wxWindowMSW::HandleExitSizeMove()
|
|||||||
return HandleWindowEvent(event);
|
return HandleWindowEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
|
bool wxWindowMSW::BeginRepositioningChildren()
|
||||||
{
|
{
|
||||||
#if wxUSE_DEFERRED_SIZING
|
#if wxUSE_DEFERRED_SIZING
|
||||||
// when we resize this window, its children are probably going to be
|
|
||||||
// repositioned as well, prepare to use DeferWindowPos() for them
|
|
||||||
int numChildren = 0;
|
int numChildren = 0;
|
||||||
for ( HWND child = ::GetWindow(GetHwndOf(this), GW_CHILD);
|
for ( HWND child = ::GetWindow(GetHwndOf(this), GW_CHILD);
|
||||||
child;
|
child;
|
||||||
@@ -5122,23 +5120,60 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
|
|||||||
numChildren ++;
|
numChildren ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Protect against valid m_hDWP being overwritten
|
// Nothing is gained by deferring the repositioning of a single child.
|
||||||
bool useDefer = false;
|
if ( numChildren < 2 )
|
||||||
|
return false;
|
||||||
|
|
||||||
if ( numChildren > 1 )
|
// Protect against valid m_hDWP being overwritten
|
||||||
|
if ( m_hDWP )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren);
|
||||||
|
if ( !m_hDWP )
|
||||||
{
|
{
|
||||||
if (!m_hDWP)
|
wxLogLastError(wxT("BeginDeferWindowPos"));
|
||||||
{
|
return false;
|
||||||
m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren);
|
}
|
||||||
if ( !m_hDWP )
|
|
||||||
{
|
// Return true to indicate that EndDeferWindowPos() should be called.
|
||||||
wxLogLastError(wxT("BeginDeferWindowPos"));
|
return true;
|
||||||
}
|
#endif // wxUSE_DEFERRED_SIZING
|
||||||
if (m_hDWP)
|
}
|
||||||
useDefer = true;
|
|
||||||
}
|
void wxWindowMSW::EndRepositioningChildren()
|
||||||
|
{
|
||||||
|
#if wxUSE_DEFERRED_SIZING
|
||||||
|
wxASSERT_MSG( m_hDWP, wxS("Shouldn't be called") );
|
||||||
|
|
||||||
|
// reset m_hDWP to NULL so that child windows don't try to use our
|
||||||
|
// m_hDWP after we call EndDeferWindowPos() on it (this shouldn't
|
||||||
|
// happen anyhow normally but who knows what weird flow of control we
|
||||||
|
// may have depending on what the users EVT_SIZE handler does...)
|
||||||
|
HDWP hDWP = (HDWP)m_hDWP;
|
||||||
|
m_hDWP = NULL;
|
||||||
|
|
||||||
|
// do put all child controls in place at once
|
||||||
|
if ( !::EndDeferWindowPos(hDWP) )
|
||||||
|
{
|
||||||
|
wxLogLastError(wxT("EndDeferWindowPos"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset our children's pending pos/size values.
|
||||||
|
for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
|
||||||
|
node;
|
||||||
|
node = node->GetNext() )
|
||||||
|
{
|
||||||
|
wxWindowMSW * const child = node->GetData();
|
||||||
|
child->MSWEndDeferWindowPos();
|
||||||
}
|
}
|
||||||
#endif // wxUSE_DEFERRED_SIZING
|
#endif // wxUSE_DEFERRED_SIZING
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
|
||||||
|
{
|
||||||
|
// when we resize this window, its children are probably going to be
|
||||||
|
// repositioned as well, prepare to use DeferWindowPos() for them
|
||||||
|
ChildrenRepositioningGuard repositionGuard(this);
|
||||||
|
|
||||||
// update this window size
|
// update this window size
|
||||||
bool processed = false;
|
bool processed = false;
|
||||||
@@ -5171,34 +5206,6 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
|
|||||||
processed = HandleWindowEvent(event);
|
processed = HandleWindowEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if wxUSE_DEFERRED_SIZING
|
|
||||||
// and finally change the positions of all child windows at once
|
|
||||||
if ( useDefer && m_hDWP )
|
|
||||||
{
|
|
||||||
// reset m_hDWP to NULL so that child windows don't try to use our
|
|
||||||
// m_hDWP after we call EndDeferWindowPos() on it (this shouldn't
|
|
||||||
// happen anyhow normally but who knows what weird flow of control we
|
|
||||||
// may have depending on what the users EVT_SIZE handler does...)
|
|
||||||
HDWP hDWP = (HDWP)m_hDWP;
|
|
||||||
m_hDWP = NULL;
|
|
||||||
|
|
||||||
// do put all child controls in place at once
|
|
||||||
if ( !::EndDeferWindowPos(hDWP) )
|
|
||||||
{
|
|
||||||
wxLogLastError(wxT("EndDeferWindowPos"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset our children's pending pos/size values.
|
|
||||||
for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
|
|
||||||
node;
|
|
||||||
node = node->GetNext() )
|
|
||||||
{
|
|
||||||
wxWindowMSW * const child = node->GetData();
|
|
||||||
child->MSWEndDeferWindowPos();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // wxUSE_DEFERRED_SIZING
|
|
||||||
|
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user