+ constr->top.SetDone(true);
+ }
+ }
+}
+
+void wxWindowBase::GetSizeConstraint(int *w, int *h) const
+{
+ wxLayoutConstraints *constr = GetConstraints();
+ if ( constr )
+ {
+ *w = constr->width.GetValue();
+ *h = constr->height.GetValue();
+ }
+ else
+ GetSize(w, h);
+}
+
+void wxWindowBase::GetClientSizeConstraint(int *w, int *h) const
+{
+ wxLayoutConstraints *constr = GetConstraints();
+ if ( constr )
+ {
+ *w = constr->width.GetValue();
+ *h = constr->height.GetValue();
+ }
+ else
+ GetClientSize(w, h);
+}
+
+void wxWindowBase::GetPositionConstraint(int *x, int *y) const
+{
+ wxLayoutConstraints *constr = GetConstraints();
+ if ( constr )
+ {
+ *x = constr->left.GetValue();
+ *y = constr->top.GetValue();
+ }
+ else
+ GetPosition(x, y);
+}
+
+#endif // wxUSE_CONSTRAINTS
+
+void wxWindowBase::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) const
+{
+ // don't do it for the dialogs/frames - they float independently of their
+ // parent
+ if ( !IsTopLevel() )
+ {
+ wxWindow *parent = GetParent();
+ if ( !(sizeFlags & wxSIZE_NO_ADJUSTMENTS) && parent )
+ {
+ wxPoint pt(parent->GetClientAreaOrigin());
+ x += pt.x;
+ y += pt.y;
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Update UI processing
+// ----------------------------------------------------------------------------
+
+void wxWindowBase::UpdateWindowUI(long flags)
+{
+ wxUpdateUIEvent event(GetId());
+ event.SetEventObject(this);
+
+ if ( GetEventHandler()->ProcessEvent(event) )
+ {
+ DoUpdateWindowUI(event);
+ }
+
+ if (flags & wxUPDATE_UI_RECURSE)
+ {
+ wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+ while (node)
+ {
+ wxWindow* child = (wxWindow*) node->GetData();
+ child->UpdateWindowUI(flags);
+ node = node->GetNext();
+ }
+ }
+}
+
+// do the window-specific processing after processing the update event
+void wxWindowBase::DoUpdateWindowUI(wxUpdateUIEvent& event)
+{
+ if ( event.GetSetEnabled() )
+ Enable(event.GetEnabled());
+
+ if ( event.GetSetShown() )
+ Show(event.GetShown());
+}
+
+// ----------------------------------------------------------------------------
+// Idle processing
+// ----------------------------------------------------------------------------
+
+// Send idle event to window and all subwindows
+bool wxWindowBase::SendIdleEvents(wxIdleEvent& event)
+{
+ bool needMore = false;
+
+ OnInternalIdle();
+
+ // should we send idle event to this window?
+ if (wxIdleEvent::GetMode() == wxIDLE_PROCESS_ALL ||
+ HasExtraStyle(wxWS_EX_PROCESS_IDLE))
+ {
+ event.SetEventObject(this);
+ HandleWindowEvent(event);
+
+ if (event.MoreRequested())
+ needMore = true;
+ }
+ wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+ for (; node; node = node->GetNext())
+ {
+ wxWindow* child = node->GetData();
+ if (child->SendIdleEvents(event))
+ needMore = true;
+ }
+
+ return needMore;
+}
+
+void wxWindowBase::OnInternalIdle()
+{
+ if ( wxUpdateUIEvent::CanUpdate(this) )
+ UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
+}
+
+// ----------------------------------------------------------------------------
+// dialog units translations
+// ----------------------------------------------------------------------------
+
+// Windows' computes dialog units using average character width over upper-
+// and lower-case ASCII alphabet and not using the average character width
+// metadata stored in the font; see
+// http://support.microsoft.com/default.aspx/kb/145994 for detailed discussion.
+// It's important that we perform the conversion in identical way, because
+// dialog units natively exist only on Windows and Windows HIG is expressed
+// using them.
+wxSize wxWindowBase::GetDlgUnitBase() const
+{
+ const wxWindowBase * const parent = wxGetTopLevelParent((wxWindow*)this);
+
+ if ( !parent->m_font.IsOk() )
+ {
+ // Default GUI font is used. This is the most common case, so
+ // cache the results.
+ static wxSize s_defFontSize;
+ if ( s_defFontSize.x == 0 )
+ s_defFontSize = wxPrivate::GetAverageASCIILetterSize(*parent);
+ return s_defFontSize;
+ }
+ else
+ {
+ // Custom font, we always need to compute the result
+ return wxPrivate::GetAverageASCIILetterSize(*parent);
+ }
+}
+
+wxPoint wxWindowBase::ConvertPixelsToDialog(const wxPoint& pt) const
+{
+ const wxSize base = GetDlgUnitBase();
+
+ // NB: wxMulDivInt32() is used, because it correctly rounds the result
+
+ wxPoint pt2 = wxDefaultPosition;
+ if (pt.x != wxDefaultCoord)
+ pt2.x = wxMulDivInt32(pt.x, 4, base.x);
+ if (pt.y != wxDefaultCoord)
+ pt2.y = wxMulDivInt32(pt.y, 8, base.y);
+
+ return pt2;
+}
+
+wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt) const
+{
+ const wxSize base = GetDlgUnitBase();
+
+ wxPoint pt2 = wxDefaultPosition;
+ if (pt.x != wxDefaultCoord)
+ pt2.x = wxMulDivInt32(pt.x, base.x, 4);
+ if (pt.y != wxDefaultCoord)
+ pt2.y = wxMulDivInt32(pt.y, base.y, 8);
+
+ return pt2;
+}
+
+// ----------------------------------------------------------------------------
+// event handlers
+// ----------------------------------------------------------------------------
+
+// propagate the colour change event to the subwindows
+void wxWindowBase::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
+{
+ wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+ while ( node )
+ {
+ // Only propagate to non-top-level windows
+ wxWindow *win = node->GetData();
+ if ( !win->IsTopLevel() )
+ {
+ wxSysColourChangedEvent event2;
+ event2.SetEventObject(win);
+ win->GetEventHandler()->ProcessEvent(event2);
+ }
+
+ node = node->GetNext();
+ }
+
+ Refresh();
+}
+
+// the default action is to populate dialog with data when it's created,
+// and nudge the UI into displaying itself correctly in case
+// we've turned the wxUpdateUIEvents frequency down low.
+void wxWindowBase::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) )
+{
+ TransferDataToWindow();
+
+ // Update the UI at this point
+ UpdateWindowUI(wxUPDATE_UI_RECURSE);
+}
+
+// ----------------------------------------------------------------------------
+// menu-related functions
+// ----------------------------------------------------------------------------
+
+#if wxUSE_MENUS
+
+bool wxWindowBase::PopupMenu(wxMenu *menu, int x, int y)
+{
+ wxCHECK_MSG( menu, false, "can't popup NULL menu" );
+
+ wxMenuInvokingWindowSetter
+ setInvokingWin(*menu, static_cast<wxWindow *>(this));
+
+ wxCurrentPopupMenu = menu;
+ const bool rc = DoPopupMenu(menu, x, y);
+ wxCurrentPopupMenu = NULL;
+
+ return rc;
+}
+
+// this is used to pass the id of the selected item from the menu event handler
+// to the main function itself
+//
+// it's ok to use a global here as there can be at most one popup menu shown at
+// any time
+static int gs_popupMenuSelection = wxID_NONE;
+
+void wxWindowBase::InternalOnPopupMenu(wxCommandEvent& event)
+{
+ // store the id in a global variable where we'll retrieve it from later
+ gs_popupMenuSelection = event.GetId();
+}
+
+void wxWindowBase::InternalOnPopupMenuUpdate(wxUpdateUIEvent& WXUNUSED(event))
+{
+ // nothing to do but do not skip it
+}
+
+int
+wxWindowBase::DoGetPopupMenuSelectionFromUser(wxMenu& menu, int x, int y)
+{
+ gs_popupMenuSelection = wxID_NONE;
+
+ Connect(wxEVT_COMMAND_MENU_SELECTED,
+ wxCommandEventHandler(wxWindowBase::InternalOnPopupMenu),
+ NULL,
+ this);
+
+ // it is common to construct the menu passed to this function dynamically
+ // using some fixed range of ids which could clash with the ids used
+ // elsewhere in the program, which could result in some menu items being
+ // unintentionally disabled or otherwise modified by update UI handlers
+ // elsewhere in the program code and this is difficult to avoid in the
+ // program itself, so instead we just temporarily suspend UI updating while
+ // this menu is shown
+ Connect(wxEVT_UPDATE_UI,
+ wxUpdateUIEventHandler(wxWindowBase::InternalOnPopupMenuUpdate),
+ NULL,
+ this);
+
+ PopupMenu(&menu, x, y);
+
+ Disconnect(wxEVT_UPDATE_UI,
+ wxUpdateUIEventHandler(wxWindowBase::InternalOnPopupMenuUpdate),
+ NULL,
+ this);
+ Disconnect(wxEVT_COMMAND_MENU_SELECTED,
+ wxCommandEventHandler(wxWindowBase::InternalOnPopupMenu),
+ NULL,
+ this);
+
+ return gs_popupMenuSelection;
+}
+
+#endif // wxUSE_MENUS
+
+// methods for drawing the sizers in a visible way: this is currently only
+// enabled for "full debug" builds with wxDEBUG_LEVEL==2 as it doesn't work
+// that well and also because we don't want to leave it enabled in default
+// builds used for production
+#if wxDEBUG_LEVEL > 1
+
+static void DrawSizers(wxWindowBase *win);
+
+static void DrawBorder(wxWindowBase *win, const wxRect& rect, bool fill, const wxPen* pen)
+{
+ wxClientDC dc((wxWindow *)win);
+ dc.SetPen(*pen);
+ dc.SetBrush(fill ? wxBrush(pen->GetColour(), wxBRUSHSTYLE_CROSSDIAG_HATCH) :
+ *wxTRANSPARENT_BRUSH);
+ dc.DrawRectangle(rect.Deflate(1, 1));
+}
+
+static void DrawSizer(wxWindowBase *win, wxSizer *sizer)
+{
+ const wxSizerItemList& items = sizer->GetChildren();
+ for ( wxSizerItemList::const_iterator i = items.begin(),
+ end = items.end();
+ i != end;
+ ++i )
+ {
+ wxSizerItem *item = *i;
+ if ( item->IsSizer() )
+ {
+ DrawBorder(win, item->GetRect().Deflate(2), false, wxRED_PEN);
+ DrawSizer(win, item->GetSizer());
+ }
+ else if ( item->IsSpacer() )
+ {
+ DrawBorder(win, item->GetRect().Deflate(2), true, wxBLUE_PEN);
+ }
+ else if ( item->IsWindow() )
+ {
+ DrawSizers(item->GetWindow());
+ }
+ else
+ wxFAIL_MSG("inconsistent wxSizerItem status!");
+ }
+}
+
+static void DrawSizers(wxWindowBase *win)
+{
+ DrawBorder(win, win->GetClientSize(), false, wxGREEN_PEN);
+
+ wxSizer *sizer = win->GetSizer();
+ if ( sizer )
+ {
+ DrawSizer(win, sizer);
+ }
+ else // no sizer, still recurse into the children
+ {
+ const wxWindowList& children = win->GetChildren();
+ for ( wxWindowList::const_iterator i = children.begin(),
+ end = children.end();
+ i != end;
+ ++i )
+ {
+ DrawSizers(*i);
+ }
+
+ // show all kind of sizes of this window; see the "window sizing" topic
+ // overview for more info about the various differences:
+ wxSize fullSz = win->GetSize();
+ wxSize clientSz = win->GetClientSize();
+ wxSize bestSz = win->GetBestSize();
+ wxSize minSz = win->GetMinSize();
+ wxSize maxSz = win->GetMaxSize();
+ wxSize virtualSz = win->GetVirtualSize();
+
+ wxMessageOutputDebug dbgout;
+ dbgout.Printf(
+ "%-10s => fullsz=%4d;%-4d clientsz=%4d;%-4d bestsz=%4d;%-4d minsz=%4d;%-4d maxsz=%4d;%-4d virtualsz=%4d;%-4d\n",
+ win->GetName(),
+ fullSz.x, fullSz.y,
+ clientSz.x, clientSz.y,
+ bestSz.x, bestSz.y,
+ minSz.x, minSz.y,
+ maxSz.x, maxSz.y,
+ virtualSz.x, virtualSz.y);
+ }
+}
+
+#endif // wxDEBUG_LEVEL
+
+// process special middle clicks
+void wxWindowBase::OnMiddleClick( wxMouseEvent& event )
+{
+ if ( event.ControlDown() && event.AltDown() )
+ {
+#if wxDEBUG_LEVEL > 1
+ // Ctrl-Alt-Shift-mclick makes the sizers visible in debug builds
+ if ( event.ShiftDown() )
+ {
+ DrawSizers(this);
+ }
+ else
+#endif // __WXDEBUG__
+ {
+#if wxUSE_MSGDLG
+ // just Ctrl-Alt-middle click shows information about wx version
+ ::wxInfoMessageBox((wxWindow*)this);
+#endif // wxUSE_MSGDLG
+ }
+ }
+ else
+ {
+ event.Skip();
+ }
+}
+
+// ----------------------------------------------------------------------------
+// accessibility
+// ----------------------------------------------------------------------------
+
+#if wxUSE_ACCESSIBILITY
+void wxWindowBase::SetAccessible(wxAccessible* accessible)
+{
+ if (m_accessible && (accessible != m_accessible))
+ delete m_accessible;
+ m_accessible = accessible;
+ if (m_accessible)
+ m_accessible->SetWindow((wxWindow*) this);
+}
+
+// Returns the accessible object, creating if necessary.
+wxAccessible* wxWindowBase::GetOrCreateAccessible()
+{
+ if (!m_accessible)
+ m_accessible = CreateAccessible();
+ return m_accessible;
+}
+
+// Override to create a specific accessible object.
+wxAccessible* wxWindowBase::CreateAccessible()
+{
+ return new wxWindowAccessible((wxWindow*) this);
+}
+
+#endif
+
+// ----------------------------------------------------------------------------
+// list classes implementation
+// ----------------------------------------------------------------------------
+
+#if wxUSE_STD_CONTAINERS
+
+#include "wx/listimpl.cpp"
+WX_DEFINE_LIST(wxWindowList)
+
+#else // !wxUSE_STD_CONTAINERS
+
+void wxWindowListNode::DeleteData()
+{
+ delete (wxWindow *)GetData();
+}
+
+#endif // wxUSE_STD_CONTAINERS/!wxUSE_STD_CONTAINERS
+
+// ----------------------------------------------------------------------------
+// borders
+// ----------------------------------------------------------------------------
+
+wxBorder wxWindowBase::GetBorder(long flags) const
+{
+ wxBorder border = (wxBorder)(flags & wxBORDER_MASK);
+ if ( border == wxBORDER_DEFAULT )
+ {
+ border = GetDefaultBorder();
+ }
+ else if ( border == wxBORDER_THEME )
+ {
+ border = GetDefaultBorderForControl();
+ }
+
+ return border;
+}
+
+wxBorder wxWindowBase::GetDefaultBorder() const
+{
+ return wxBORDER_NONE;
+}
+
+// ----------------------------------------------------------------------------
+// hit testing
+// ----------------------------------------------------------------------------
+
+wxHitTest wxWindowBase::DoHitTest(wxCoord x, wxCoord y) const
+{
+ // here we just check if the point is inside the window or not
+
+ // check the top and left border first
+ bool outside = x < 0 || y < 0;
+ if ( !outside )
+ {
+ // check the right and bottom borders too
+ wxSize size = GetSize();
+ outside = x >= size.x || y >= size.y;
+ }
+
+ return outside ? wxHT_WINDOW_OUTSIDE : wxHT_WINDOW_INSIDE;
+}
+
+// ----------------------------------------------------------------------------
+// mouse capture
+// ----------------------------------------------------------------------------
+
+struct WXDLLEXPORT wxWindowNext
+{
+ wxWindow *win;
+ wxWindowNext *next;
+} *wxWindowBase::ms_winCaptureNext = NULL;
+wxWindow *wxWindowBase::ms_winCaptureCurrent = NULL;
+bool wxWindowBase::ms_winCaptureChanging = false;
+
+void wxWindowBase::CaptureMouse()
+{
+ wxLogTrace(wxT("mousecapture"), wxT("CaptureMouse(%p)"), static_cast<void*>(this));
+
+ wxASSERT_MSG( !ms_winCaptureChanging, wxT("recursive CaptureMouse call?") );
+
+ ms_winCaptureChanging = true;
+
+ wxWindow *winOld = GetCapture();
+ if ( winOld )
+ {
+ ((wxWindowBase*) winOld)->DoReleaseMouse();
+
+ // save it on stack
+ wxWindowNext *item = new wxWindowNext;
+ item->win = winOld;
+ item->next = ms_winCaptureNext;
+ ms_winCaptureNext = item;
+ }
+ //else: no mouse capture to save
+
+ DoCaptureMouse();
+ ms_winCaptureCurrent = (wxWindow*)this;
+
+ ms_winCaptureChanging = false;
+}
+
+void wxWindowBase::ReleaseMouse()
+{
+ wxLogTrace(wxT("mousecapture"), wxT("ReleaseMouse(%p)"), static_cast<void*>(this));
+
+ wxASSERT_MSG( !ms_winCaptureChanging, wxT("recursive ReleaseMouse call?") );
+
+ wxASSERT_MSG( GetCapture() == this,
+ "attempt to release mouse, but this window hasn't captured it" );
+ wxASSERT_MSG( ms_winCaptureCurrent == this,
+ "attempt to release mouse, but this window hasn't captured it" );
+
+ ms_winCaptureChanging = true;
+
+ DoReleaseMouse();
+ ms_winCaptureCurrent = NULL;
+
+ if ( ms_winCaptureNext )
+ {
+ ((wxWindowBase*)ms_winCaptureNext->win)->DoCaptureMouse();
+ ms_winCaptureCurrent = ms_winCaptureNext->win;
+
+ wxWindowNext *item = ms_winCaptureNext;
+ ms_winCaptureNext = item->next;
+ delete item;
+ }
+ //else: stack is empty, no previous capture
+
+ ms_winCaptureChanging = false;
+
+ wxLogTrace(wxT("mousecapture"),
+ (const wxChar *) wxT("After ReleaseMouse() mouse is captured by %p"),
+ static_cast<void*>(GetCapture()));
+}
+
+static void DoNotifyWindowAboutCaptureLost(wxWindow *win)
+{
+ wxMouseCaptureLostEvent event(win->GetId());
+ event.SetEventObject(win);
+ if ( !win->GetEventHandler()->ProcessEvent(event) )
+ {
+ // windows must handle this event, otherwise the app wouldn't behave
+ // correctly if it loses capture unexpectedly; see the discussion here:
+ // http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863
+ // http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/82376
+ wxFAIL_MSG( wxT("window that captured the mouse didn't process wxEVT_MOUSE_CAPTURE_LOST") );
+ }
+}
+
+/* static */
+void wxWindowBase::NotifyCaptureLost()
+{
+ // don't do anything if capture lost was expected, i.e. resulted from
+ // a wx call to ReleaseMouse or CaptureMouse:
+ if ( ms_winCaptureChanging )
+ return;
+
+ // if the capture was lost unexpectedly, notify every window that has
+ // capture (on stack or current) about it and clear the stack:
+
+ if ( ms_winCaptureCurrent )
+ {
+ DoNotifyWindowAboutCaptureLost(ms_winCaptureCurrent);
+ ms_winCaptureCurrent = NULL;
+ }
+
+ while ( ms_winCaptureNext )
+ {
+ wxWindowNext *item = ms_winCaptureNext;
+ ms_winCaptureNext = item->next;
+
+ DoNotifyWindowAboutCaptureLost(item->win);
+
+ delete item;
+ }
+}
+
+#if wxUSE_HOTKEY
+
+bool
+wxWindowBase::RegisterHotKey(int WXUNUSED(hotkeyId),
+ int WXUNUSED(modifiers),
+ int WXUNUSED(keycode))
+{
+ // not implemented
+ return false;
+}
+
+bool wxWindowBase::UnregisterHotKey(int WXUNUSED(hotkeyId))
+{
+ // not implemented
+ return false;
+}
+
+#endif // wxUSE_HOTKEY
+
+// ----------------------------------------------------------------------------
+// event processing
+// ----------------------------------------------------------------------------
+
+bool wxWindowBase::TryBefore(wxEvent& event)
+{
+#if wxUSE_VALIDATORS
+ // Can only use the validator of the window which
+ // is receiving the event
+ if ( event.GetEventObject() == this )
+ {
+ wxValidator * const validator = GetValidator();
+ if ( validator && validator->ProcessEventLocally(event) )
+ {
+ return true;
+ }
+ }
+#endif // wxUSE_VALIDATORS
+
+ return wxEvtHandler::TryBefore(event);
+}
+
+bool wxWindowBase::TryAfter(wxEvent& event)
+{
+ // carry on up the parent-child hierarchy if the propagation count hasn't
+ // reached zero yet
+ if ( event.ShouldPropagate() )
+ {
+ // honour the requests to stop propagation at this window: this is
+ // used by the dialogs, for example, to prevent processing the events
+ // from the dialog controls in the parent frame which rarely, if ever,
+ // makes sense
+ if ( !(GetExtraStyle() & wxWS_EX_BLOCK_EVENTS) )
+ {
+ wxWindow *parent = GetParent();
+ if ( parent && !parent->IsBeingDeleted() )
+ {
+ wxPropagateOnce propagateOnce(event);
+
+ return parent->GetEventHandler()->ProcessEvent(event);
+ }