]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/wincmn.cpp
wxWindow::Fit() infinite loop bug fixed
[wxWidgets.git] / src / common / wincmn.cpp
index 28fd6ab1d1c31db41d8468fd9fb78cfa4116ce9a..87709ad66a4b3dcc167a3a3f55fcca2783800481 100644 (file)
 /////////////////////////////////////////////////////////////////////////////
-// Name:        windows.cpp
+// Name:        common/window.cpp
 // Purpose:     common (to all ports) wxWindow functions
 // Author:      Julian Smart, Vadim Zeitlin
 // Modified by:
 // Created:     13/07/98
 // RCS-ID:      $Id$
-// Copyright:   (c) Julian Smart and Markus Holzem
+// Copyright:   (c) wxWindows team
 // Licence:     wxWindows license
 /////////////////////////////////////////////////////////////////////////////
 
-#include "wx/defs.h"
-#include "wx/window.h"
+// ============================================================================
+// declarations
+// ============================================================================
 
-// Do Update UI processing for child controls
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#ifdef __GNUG__
+    #pragma implementation "windowbase.h"
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#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);
+    }
+}
+
+// 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(otherWin) )
+        m_constraintsInvolvedIn->Append(otherWin);
+}
+
+// REMOVE back-pointer to other windows we're involved with.
+void wxWindowBase::RemoveConstraintReference(wxWindowBase *otherWin)
+{
+    if ( m_constraintsInvolvedIn )
+        m_constraintsInvolvedIn->DeleteObject(otherWin);
+}
+
+// Reset any constraints that mention this window
+void wxWindowBase::DeleteRelatedConstraints()
+{
+    if ( m_constraintsInvolvedIn )
+    {
+        wxWindowList::Node *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::Node *next = node->GetNext();
+            delete node;
+            node = next;
+        }
+
+        delete m_constraintsInvolvedIn;
+        m_constraintsInvolvedIn = (wxWindowList *) NULL;
+    }
+}
+
+void wxWindowBase::SetSizer(wxSizer *sizer)
+{
+    m_windowSizer = sizer;
+    if ( sizer )
+        sizer->SetSizerParent(this);
+}
+
+bool wxWindowBase::Layout()
+{
+    if ( GetConstraints() )
+    {
+        int w, h;
+        GetClientSize(&w, &h);
+        GetConstraints()->width.SetValue(w);
+        GetConstraints()->height.SetValue(h);
+    }
+
+    // If top level (one sizer), evaluate the sizer's constraints.
+    if ( GetSizer() )
+    {
+        int noChanges;
+        GetSizer()->ResetConstraints();   // Mark all constraints as unevaluated
+        GetSizer()->LayoutPhase1(&noChanges);
+        GetSizer()->LayoutPhase2(&noChanges);
+        GetSizer()->SetConstraintSizes(); // Recursively set the real window sizes
+        return TRUE;
+    }
+    else
+    {
+        // Otherwise, evaluate child constraints
+        ResetConstraints();   // Mark all constraints as unevaluated
+        DoPhase(1);           // Just one phase need if no sizers involved
+        DoPhase(2);
+        SetConstraintSizes(); // Recursively set the real window sizes
+    }
+    return TRUE;
+}
+
+
+// Do a phase of evaluating constraints: the default behaviour. wxSizers may
+// do a similar thing, but also impose their own 'constraints' and order the
+// evaluation differently.
+bool wxWindowBase::LayoutPhase1(int *noChanges)
+{
+    wxLayoutConstraints *constr = GetConstraints();
+    if ( constr )
+    {
+        return constr->SatisfyConstraints(this, noChanges);
+    }
+    else
+        return TRUE;
+}
+
+bool wxWindowBase::LayoutPhase2(int *noChanges)
+{
+    *noChanges = 0;
+
+    // Layout children
+    DoPhase(1);
+    DoPhase(2);
+    return TRUE;
+}
+
+// Do a phase of evaluating child constraints
+bool wxWindowBase::DoPhase(int phase)
+{
+    int noIterations = 0;
+    int maxIterations = 500;
+    int noChanges = 1;
+    int noFailures = 0;
+    wxWindowList succeeded;
+    while ((noChanges > 0) && (noIterations < maxIterations))
+    {
+        noChanges = 0;
+        noFailures = 0;
+        wxWindowList::Node *node = GetChildren().GetFirst();
+        while (node)
+        {
+            wxWindow *child = node->GetData();
+            if ( !child->IsTopLevel() )
+            {
+                wxLayoutConstraints *constr = child->GetConstraints();
+                if ( constr )
+                {
+                    if ( !succeeded.Find(child) )
+                    {
+                        int tempNoChanges = 0;
+                        bool success = ( (phase == 1) ? child->LayoutPhase1(&tempNoChanges) : child->LayoutPhase2(&tempNoChanges) ) ;
+                        noChanges += tempNoChanges;
+                        if ( success )
+                        {
+                            succeeded.Append(child);
+                        }
+                    }
+                }
+            }
+            node = node->GetNext();
+        }
+
+        noIterations++;
+    }
+
+    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::Node *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->left.GetDone() && constr->right.GetDone( ) &&
+            constr->width.GetDone() && constr->height.GetDone())
+    {
+        int x = constr->left.GetValue();
+        int y = constr->top.GetValue();
+        int w = constr->width.GetValue();
+        int h = constr->height.GetValue();
+
+        // If we don't want to resize this window, just move it...
+        if ( (constr->width.GetRelationship() != wxAsIs ) ||
+                (constr->height.GetRelationship() != wxAsIs))
+        {
+            // Calls Layout() recursively. AAAGH. How can we stop that.
+            // Simply take Layout() out of non-top level OnSizes.
+            SizerSetSize(x, y, w, h);
+        }
+        else
+        {
+            SizerMove(x, y);
+        }
+    }
+    else if ( constr )
+    {
+        wxChar *windowClass = GetClassInfo()->GetClassName();
+
+        wxString winName;
+        if ( GetName() == _T("") )
+            winName = _T("unnamed");
+        else
+            winName = GetName();
+        wxLogDebug( _T("Constraint(s) not satisfied for window of type %s, name %s:\n"),
+                (const wxChar *)windowClass,
+                (const wxChar *)winName);
+        if ( !constr->left.GetDone()) wxLogDebug( _T("  unsatisfied 'left' constraint.\n")  );
+        if ( !constr->right.GetDone()) wxLogDebug( _T("  unsatisfied 'right' constraint.\n")  );
+        if ( !constr->width.GetDone()) wxLogDebug( _T("  unsatisfied 'width' constraint.\n")  );
+        if ( !constr->height.GetDone())  wxLogDebug( _T("  unsatisfied 'height' constraint.\n")  );
+        wxLogDebug( _T("Please check constraints: try adding AsIs() constraints.\n") );
+    }
+
+    if ( recurse )
+    {
+        wxWindowList::Node *node = GetChildren().GetFirst();
+        while (node)
+        {
+            wxWindow *win = node->GetData();
+            if ( !win->IsTopLevel() )
+                win->SetConstraintSizes();
+            node = node->GetNext();
+        }
+    }
+}
+
+// This assumes that all sizers are 'on' the same window, i.e. the parent of
+// this window.
+void wxWindowBase::TransformSizerToActual(int *x, int *y) const
+{
+    if ( !m_sizerParent || m_sizerParent->IsTopLevel() )
+        return;
+
+    int xp, yp;
+    m_sizerParent->GetPosition(&xp, &yp);
+    m_sizerParent->TransformSizerToActual(&xp, &yp);
+    *x += xp;
+    *y += yp;
+}
+
+void wxWindowBase::SizerSetSize(int x, int y, int w, int h)
+{
+    int xx = x;
+    int yy = y;
+    TransformSizerToActual(&xx, &yy);
+    SetSize(xx, yy, w, h);
+}
+
+void wxWindowBase::SizerMove(int x, int y)
+{
+    int xx = x;
+    int yy = y;
+    TransformSizerToActual(&xx, &yy);
+    Move(xx, yy);
+}
+
+// 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 != -1 )
+        {
+            constr->left.SetValue(x);
+            constr->left.SetDone(TRUE);
+        }
+        if ( y != -1 )
+        {
+            constr->top.SetValue(y);
+            constr->top.SetDone(TRUE);
+        }
+        if ( w != -1 )
+        {
+            constr->width.SetValue(w);
+            constr->width.SetDone(TRUE);
+        }
+        if ( h != -1 )
+        {
+            constr->height.SetValue(h);
+            constr->height.SetDone(TRUE);
+        }
+    }
+}
+
+void wxWindowBase::MoveConstraint(int x, int y)
+{
+    wxLayoutConstraints *constr = GetConstraints();
+    if ( constr )
+    {
+        if ( x != -1 )
+        {
+            constr->left.SetValue(x);
+            constr->left.SetDone(TRUE);
+        }
+        if ( y != -1 )
+        {
+            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
+
+// ----------------------------------------------------------------------------
+// do Update UI processing for child controls
+// ----------------------------------------------------------------------------
 
 // TODO: should this be implemented for the child window rather
 // than the parent? Then you can override it e.g. for wxCheckBox
 // to do the Right Thing rather than having to assume a fixed number
 // of control classes.
-#include "wx/checkbox.h"
-#include "wx/radiobut.h"
-
-void wxWindow::UpdateWindowUI()
-{
-  wxWindowID id = GetId();
-  if (id > 0)
-  {
-    wxUpdateUIEvent event(id);
-    event.m_eventObject = this;
-
-    if (this->GetEventHandler()->ProcessEvent(event))
-    {
-      if (event.GetSetEnabled())
-        this->Enable(event.GetEnabled());
-
-      if (event.GetSetText() && this->IsKindOf(CLASSINFO(wxControl)))
-        ((wxControl*)this)->SetLabel(event.GetText());
-
-      if (this->IsKindOf(CLASSINFO(wxCheckBox)))
-      {
-        if (event.GetSetChecked())
-          ((wxCheckBox *) this)->SetValue(event.GetChecked());
-      }
-      // @@@ No radio buttons in wxGTK yet
-#ifndef __WXGTK__
-      else if (this->IsKindOf(CLASSINFO(wxRadioButton)))
-      {
-        if (event.GetSetChecked())
-          ((wxRadioButton *) this)->SetValue(event.GetChecked());
-      }
-#endif
+void wxWindowBase::UpdateWindowUI()
+{
+    wxWindowID id = GetId();
+    if ( id > 0 )
+    {
+        wxUpdateUIEvent event(id);
+        event.m_eventObject = this;
+
+        if ( GetEventHandler()->ProcessEvent(event) )
+        {
+            if ( event.GetSetEnabled() )
+                Enable(event.GetEnabled());
+
+            if ( event.GetSetText() )
+            {
+                wxControl *control = wxDynamicCast(this, wxControl);
+                if ( control )
+                    control->SetLabel(event.GetText());
+            }
+
+#if wxUSE_CHECKBOX
+            wxCheckBox *checkbox = wxDynamicCast(this, wxCheckBox);
+            if ( checkbox )
+            {
+                if ( event.GetSetChecked() )
+                    checkbox->SetValue(event.GetChecked());
+            }
+#endif // wxUSE_CHECKBOX
+
+#if wxUSE_RADIOBUTTON
+            wxRadioButton *radiobtn = wxDynamicCast(this, wxRadioButton);
+            if ( radiobtn )
+            {
+                if ( event.GetSetChecked() )
+                    radiobtn->SetValue(event.GetChecked());
+            }
+#endif // wxUSE_RADIOBUTTON
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+// dialog units translations
+// ----------------------------------------------------------------------------
+
+wxPoint wxWindowBase::ConvertPixelsToDialog(const wxPoint& pt)
+{
+    int charWidth = GetCharWidth();
+    int charHeight = GetCharHeight();
+    wxPoint pt2;
+    pt2.x = (int) ((pt.x * 4) / charWidth) ;
+    pt2.y = (int) ((pt.y * 8) / charHeight) ;
+
+    return pt2;
+}
+
+wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt)
+{
+    int charWidth = GetCharWidth();
+    int charHeight = GetCharHeight();
+    wxPoint pt2;
+    pt2.x = (int) ((pt.x * charWidth) / 4) ;
+    pt2.y = (int) ((pt.y * charHeight) / 8) ;
+
+    return pt2;
+}
+
+// ----------------------------------------------------------------------------
+// event handlers
+// ----------------------------------------------------------------------------
+
+// propagate the colour change event to the subwindows
+void wxWindowBase::OnSysColourChanged(wxSysColourChangedEvent& event)
+{
+    wxWindowList::Node *node = GetChildren().GetFirst();
+    while ( node )
+    {
+        // Only propagate to non-top-level windows
+        wxWindow *win = node->GetData();
+        if ( !win->IsTopLevel() )
+        {
+            wxSysColourChangedEvent event2;
+            event.m_eventObject = win;
+            win->GetEventHandler()->ProcessEvent(event2);
+        }
+
+        node = node->GetNext();
     }
-  }
 }
+
+// the default action is to populate dialog with data when it's created
+void wxWindowBase::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) )
+{
+    TransferDataToWindow();
+}
+
+// ----------------------------------------------------------------------------
+// list classes implementation
+// ----------------------------------------------------------------------------
+
+void wxWindowListNode::DeleteData()
+{
+    delete (wxWindow *)GetData();
+}
+