- Allow associating a validator with wxGridCellTextEditor (derEine).
- Add more convenient wxFont(wxFontInfo) ctor.
- Pass menu events to the handler in the associated wxMenuBar.
+- Add wxWindow::BeginRepositioningChildren() and EndRepositioningChildren().
wxGTK:
virtual void Raise();
virtual void Lower();
+ virtual bool BeginRepositioningChildren();
+ virtual void EndRepositioningChildren();
+
virtual bool Show(bool show = true);
virtual bool ShowWithEffect(wxShowEffect effect,
unsigned timeout = 0)
// this is the same as SendSizeEventToParent() but using PostSizeEvent()
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
// ------------
*/
//@{
+ /**
+ 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.
return HandleWindowEvent(event);
}
-bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
+bool wxWindowMSW::BeginRepositioningChildren()
{
#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;
for ( HWND child = ::GetWindow(GetHwndOf(this), GW_CHILD);
child;
numChildren ++;
}
+ // Nothing is gained by deferring the repositioning of a single child.
+ if ( numChildren < 2 )
+ return false;
+
// Protect against valid m_hDWP being overwritten
- bool useDefer = false;
+ if ( m_hDWP )
+ return false;
- if ( numChildren > 1 )
+ m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren);
+ if ( !m_hDWP )
{
- if (!m_hDWP)
- {
- m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren);
- if ( !m_hDWP )
- {
- wxLogLastError(wxT("BeginDeferWindowPos"));
- }
- if (m_hDWP)
- useDefer = true;
- }
+ wxLogLastError(wxT("BeginDeferWindowPos"));
+ return false;
}
+
+ // Return true to indicate that EndDeferWindowPos() should be called.
+ return true;
#endif // wxUSE_DEFERRED_SIZING
+}
+
+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
+}
+
+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
bool processed = false;
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;
}