+#endif // wxUSE_VALIDATORS
+
+ return true;
+}
+
+void wxWindowBase::InitDialog()
+{
+ wxInitDialogEvent event(GetId());
+ event.SetEventObject( this );
+ GetEventHandler()->ProcessEvent(event);
+}
+
+// ----------------------------------------------------------------------------
+// context-sensitive help support
+// ----------------------------------------------------------------------------
+
+#if wxUSE_HELP
+
+// associate this help text with this window
+void wxWindowBase::SetHelpText(const wxString& text)
+{
+ wxHelpProvider *helpProvider = wxHelpProvider::Get();
+ if ( helpProvider )
+ {
+ helpProvider->AddHelp(this, text);
+ }
+}
+
+#if WXWIN_COMPATIBILITY_2_8
+// associate this help text with all windows with the same id as this
+// one
+void wxWindowBase::SetHelpTextForId(const wxString& text)
+{
+ wxHelpProvider *helpProvider = wxHelpProvider::Get();
+ if ( helpProvider )
+ {
+ helpProvider->AddHelp(GetId(), text);
+ }
+}
+#endif // WXWIN_COMPATIBILITY_2_8
+
+// get the help string associated with this window (may be empty)
+// default implementation forwards calls to the help provider
+wxString
+wxWindowBase::GetHelpTextAtPoint(const wxPoint & WXUNUSED(pt),
+ wxHelpEvent::Origin WXUNUSED(origin)) const
+{
+ wxString text;
+ wxHelpProvider *helpProvider = wxHelpProvider::Get();
+ if ( helpProvider )
+ {
+ text = helpProvider->GetHelp(this);
+ }
+
+ return text;
+}
+
+// show help for this window
+void wxWindowBase::OnHelp(wxHelpEvent& event)
+{
+ wxHelpProvider *helpProvider = wxHelpProvider::Get();
+ if ( helpProvider )
+ {
+ wxPoint pos = event.GetPosition();
+ const wxHelpEvent::Origin origin = event.GetOrigin();
+ if ( origin == wxHelpEvent::Origin_Keyboard )
+ {
+ // if the help event was generated from keyboard it shouldn't
+ // appear at the mouse position (which is still the only position
+ // associated with help event) if the mouse is far away, although
+ // we still do use the mouse position if it's over the window
+ // because we suppose the user looks approximately at the mouse
+ // already and so it would be more convenient than showing tooltip
+ // at some arbitrary position which can be quite far from it
+ const wxRect rectClient = GetClientRect();
+ if ( !rectClient.Contains(ScreenToClient(pos)) )
+ {
+ // position help slightly under and to the right of this window
+ pos = ClientToScreen(wxPoint(
+ 2*GetCharWidth(),
+ rectClient.height + GetCharHeight()
+ ));
+ }
+ }
+
+ if ( helpProvider->ShowHelpAtPoint(this, pos, origin) )
+ {
+ // skip the event.Skip() below
+ return;
+ }
+ }
+
+ event.Skip();
+}
+
+#endif // wxUSE_HELP
+
+// ----------------------------------------------------------------------------
+// tooltips
+// ----------------------------------------------------------------------------
+
+#if wxUSE_TOOLTIPS
+
+wxString wxWindowBase::GetToolTipText() const
+{
+ return m_tooltip ? m_tooltip->GetTip() : wxString();
+}
+
+void wxWindowBase::SetToolTip( const wxString &tip )
+{
+ // don't create the new tooltip if we already have one
+ if ( m_tooltip )
+ {
+ m_tooltip->SetTip( tip );
+ }
+ else
+ {
+ SetToolTip( new wxToolTip( tip ) );
+ }
+
+ // setting empty tooltip text does not remove the tooltip any more - use
+ // SetToolTip(NULL) for this
+}
+
+void wxWindowBase::DoSetToolTip(wxToolTip *tooltip)
+{
+ if ( m_tooltip != tooltip )
+ {
+ if ( m_tooltip )
+ delete m_tooltip;
+
+ m_tooltip = tooltip;
+ }
+}
+
+#endif // wxUSE_TOOLTIPS
+
+// ----------------------------------------------------------------------------
+// constraints and sizers
+// ----------------------------------------------------------------------------
+
+#if wxUSE_CONSTRAINTS
+
+void wxWindowBase::SetConstraints( wxLayoutConstraints *constraints )
+{
+ if ( m_constraints )
+ {
+ UnsetConstraints(m_constraints);
+ delete m_constraints;
+ }
+ m_constraints = constraints;
+ if ( m_constraints )
+ {
+ // Make sure other windows know they're part of a 'meaningful relationship'
+ if ( m_constraints->left.GetOtherWindow() && (m_constraints->left.GetOtherWindow() != this) )
+ m_constraints->left.GetOtherWindow()->AddConstraintReference(this);
+ if ( m_constraints->top.GetOtherWindow() && (m_constraints->top.GetOtherWindow() != this) )
+ m_constraints->top.GetOtherWindow()->AddConstraintReference(this);
+ if ( m_constraints->right.GetOtherWindow() && (m_constraints->right.GetOtherWindow() != this) )
+ m_constraints->right.GetOtherWindow()->AddConstraintReference(this);
+ if ( m_constraints->bottom.GetOtherWindow() && (m_constraints->bottom.GetOtherWindow() != this) )
+ m_constraints->bottom.GetOtherWindow()->AddConstraintReference(this);
+ if ( m_constraints->width.GetOtherWindow() && (m_constraints->width.GetOtherWindow() != this) )
+ m_constraints->width.GetOtherWindow()->AddConstraintReference(this);
+ if ( m_constraints->height.GetOtherWindow() && (m_constraints->height.GetOtherWindow() != this) )
+ m_constraints->height.GetOtherWindow()->AddConstraintReference(this);
+ if ( m_constraints->centreX.GetOtherWindow() && (m_constraints->centreX.GetOtherWindow() != this) )
+ m_constraints->centreX.GetOtherWindow()->AddConstraintReference(this);
+ if ( m_constraints->centreY.GetOtherWindow() && (m_constraints->centreY.GetOtherWindow() != this) )
+ m_constraints->centreY.GetOtherWindow()->AddConstraintReference(this);
+ }
+}
+
+// This removes any dangling pointers to this window in other windows'
+// constraintsInvolvedIn lists.
+void wxWindowBase::UnsetConstraints(wxLayoutConstraints *c)
+{
+ if ( c )
+ {
+ if ( c->left.GetOtherWindow() && (c->top.GetOtherWindow() != this) )
+ c->left.GetOtherWindow()->RemoveConstraintReference(this);
+ if ( c->top.GetOtherWindow() && (c->top.GetOtherWindow() != this) )
+ c->top.GetOtherWindow()->RemoveConstraintReference(this);
+ if ( c->right.GetOtherWindow() && (c->right.GetOtherWindow() != this) )
+ c->right.GetOtherWindow()->RemoveConstraintReference(this);
+ if ( c->bottom.GetOtherWindow() && (c->bottom.GetOtherWindow() != this) )
+ c->bottom.GetOtherWindow()->RemoveConstraintReference(this);
+ if ( c->width.GetOtherWindow() && (c->width.GetOtherWindow() != this) )
+ c->width.GetOtherWindow()->RemoveConstraintReference(this);
+ if ( c->height.GetOtherWindow() && (c->height.GetOtherWindow() != this) )
+ c->height.GetOtherWindow()->RemoveConstraintReference(this);
+ if ( c->centreX.GetOtherWindow() && (c->centreX.GetOtherWindow() != this) )
+ c->centreX.GetOtherWindow()->RemoveConstraintReference(this);
+ if ( c->centreY.GetOtherWindow() && (c->centreY.GetOtherWindow() != this) )
+ c->centreY.GetOtherWindow()->RemoveConstraintReference(this);
+ }
+}
+
+// Back-pointer to other windows we're involved with, so if we delete this
+// window, we must delete any constraints we're involved with.
+void wxWindowBase::AddConstraintReference(wxWindowBase *otherWin)
+{
+ if ( !m_constraintsInvolvedIn )
+ m_constraintsInvolvedIn = new wxWindowList;
+ if ( !m_constraintsInvolvedIn->Find((wxWindow *)otherWin) )
+ m_constraintsInvolvedIn->Append((wxWindow *)otherWin);
+}
+
+// REMOVE back-pointer to other windows we're involved with.
+void wxWindowBase::RemoveConstraintReference(wxWindowBase *otherWin)
+{
+ if ( m_constraintsInvolvedIn )
+ m_constraintsInvolvedIn->DeleteObject((wxWindow *)otherWin);
+}
+
+// Reset any constraints that mention this window
+void wxWindowBase::DeleteRelatedConstraints()
+{
+ if ( m_constraintsInvolvedIn )
+ {
+ wxWindowList::compatibility_iterator node = m_constraintsInvolvedIn->GetFirst();
+ while (node)
+ {
+ wxWindow *win = node->GetData();
+ wxLayoutConstraints *constr = win->GetConstraints();
+
+ // Reset any constraints involving this window
+ if ( constr )
+ {
+ constr->left.ResetIfWin(this);
+ constr->top.ResetIfWin(this);
+ constr->right.ResetIfWin(this);
+ constr->bottom.ResetIfWin(this);
+ constr->width.ResetIfWin(this);
+ constr->height.ResetIfWin(this);
+ constr->centreX.ResetIfWin(this);
+ constr->centreY.ResetIfWin(this);
+ }
+
+ wxWindowList::compatibility_iterator next = node->GetNext();
+ m_constraintsInvolvedIn->Erase(node);
+ node = next;
+ }
+
+ delete m_constraintsInvolvedIn;
+ m_constraintsInvolvedIn = NULL;
+ }
+}
+
+#endif // wxUSE_CONSTRAINTS
+
+void wxWindowBase::SetSizer(wxSizer *sizer, bool deleteOld)
+{
+ if ( sizer == m_windowSizer)
+ return;
+
+ if ( m_windowSizer )
+ {
+ m_windowSizer->SetContainingWindow(NULL);
+
+ if ( deleteOld )
+ delete m_windowSizer;
+ }
+
+ m_windowSizer = sizer;
+ if ( m_windowSizer )
+ {
+ m_windowSizer->SetContainingWindow((wxWindow *)this);
+ }
+
+ SetAutoLayout(m_windowSizer != NULL);
+}
+
+void wxWindowBase::SetSizerAndFit(wxSizer *sizer, bool deleteOld)
+{
+ SetSizer( sizer, deleteOld );
+ sizer->SetSizeHints( (wxWindow*) this );
+}
+
+
+void wxWindowBase::SetContainingSizer(wxSizer* sizer)
+{
+ // adding a window to a sizer twice is going to result in fatal and
+ // hard to debug problems later because when deleting the second
+ // associated wxSizerItem we're going to dereference a dangling
+ // pointer; so try to detect this as early as possible
+ wxASSERT_MSG( !sizer || m_containingSizer != sizer,
+ wxT("Adding a window to the same sizer twice?") );
+
+ m_containingSizer = sizer;
+}
+
+#if wxUSE_CONSTRAINTS
+
+void wxWindowBase::SatisfyConstraints()
+{
+ wxLayoutConstraints *constr = GetConstraints();
+ bool wasOk = constr && constr->AreSatisfied();
+
+ ResetConstraints(); // Mark all constraints as unevaluated
+
+ int noChanges = 1;
+
+ // if we're a top level panel (i.e. our parent is frame/dialog), our
+ // own constraints will never be satisfied any more unless we do it
+ // here
+ if ( wasOk )
+ {
+ while ( noChanges > 0 )
+ {
+ LayoutPhase1(&noChanges);
+ }
+ }
+
+ LayoutPhase2(&noChanges);
+}
+
+#endif // wxUSE_CONSTRAINTS
+
+bool wxWindowBase::Layout()
+{
+ // If there is a sizer, use it instead of the constraints
+ if ( GetSizer() )
+ {
+ int w = 0, h = 0;
+ GetVirtualSize(&w, &h);
+ GetSizer()->SetDimension( 0, 0, w, h );
+ }
+#if wxUSE_CONSTRAINTS
+ else
+ {
+ SatisfyConstraints(); // Find the right constraints values
+ SetConstraintSizes(); // Recursively set the real window sizes
+ }
+#endif
+
+ return true;
+}
+
+void wxWindowBase::InternalOnSize(wxSizeEvent& event)
+{
+ if ( GetAutoLayout() )
+ Layout();
+
+ event.Skip();
+}
+
+#if wxUSE_CONSTRAINTS
+
+// first phase of the constraints evaluation: set our own constraints
+bool wxWindowBase::LayoutPhase1(int *noChanges)
+{
+ wxLayoutConstraints *constr = GetConstraints();
+
+ return !constr || constr->SatisfyConstraints(this, noChanges);
+}
+
+// second phase: set the constraints for our children
+bool wxWindowBase::LayoutPhase2(int *noChanges)
+{
+ *noChanges = 0;
+
+ // Layout children
+ DoPhase(1);
+
+ // Layout grand children
+ DoPhase(2);
+
+ return true;
+}
+
+// Do a phase of evaluating child constraints
+bool wxWindowBase::DoPhase(int phase)
+{
+ // the list containing the children for which the constraints are already
+ // set correctly
+ wxWindowList succeeded;
+
+ // the max number of iterations we loop before concluding that we can't set
+ // the constraints
+ static const int maxIterations = 500;
+
+ for ( int noIterations = 0; noIterations < maxIterations; noIterations++ )
+ {
+ int noChanges = 0;
+
+ // loop over all children setting their constraints
+ for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ wxWindow *child = node->GetData();
+ if ( child->IsTopLevel() )
+ {
+ // top level children are not inside our client area
+ continue;
+ }
+
+ if ( !child->GetConstraints() || succeeded.Find(child) )
+ {
+ // this one is either already ok or nothing we can do about it
+ continue;
+ }
+
+ int tempNoChanges = 0;
+ bool success = phase == 1 ? child->LayoutPhase1(&tempNoChanges)
+ : child->LayoutPhase2(&tempNoChanges);
+ noChanges += tempNoChanges;
+
+ if ( success )
+ {
+ succeeded.Append(child);
+ }
+ }
+
+ if ( !noChanges )
+ {
+ // constraints are set
+ break;
+ }
+ }
+
+ return true;
+}
+
+void wxWindowBase::ResetConstraints()
+{
+ wxLayoutConstraints *constr = GetConstraints();
+ if ( constr )
+ {
+ constr->left.SetDone(false);
+ constr->top.SetDone(false);
+ constr->right.SetDone(false);
+ constr->bottom.SetDone(false);
+ constr->width.SetDone(false);
+ constr->height.SetDone(false);
+ constr->centreX.SetDone(false);
+ constr->centreY.SetDone(false);
+ }
+
+ wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+ while (node)
+ {
+ wxWindow *win = node->GetData();
+ if ( !win->IsTopLevel() )
+ win->ResetConstraints();
+ node = node->GetNext();
+ }
+}
+
+// Need to distinguish between setting the 'fake' size for windows and sizers,
+// and setting the real values.
+void wxWindowBase::SetConstraintSizes(bool recurse)
+{
+ wxLayoutConstraints *constr = GetConstraints();
+ if ( constr && constr->AreSatisfied() )
+ {
+ int x = constr->left.GetValue();
+ int y = constr->top.GetValue();
+ int w = constr->width.GetValue();
+ int h = constr->height.GetValue();
+
+ if ( (constr->width.GetRelationship() != wxAsIs ) ||
+ (constr->height.GetRelationship() != wxAsIs) )
+ {
+ SetSize(x, y, w, h);
+ }
+ else
+ {
+ // If we don't want to resize this window, just move it...
+ Move(x, y);
+ }
+ }
+ else if ( constr )
+ {
+ wxLogDebug(wxT("Constraints not satisfied for %s named '%s'."),
+ GetClassInfo()->GetClassName(),
+ GetName().c_str());
+ }
+
+ if ( recurse )
+ {
+ wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+ while (node)
+ {
+ wxWindow *win = node->GetData();
+ if ( !win->IsTopLevel() && win->GetConstraints() )
+ win->SetConstraintSizes();
+ node = node->GetNext();
+ }
+ }
+}
+
+// Only set the size/position of the constraint (if any)
+void wxWindowBase::SetSizeConstraint(int x, int y, int w, int h)
+{
+ wxLayoutConstraints *constr = GetConstraints();
+ if ( constr )
+ {
+ if ( x != wxDefaultCoord )
+ {
+ constr->left.SetValue(x);
+ constr->left.SetDone(true);
+ }
+ if ( y != wxDefaultCoord )
+ {
+ constr->top.SetValue(y);
+ constr->top.SetDone(true);
+ }
+ if ( w != wxDefaultCoord )
+ {
+ constr->width.SetValue(w);
+ constr->width.SetDone(true);
+ }
+ if ( h != wxDefaultCoord )
+ {
+ constr->height.SetValue(h);
+ constr->height.SetDone(true);
+ }
+ }
+}
+
+void wxWindowBase::MoveConstraint(int x, int y)
+{
+ wxLayoutConstraints *constr = GetConstraints();
+ if ( constr )
+ {
+ if ( x != wxDefaultCoord )
+ {
+ constr->left.SetValue(x);
+ constr->left.SetDone(true);
+ }
+ if ( y != wxDefaultCoord )
+ {
+ constr->top.SetValue(y);
+ 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());
+}
+
+// ----------------------------------------------------------------------------
+// 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 wxWindow *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__
+ {
+ // just Ctrl-Alt-middle click shows information about wx version
+ ::wxInfoMessageBox((wxWindow*)this);
+ }
+ }
+ 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_STL
+
+#include "wx/listimpl.cpp"
+WX_DEFINE_LIST(wxWindowList)
+
+#else // !wxUSE_STL
+
+void wxWindowListNode::DeleteData()
+{
+ delete (wxWindow *)GetData();
+}
+
+#endif // wxUSE_STL/!wxUSE_STL
+
+// ----------------------------------------------------------------------------
+// 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);
+ }
+ }
+ }
+
+ return wxEvtHandler::TryAfter(event);
+}
+
+// ----------------------------------------------------------------------------
+// window relationships
+// ----------------------------------------------------------------------------
+
+wxWindow *wxWindowBase::DoGetSibling(WindowOrder order) const
+{
+ wxCHECK_MSG( GetParent(), NULL,
+ wxT("GetPrev/NextSibling() don't work for TLWs!") );
+
+ wxWindowList& siblings = GetParent()->GetChildren();
+ wxWindowList::compatibility_iterator i = siblings.Find((wxWindow *)this);
+ wxCHECK_MSG( i, NULL, wxT("window not a child of its parent?") );
+
+ if ( order == OrderBefore )
+ i = i->GetPrevious();
+ else // OrderAfter
+ i = i->GetNext();
+
+ return i ? i->GetData() : NULL;
+}
+
+// ----------------------------------------------------------------------------
+// keyboard navigation
+// ----------------------------------------------------------------------------
+
+// Navigates in the specified direction inside this window
+bool wxWindowBase::DoNavigateIn(int flags)
+{
+#ifdef wxHAS_NATIVE_TAB_TRAVERSAL
+ // native code doesn't process our wxNavigationKeyEvents anyhow
+ wxUnusedVar(flags);
+ return false;
+#else // !wxHAS_NATIVE_TAB_TRAVERSAL
+ wxNavigationKeyEvent eventNav;
+ wxWindow *focused = FindFocus();
+ eventNav.SetCurrentFocus(focused);
+ eventNav.SetEventObject(focused);
+ eventNav.SetFlags(flags);
+ return GetEventHandler()->ProcessEvent(eventNav);
+#endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL
+}
+
+bool wxWindowBase::HandleAsNavigationKey(const wxKeyEvent& event)
+{
+ if ( event.GetKeyCode() != WXK_TAB )
+ return false;
+
+ int flags = wxNavigationKeyEvent::FromTab;
+
+ if ( event.ShiftDown() )
+ flags |= wxNavigationKeyEvent::IsBackward;
+ else
+ flags |= wxNavigationKeyEvent::IsForward;
+
+ if ( event.ControlDown() )
+ flags |= wxNavigationKeyEvent::WinChange;
+
+ Navigate(flags);
+ return true;
+}
+
+void wxWindowBase::DoMoveInTabOrder(wxWindow *win, WindowOrder move)
+{
+ // check that we're not a top level window
+ wxCHECK_RET( GetParent(),
+ wxT("MoveBefore/AfterInTabOrder() don't work for TLWs!") );
+
+ // detect the special case when we have nothing to do anyhow and when the
+ // code below wouldn't work
+ if ( win == this )
+ return;
+
+ // find the target window in the siblings list
+ wxWindowList& siblings = GetParent()->GetChildren();
+ wxWindowList::compatibility_iterator i = siblings.Find(win);
+ wxCHECK_RET( i, wxT("MoveBefore/AfterInTabOrder(): win is not a sibling") );
+
+ // unfortunately, when wxUSE_STL == 1 DetachNode() is not implemented so we
+ // can't just move the node around
+ wxWindow *self = (wxWindow *)this;
+ siblings.DeleteObject(self);
+ if ( move == OrderAfter )
+ {
+ i = i->GetNext();
+ }
+
+ if ( i )
+ {
+ siblings.Insert(i, self);
+ }
+ else // OrderAfter and win was the last sibling
+ {
+ siblings.Append(self);
+ }