+#ifndef WX_PRECOMP
+ #include "wx/string.h"
+ #include "wx/log.h"
+ #include "wx/intl.h"
+ #include "wx/frame.h"
+ #include "wx/defs.h"
+ #include "wx/window.h"
+ #include "wx/checkbox.h"
+ #include "wx/radiobut.h"
+ #include "wx/settings.h"
+ #include "wx/dialog.h"
+#endif //WX_PRECOMP
+
+#if wxUSE_CONSTRAINTS
+ #include "wx/layout.h"
+#endif // wxUSE_CONSTRAINTS
+
+#if wxUSE_DRAG_AND_DROP
+ #include "wx/dnd.h"
+#endif // wxUSE_DRAG_AND_DROP
+
+#if wxUSE_TOOLTIPS
+ #include "wx/tooltip.h"
+#endif // wxUSE_TOOLTIPS
+
+#if wxUSE_CARET
+ #include "wx/caret.h"
+#endif // wxUSE_CARET
+
+// ----------------------------------------------------------------------------
+// static data
+// ----------------------------------------------------------------------------
+
+int wxWindowBase::ms_lastControlId = -200;
+
+IMPLEMENT_ABSTRACT_CLASS(wxWindowBase, wxEvtHandler)
+
+// ----------------------------------------------------------------------------
+// event table
+// ----------------------------------------------------------------------------
+
+BEGIN_EVENT_TABLE(wxWindowBase, wxEvtHandler)
+ EVT_SYS_COLOUR_CHANGED(wxWindowBase::OnSysColourChanged)
+ EVT_INIT_DIALOG(wxWindowBase::OnInitDialog)
+END_EVENT_TABLE()
+
+// ============================================================================
+// implementation of the common functionality of the wxWindow class
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// initialization
+// ----------------------------------------------------------------------------
+
+// the default initialization
+void wxWindowBase::InitBase()
+{
+ // no window yet, no parent nor children
+ m_parent = (wxWindow *)NULL;
+ m_windowId = -1;
+ m_children.DeleteContents( FALSE ); // don't auto delete node data
+
+ // no constraints on the minimal window size
+ m_minWidth =
+ m_minHeight =
+ m_maxWidth =
+ m_maxHeight = -1;
+
+ // window is created enabled but it's not visible yet
+ m_isShown = FALSE;
+ m_isEnabled = TRUE;
+
+ // no client data
+ m_clientObject = (wxClientData *)NULL;
+ m_clientData = NULL;
+
+ // the default event handler is just this window
+ m_eventHandler = this;
+
+#if wxUSE_VALIDATORS
+ // no validator
+ m_windowValidator = (wxValidator *) NULL;
+#endif // wxUSE_VALIDATORS
+
+ // use the system default colours
+ wxSystemSettings settings;
+
+ m_backgroundColour = settings.GetSystemColour(wxSYS_COLOUR_BTNFACE);
+ m_foregroundColour = *wxBLACK; // TODO take this from sys settings too?
+ m_font = *wxSWISS_FONT; // and this?
+
+ // no style bits
+ m_windowStyle = 0;
+
+ // an optimization for the event processing: checking this flag is much
+ // faster than using IsKindOf(CLASSINFO(wxWindow))
+ m_isWindow = TRUE;
+
+#if wxUSE_CONSTRAINTS
+ // no constraints whatsoever
+ m_constraints = (wxLayoutConstraints *) NULL;
+ m_constraintsInvolvedIn = (wxWindowList *) NULL;
+ m_windowSizer = (wxSizer *) NULL;
+ m_sizerParent = (wxWindowBase *) NULL;
+ m_autoLayout = FALSE;
+#endif // wxUSE_CONSTRAINTS
+
+#if wxUSE_DRAG_AND_DROP
+ m_dropTarget = (wxDropTarget *)NULL;
+#endif // wxUSE_DRAG_AND_DROP
+
+#if wxUSE_TOOLTIPS
+ m_tooltip = (wxToolTip *)NULL;
+#endif // wxUSE_TOOLTIPS
+
+#if wxUSE_CARET
+ m_caret = (wxCaret *)NULL;
+#endif // wxUSE_CARET
+}
+
+// common part of window creation process
+bool wxWindowBase::CreateBase(wxWindowBase *parent,
+ wxWindowID id,
+ const wxPoint& WXUNUSED(pos),
+ const wxSize& WXUNUSED(size),
+ long style,
+ const wxString& name)
+{
+ // m_isWindow is set to TRUE in wxWindowBase::Init() as well as many other
+ // member variables - check that it has been called (will catch the case
+ // when a new ctor is added which doesn't call InitWindow)
+ wxASSERT_MSG( m_isWindow, _T("Init() must have been called before!") );
+
+ // generate a new id if the user doesn't care about it
+ m_windowId = id == -1 ? NewControlId() : id;
+
+ SetName(name);
+ SetWindowStyleFlag(style);
+ SetParent(parent);
+
+ return TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// destruction
+// ----------------------------------------------------------------------------
+
+// common clean up
+wxWindowBase::~wxWindowBase()
+{
+ // FIXME if these 2 cases result from programming errors in the user code
+ // we should probably assert here instead of silently fixing them
+
+ // Just in case the window has been Closed, but we're then deleting
+ // immediately: don't leave dangling pointers.
+ wxPendingDelete.DeleteObject(this);
+
+ // Just in case we've loaded a top-level window via LoadNativeDialog but
+ // we weren't a dialog class
+ wxTopLevelWindows.DeleteObject(this);
+
+ wxASSERT_MSG( GetChildren().GetCount() == 0, _T("children not destroyed") );
+
+#if wxUSE_CARET
+ if ( m_caret )
+ delete m_caret;
+#endif // wxUSE_CARET
+
+#if wxUSE_VALIDATORS
+ if ( m_windowValidator )
+ delete m_windowValidator;
+#endif // wxUSE_VALIDATORS
+
+ if ( m_clientObject )
+ delete m_clientObject;
+
+#if wxUSE_CONSTRAINTS
+ // Have to delete constraints/sizer FIRST otherwise sizers may try to look
+ // at deleted windows as they delete themselves.
+ DeleteRelatedConstraints();
+
+ if ( m_constraints )
+ {
+ // This removes any dangling pointers to this window in other windows'
+ // constraintsInvolvedIn lists.
+ UnsetConstraints(m_constraints);
+ delete m_constraints;
+ m_constraints = NULL;
+ }
+
+ if ( m_windowSizer )
+ delete m_windowSizer;
+
+ // If this is a child of a sizer, remove self from parent
+ if ( m_sizerParent )
+ m_sizerParent->RemoveChild(this);
+#endif // wxUSE_CONSTRAINTS
+
+#if wxUSE_DRAG_AND_DROP
+ if ( m_dropTarget )
+ delete m_dropTarget;
+#endif // wxUSE_DRAG_AND_DROP
+
+#if wxUSE_TOOLTIPS
+ if ( m_tooltip )
+ delete m_tooltip;
+#endif // wxUSE_TOOLTIPS
+}
+
+bool wxWindowBase::Destroy()
+{
+ delete this;
+
+ return TRUE;
+}
+
+bool wxWindowBase::Close(bool force)
+{
+ wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId);
+ event.SetEventObject(this);
+#if WXWIN_COMPATIBILITY
+ event.SetForce(force);
+#endif // WXWIN_COMPATIBILITY
+ event.SetCanVeto(!force);
+
+ // return FALSE if window wasn't closed because the application vetoed the
+ // close event
+ return GetEventHandler()->ProcessEvent(event) && !event.GetVeto();
+}
+
+bool wxWindowBase::DestroyChildren()
+{
+ wxWindowList::Node *node;
+ for ( ;; )
+ {
+ // we iterate until the list becomes empty
+ node = GetChildren().GetFirst();
+ if ( !node )
+ break;
+
+ wxWindow *child = node->GetData();
+
+ wxASSERT_MSG( child, _T("children list contains empty nodes") );
+
+ delete child;
+
+ wxASSERT_MSG( !GetChildren().Find(child),
+ _T("child didn't remove itself using RemoveChild()") );
+ }
+
+ return TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// centre/fit the window
+// ----------------------------------------------------------------------------
+
+// centre the window with respect to its parent in either (or both) directions
+void wxWindowBase::Centre(int direction)
+{
+ int widthParent, heightParent;
+
+ wxWindow *parent = GetParent();
+ if ( parent )
+ {
+ parent->GetClientSize(&widthParent, &heightParent);
+ }
+ else
+ {
+ // centre with respect to the whole screen
+ wxDisplaySize(&widthParent, &heightParent);
+ }
+
+ int width, height;
+ GetSize(&width, &height);
+
+ int new_x = -1,
+ new_y = -1;
+
+ if ( direction & wxHORIZONTAL )
+ new_x = (widthParent - width)/2;
+
+ if ( direction & wxVERTICAL )
+ new_y = (heightParent - height)/2;
+
+ Move(new_x, new_y);
+}
+
+// Center TopLevel windows over thier parent instead of the whole screen
+void wxWindowBase::CentreOnParent(int direction)
+{
+ wxPoint ppos;
+ wxSize psze;
+ wxSize wsze;
+ wxWindow* parent = GetParent();
+ int x, y;
+
+ if (!parent || !IsTopLevel()) {
+ Centre(direction);
+ return;
+ }
+
+ psze = parent->GetSize();
+ ppos = parent->ClientToScreen(wxPoint(0,0));
+ wsze = GetSize();
+
+ x = y = -1;
+
+ if (direction == wxBOTH || direction == wxHORIZONTAL)
+ x = ppos.x + (psze.x - wsze.x)/2;
+ if (direction == wxBOTH || direction == wxVERTICAL)
+ y = ppos.y + (psze.y - wsze.y)/2;
+
+ Move(x, y);
+}
+
+// fits the window around the children
+void wxWindowBase::Fit()
+{
+ int maxX = 0,
+ maxY = 0;
+
+ for ( wxWindowList::Node *node = GetChildren().GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ wxWindow *win = node->GetData();
+ if ( win->IsTopLevel() )
+ {
+ // dialogs and frames lie in different top level windows - don't
+ // deal with them here
+ continue;
+ }
+
+ int wx, wy, ww, wh;
+ win->GetPosition(&wx, &wy);
+ win->GetSize(&ww, &wh);
+ if ( wx + ww > maxX )
+ maxX = wx + ww;
+ if ( wy + wh > maxY )
+ maxY = wy + wh;
+ }
+
+ // leave a margin
+ SetClientSize(maxX + 7, maxY + 14);
+}
+
+// set the min/max size of the window
+
+void wxWindowBase::SetSizeHints(int minW, int minH,
+ int maxW, int maxH,
+ int WXUNUSED(incW), int WXUNUSED(incH))
+{
+ m_minWidth = minW;
+ m_maxWidth = maxW;
+ m_minHeight = minH;
+ m_maxHeight = maxH;
+}
+
+// ----------------------------------------------------------------------------
+// show/hide/enable/disable the window
+// ----------------------------------------------------------------------------
+
+bool wxWindowBase::Show(bool show)
+{
+ if ( show != m_isShown )
+ {
+ m_isShown = show;
+
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+bool wxWindowBase::Enable(bool enable)
+{
+ if ( enable != m_isEnabled )
+ {
+ m_isEnabled = enable;
+
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+// ----------------------------------------------------------------------------
+// RTTI
+// ----------------------------------------------------------------------------
+
+bool wxWindowBase::IsTopLevel() const
+{
+ return wxDynamicCast(this, wxFrame) || wxDynamicCast(this, wxDialog);
+}
+
+// ----------------------------------------------------------------------------
+// reparenting the window
+// ----------------------------------------------------------------------------
+
+void wxWindowBase::AddChild(wxWindowBase *child)
+{
+ wxCHECK_RET( child, _T("can't add a NULL child") );
+
+ GetChildren().Append(child);
+ child->SetParent(this);
+}
+
+void wxWindowBase::RemoveChild(wxWindowBase *child)
+{
+ wxCHECK_RET( child, _T("can't remove a NULL child") );
+
+ GetChildren().DeleteObject(child);
+ child->SetParent((wxWindow *)NULL);
+}
+
+bool wxWindowBase::Reparent(wxWindowBase *newParent)
+{
+ wxWindow *oldParent = GetParent();
+ if ( newParent == oldParent )
+ {
+ // nothing done
+ return FALSE;
+ }
+
+ // unlink this window from the existing parent.
+ if ( oldParent )
+ {
+ oldParent->RemoveChild(this);
+ }
+ else
+ {
+ wxTopLevelWindows.DeleteObject(this);
+ }
+
+ // add it to the new one
+ if ( newParent )
+ {
+ newParent->AddChild(this);
+ }
+ else
+ {
+ wxTopLevelWindows.Append(this);
+ }
+
+ return TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// event handler stuff
+// ----------------------------------------------------------------------------
+
+void wxWindowBase::PushEventHandler(wxEvtHandler *handler)
+{
+ handler->SetNextHandler(GetEventHandler());
+ SetEventHandler(handler);
+}
+
+wxEvtHandler *wxWindowBase::PopEventHandler(bool deleteHandler)
+{
+ wxEvtHandler *handlerA = GetEventHandler();
+ if ( handlerA )
+ {
+ wxEvtHandler *handlerB = handlerA->GetNextHandler();
+ handlerA->SetNextHandler((wxEvtHandler *)NULL);
+ SetEventHandler(handlerB);
+ if ( deleteHandler )
+ {
+ delete handlerA;
+ handlerA = (wxEvtHandler *)NULL;
+ }
+ }
+
+ return handlerA;
+}
+
+// ----------------------------------------------------------------------------
+// cursors, fonts &c
+// ----------------------------------------------------------------------------
+
+bool wxWindowBase::SetBackgroundColour( const wxColour &colour )
+{
+ if ( !colour.Ok() || (colour == m_backgroundColour) )
+ return FALSE;
+
+ m_backgroundColour = colour;
+
+ return TRUE;
+}
+
+bool wxWindowBase::SetForegroundColour( const wxColour &colour )
+{
+ if ( !colour.Ok() || (colour == m_foregroundColour) )
+ return FALSE;
+
+ m_foregroundColour = colour;
+
+ return TRUE;
+}
+
+bool wxWindowBase::SetCursor(const wxCursor& cursor)
+{
+ // don't try to set invalid cursor, always fall back to the default
+ const wxCursor& cursorOk = cursor.Ok() ? cursor : *wxSTANDARD_CURSOR;
+
+ if ( cursorOk == m_cursor )
+ {
+ // no change
+ return FALSE;
+ }
+
+ m_cursor = cursorOk;
+
+ return TRUE;
+}
+
+bool wxWindowBase::SetFont(const wxFont& font)
+{
+ // don't try to set invalid font, always fall back to the default
+ const wxFont& fontOk = font.Ok() ? font : *wxSWISS_FONT;
+
+ if ( fontOk == m_font )
+ {
+ // no change
+ return FALSE;
+ }
+
+ m_font = fontOk;
+
+ return TRUE;
+}
+
+#if wxUSE_CARET
+void wxWindowBase::SetCaret(wxCaret *caret)
+{
+ if ( m_caret )
+ {
+ delete m_caret;
+ }
+
+ m_caret = caret;
+
+ if ( m_caret )
+ {
+ wxASSERT_MSG( m_caret->GetWindow() == this,
+ _T("caret should be created associated to this window") );
+ }
+}
+#endif // wxUSE_CARET
+
+#if wxUSE_VALIDATORS
+// ----------------------------------------------------------------------------
+// validators
+// ----------------------------------------------------------------------------
+
+void wxWindowBase::SetValidator(const wxValidator& validator)
+{
+ if ( m_windowValidator )
+ delete m_windowValidator;
+
+ m_windowValidator = (wxValidator *)validator.Clone();
+
+ if ( m_windowValidator )
+ m_windowValidator->SetWindow(this) ;
+}
+#endif // wxUSE_VALIDATORS
+
+// ----------------------------------------------------------------------------
+// update region testing
+// ----------------------------------------------------------------------------
+
+bool wxWindowBase::IsExposed(int x, int y) const
+{
+ return m_updateRegion.Contains(x, y) != wxOutRegion;
+}
+
+bool wxWindowBase::IsExposed(int x, int y, int w, int h) const
+{
+ return m_updateRegion.Contains(x, y, w, h) != wxOutRegion;
+}
+
+// ----------------------------------------------------------------------------
+// find window by id or name
+// ----------------------------------------------------------------------------
+
+wxWindow *wxWindowBase::FindWindow( long id )
+{
+ if ( id == m_windowId )
+ return (wxWindow *)this;
+
+ wxWindowBase *res = (wxWindow *)NULL;
+ wxWindowList::Node *node;
+ for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() )
+ {
+ wxWindowBase *child = node->GetData();
+ res = child->FindWindow( id );
+ }
+
+ return (wxWindow *)res;
+}
+
+wxWindow *wxWindowBase::FindWindow( const wxString& name )
+{
+ if ( name == m_windowName )
+ return (wxWindow *)this;
+
+ wxWindowBase *res = (wxWindow *)NULL;
+ wxWindowList::Node *node;
+ for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() )
+ {
+ wxWindow *child = node->GetData();
+ res = child->FindWindow(name);
+ }
+
+ return (wxWindow *)res;
+}
+
+// ----------------------------------------------------------------------------
+// dialog oriented functions
+// ----------------------------------------------------------------------------
+
+void wxWindowBase::MakeModal(bool modal)
+{
+ // Disable all other windows
+ if ( IsTopLevel() )
+ {
+ wxWindowList::Node *node = wxTopLevelWindows.GetFirst();
+ while (node)
+ {
+ wxWindow *win = node->GetData();
+ if (win != this)
+ win->Enable(!modal);
+
+ node = node->GetNext();
+ }
+ }
+}
+
+bool wxWindowBase::Validate()
+{
+#if wxUSE_VALIDATORS
+ wxWindowList::Node *node;
+ for ( node = m_children.GetFirst(); node; node = node->GetNext() )
+ {
+ wxWindowBase *child = node->GetData();
+ wxValidator *validator = child->GetValidator();
+ if ( validator && !validator->Validate((wxWindow *)this) )
+ {
+ return FALSE;
+ }
+ }
+#endif // wxUSE_VALIDATORS
+
+ return TRUE;
+}
+
+bool wxWindowBase::TransferDataToWindow()
+{
+#if wxUSE_VALIDATORS
+ wxWindowList::Node *node;
+ for ( node = m_children.GetFirst(); node; node = node->GetNext() )
+ {
+ wxWindowBase *child = node->GetData();
+ wxValidator *validator = child->GetValidator();
+ if ( validator && !validator->TransferToWindow() )
+ {
+ wxLog *log = wxLog::GetActiveTarget();
+ if ( log )
+ {
+ wxLogWarning(_("Could not transfer data to window"));
+ log->Flush();
+ }
+
+ return FALSE;
+ }
+ }
+#endif // wxUSE_VALIDATORS
+
+ return TRUE;
+}
+
+bool wxWindowBase::TransferDataFromWindow()
+{
+#if wxUSE_VALIDATORS
+ wxWindowList::Node *node;
+ for ( node = m_children.GetFirst(); node; node = node->GetNext() )
+ {
+ wxWindow *child = node->GetData();
+ if ( child->GetValidator() &&
+ !child->GetValidator()->TransferFromWindow() )
+ {
+ return FALSE;
+ }
+ }
+#endif // wxUSE_VALIDATORS
+
+ return TRUE;
+}
+
+void wxWindowBase::InitDialog()
+{
+ wxInitDialogEvent event(GetId());
+ event.SetEventObject( this );
+ GetEventHandler()->ProcessEvent(event);
+}
+
+// ----------------------------------------------------------------------------
+// tooltips
+// ----------------------------------------------------------------------------
+
+#if wxUSE_TOOLTIPS
+
+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((wxToolTip *)NULL) for this
+}
+
+void wxWindowBase::DoSetToolTip(wxToolTip *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);
+ }
+}