1 /////////////////////////////////////////////////////////////////////////////
2 // Name: common/window.cpp
3 // Purpose: common (to all ports) wxWindow functions
4 // Author: Julian Smart, Vadim Zeitlin
8 // Copyright: (c) wxWindows team
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "windowbase.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
32 #include "wx/string.h"
37 #include "wx/window.h"
38 #include "wx/checkbox.h"
39 #include "wx/radiobut.h"
40 #include "wx/textctrl.h"
41 #include "wx/settings.h"
42 #include "wx/dialog.h"
43 #include "wx/msgdlg.h"
44 #include "wx/statusbr.h"
48 #include "wx/layout.h"
50 #endif // wxUSE_CONSTRAINTS
52 #if wxUSE_DRAG_AND_DROP
54 #endif // wxUSE_DRAG_AND_DROP
57 #include "wx/cshelp.h"
61 #include "wx/tooltip.h"
62 #endif // wxUSE_TOOLTIPS
68 // ----------------------------------------------------------------------------
70 // ----------------------------------------------------------------------------
72 int wxWindowBase::ms_lastControlId
= -200;
74 IMPLEMENT_ABSTRACT_CLASS(wxWindowBase
, wxEvtHandler
)
76 // ----------------------------------------------------------------------------
78 // ----------------------------------------------------------------------------
80 BEGIN_EVENT_TABLE(wxWindowBase
, wxEvtHandler
)
81 EVT_SYS_COLOUR_CHANGED(wxWindowBase::OnSysColourChanged
)
82 EVT_INIT_DIALOG(wxWindowBase::OnInitDialog
)
83 EVT_MIDDLE_DOWN(wxWindowBase::OnMiddleClick
)
86 EVT_HELP(-1, wxWindowBase::OnHelp
)
91 // ============================================================================
92 // implementation of the common functionality of the wxWindow class
93 // ============================================================================
95 // ----------------------------------------------------------------------------
97 // ----------------------------------------------------------------------------
99 // the default initialization
100 void wxWindowBase::InitBase()
102 // no window yet, no parent nor children
103 m_parent
= (wxWindow
*)NULL
;
105 m_children
.DeleteContents( FALSE
); // don't auto delete node data
107 // no constraints on the minimal window size
113 // window is created enabled but it's not visible yet
117 // no client data (yet)
119 m_clientDataType
= ClientData_None
;
121 // the default event handler is just this window
122 m_eventHandler
= this;
126 m_windowValidator
= (wxValidator
*) NULL
;
127 #endif // wxUSE_VALIDATORS
129 // use the system default colours
130 m_backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE
);
131 m_foregroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT
);
133 // don't set the font here for wxMSW as we don't call WM_SETFONT here and
134 // so the font is *not* really set - but calls to SetFont() later won't do
135 // anything because m_font appears to be already set!
137 m_font
= wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
);
144 // an optimization for the event processing: checking this flag is much
145 // faster than using IsKindOf(CLASSINFO(wxWindow))
148 #if wxUSE_CONSTRAINTS
149 // no constraints whatsoever
150 m_constraints
= (wxLayoutConstraints
*) NULL
;
151 m_constraintsInvolvedIn
= (wxWindowList
*) NULL
;
152 m_windowSizer
= (wxSizer
*) NULL
;
153 m_autoLayout
= FALSE
;
154 #endif // wxUSE_CONSTRAINTS
156 #if wxUSE_DRAG_AND_DROP
157 m_dropTarget
= (wxDropTarget
*)NULL
;
158 #endif // wxUSE_DRAG_AND_DROP
161 m_tooltip
= (wxToolTip
*)NULL
;
162 #endif // wxUSE_TOOLTIPS
165 m_caret
= (wxCaret
*)NULL
;
166 #endif // wxUSE_CARET
168 // Whether we're using the current theme for this window (wxGTK only for now)
169 m_themeEnabled
= FALSE
;
172 // common part of window creation process
173 bool wxWindowBase::CreateBase(wxWindowBase
*parent
,
175 const wxPoint
& WXUNUSED(pos
),
176 const wxSize
& WXUNUSED(size
),
178 const wxValidator
& validator
,
179 const wxString
& name
)
181 // m_isWindow is set to TRUE in wxWindowBase::Init() as well as many other
182 // member variables - check that it has been called (will catch the case
183 // when a new ctor is added which doesn't call InitWindow)
184 wxASSERT_MSG( m_isWindow
, wxT("Init() must have been called before!") );
186 // generate a new id if the user doesn't care about it
187 m_windowId
= id
== -1 ? NewControlId() : id
;
190 SetWindowStyleFlag(style
);
194 SetValidator(validator
);
195 #endif // wxUSE_VALIDATORS
197 // if the parent window has wxWS_EX_VALIDATE_RECURSIVELY set, we want to
198 // have it too - like this it's possible to set it only in the top level
199 // dialog/frame and all children will inherit it by defult
200 if ( parent
&& (parent
->GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY
) )
202 SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY
);
208 // ----------------------------------------------------------------------------
210 // ----------------------------------------------------------------------------
213 wxWindowBase::~wxWindowBase()
215 // FIXME if these 2 cases result from programming errors in the user code
216 // we should probably assert here instead of silently fixing them
218 // Just in case the window has been Closed, but we're then deleting
219 // immediately: don't leave dangling pointers.
220 wxPendingDelete
.DeleteObject(this);
222 // Just in case we've loaded a top-level window via LoadNativeDialog but
223 // we weren't a dialog class
224 wxTopLevelWindows
.DeleteObject(this);
226 wxASSERT_MSG( GetChildren().GetCount() == 0, wxT("children not destroyed") );
228 // make sure that there are no dangling pointers left pointing to us
229 wxPanel
*panel
= wxDynamicCast(GetParent(), wxPanel
);
232 if ( panel
->GetLastFocus() == this )
234 panel
->SetLastFocus((wxWindow
*)NULL
);
241 #endif // wxUSE_CARET
244 if ( m_windowValidator
)
245 delete m_windowValidator
;
246 #endif // wxUSE_VALIDATORS
248 // we only delete object data, not untyped
249 if ( m_clientDataType
== ClientData_Object
)
250 delete m_clientObject
;
252 #if wxUSE_CONSTRAINTS
253 // Have to delete constraints/sizer FIRST otherwise sizers may try to look
254 // at deleted windows as they delete themselves.
255 DeleteRelatedConstraints();
259 // This removes any dangling pointers to this window in other windows'
260 // constraintsInvolvedIn lists.
261 UnsetConstraints(m_constraints
);
262 delete m_constraints
;
263 m_constraints
= NULL
;
267 delete m_windowSizer
;
269 #endif // wxUSE_CONSTRAINTS
271 #if wxUSE_DRAG_AND_DROP
274 #endif // wxUSE_DRAG_AND_DROP
279 #endif // wxUSE_TOOLTIPS
282 bool wxWindowBase::Destroy()
289 bool wxWindowBase::Close(bool force
)
291 wxCloseEvent
event(wxEVT_CLOSE_WINDOW
, m_windowId
);
292 event
.SetEventObject(this);
293 #if WXWIN_COMPATIBILITY
294 event
.SetForce(force
);
295 #endif // WXWIN_COMPATIBILITY
296 event
.SetCanVeto(!force
);
298 // return FALSE if window wasn't closed because the application vetoed the
300 return GetEventHandler()->ProcessEvent(event
) && !event
.GetVeto();
303 bool wxWindowBase::DestroyChildren()
305 wxWindowList::Node
*node
;
308 // we iterate until the list becomes empty
309 node
= GetChildren().GetFirst();
313 wxWindow
*child
= node
->GetData();
315 wxASSERT_MSG( child
, wxT("children list contains empty nodes") );
319 wxASSERT_MSG( !GetChildren().Find(child
),
320 wxT("child didn't remove itself using RemoveChild()") );
326 // ----------------------------------------------------------------------------
327 // size/position related methods
328 // ----------------------------------------------------------------------------
330 // centre the window with respect to its parent in either (or both) directions
331 void wxWindowBase::Centre(int direction
)
333 // the position/size of the parent window or of the entire screen
335 int widthParent
, heightParent
;
337 wxWindow
*parent
= NULL
;
339 if ( !(direction
& wxCENTRE_ON_SCREEN
) )
341 // find the parent to centre this window on: it should be the
342 // immediate parent for the controls but the top level parent for the
343 // top level windows (like dialogs)
344 parent
= GetParent();
347 while ( parent
&& !parent
->IsTopLevel() )
349 parent
= parent
->GetParent();
353 // did we find the parent?
357 direction
|= wxCENTRE_ON_SCREEN
;
361 if ( direction
& wxCENTRE_ON_SCREEN
)
363 // centre with respect to the whole screen
364 wxDisplaySize(&widthParent
, &heightParent
);
370 // centre on the parent
371 parent
->GetSize(&widthParent
, &heightParent
);
373 // adjust to the parents position
374 posParent
= parent
->GetPosition();
378 // centre inside the parents client rectangle
379 parent
->GetClientSize(&widthParent
, &heightParent
);
384 GetSize(&width
, &height
);
389 if ( direction
& wxHORIZONTAL
)
390 xNew
= (widthParent
- width
)/2;
392 if ( direction
& wxVERTICAL
)
393 yNew
= (heightParent
- height
)/2;
398 // move the window to this position (keeping the old size but using
399 // SetSize() and not Move() to allow xNew and/or yNew to be -1)
400 SetSize(xNew
, yNew
, width
, height
, wxSIZE_ALLOW_MINUS_ONE
);
403 // fits the window around the children
404 void wxWindowBase::Fit()
406 if ( GetChildren().GetCount() > 0 )
408 wxSize size
= DoGetBestSize();
410 // for compatibility with the old versions and because it really looks
411 // slightly more pretty like this, add a pad
417 //else: do nothing if we have no children
420 // return the size best suited for the current window
421 wxSize
wxWindowBase::DoGetBestSize() const
423 if ( GetChildren().GetCount() > 0 )
425 // our minimal acceptable size is such that all our windows fit inside
429 for ( wxWindowList::Node
*node
= GetChildren().GetFirst();
431 node
= node
->GetNext() )
433 wxWindow
*win
= node
->GetData();
434 if ( win
->IsTopLevel() || wxDynamicCast(win
, wxStatusBar
) || !win
->IsShown())
436 // dialogs and frames lie in different top level windows -
437 // don't deal with them here; as for the status bars, they
438 // don't lie in the client area at all
443 win
->GetPosition(&wx
, &wy
);
445 // if the window hadn't been positioned yet, assume that it is in
452 win
->GetSize(&ww
, &wh
);
453 if ( wx
+ ww
> maxX
)
455 if ( wy
+ wh
> maxY
)
459 return wxSize(maxX
, maxY
);
463 // for a generic window there is no natural best size - just use the
469 // set the min/max size of the window
470 void wxWindowBase::SetSizeHints(int minW
, int minH
,
472 int WXUNUSED(incW
), int WXUNUSED(incH
))
480 // ----------------------------------------------------------------------------
481 // show/hide/enable/disable the window
482 // ----------------------------------------------------------------------------
484 bool wxWindowBase::Show(bool show
)
486 if ( show
!= m_isShown
)
498 bool wxWindowBase::Enable(bool enable
)
500 if ( enable
!= m_isEnabled
)
502 m_isEnabled
= enable
;
511 // ----------------------------------------------------------------------------
513 // ----------------------------------------------------------------------------
515 bool wxWindowBase::IsTopLevel() const
520 // ----------------------------------------------------------------------------
521 // reparenting the window
522 // ----------------------------------------------------------------------------
524 void wxWindowBase::AddChild(wxWindowBase
*child
)
526 wxCHECK_RET( child
, wxT("can't add a NULL child") );
528 // this should never happen and it will lead to a crash later if it does
529 // because RemoveChild() will remove only one node from the children list
530 // and the other(s) one(s) will be left with dangling pointers in them
531 wxASSERT_MSG( !GetChildren().Find(child
), _T("AddChild() called twice") );
533 GetChildren().Append(child
);
534 child
->SetParent(this);
537 void wxWindowBase::RemoveChild(wxWindowBase
*child
)
539 wxCHECK_RET( child
, wxT("can't remove a NULL child") );
541 GetChildren().DeleteObject(child
);
542 child
->SetParent((wxWindow
*)NULL
);
545 bool wxWindowBase::Reparent(wxWindowBase
*newParent
)
547 wxWindow
*oldParent
= GetParent();
548 if ( newParent
== oldParent
)
554 // unlink this window from the existing parent.
557 oldParent
->RemoveChild(this);
561 wxTopLevelWindows
.DeleteObject(this);
564 // add it to the new one
567 newParent
->AddChild(this);
571 wxTopLevelWindows
.Append(this);
577 // ----------------------------------------------------------------------------
578 // event handler stuff
579 // ----------------------------------------------------------------------------
581 void wxWindowBase::PushEventHandler(wxEvtHandler
*handler
)
583 handler
->SetNextHandler(GetEventHandler());
584 SetEventHandler(handler
);
587 wxEvtHandler
*wxWindowBase::PopEventHandler(bool deleteHandler
)
589 wxEvtHandler
*handlerA
= GetEventHandler();
592 wxEvtHandler
*handlerB
= handlerA
->GetNextHandler();
593 handlerA
->SetNextHandler((wxEvtHandler
*)NULL
);
594 SetEventHandler(handlerB
);
598 handlerA
= (wxEvtHandler
*)NULL
;
605 // ----------------------------------------------------------------------------
607 // ----------------------------------------------------------------------------
609 bool wxWindowBase::SetBackgroundColour( const wxColour
&colour
)
611 if ( !colour
.Ok() || (colour
== m_backgroundColour
) )
614 m_backgroundColour
= colour
;
619 bool wxWindowBase::SetForegroundColour( const wxColour
&colour
)
621 if ( !colour
.Ok() || (colour
== m_foregroundColour
) )
624 m_foregroundColour
= colour
;
629 bool wxWindowBase::SetCursor(const wxCursor
& cursor
)
631 // setting an invalid cursor is ok, it means that we don't have any special
633 if ( m_cursor
== cursor
)
644 bool wxWindowBase::SetFont(const wxFont
& font
)
646 // don't try to set invalid font, always fall back to the default
647 const wxFont
& fontOk
= font
.Ok() ? font
: *wxSWISS_FONT
;
649 if ( fontOk
== m_font
)
661 void wxWindowBase::SetCaret(wxCaret
*caret
)
672 wxASSERT_MSG( m_caret
->GetWindow() == this,
673 wxT("caret should be created associated to this window") );
676 #endif // wxUSE_CARET
679 // ----------------------------------------------------------------------------
681 // ----------------------------------------------------------------------------
683 void wxWindowBase::SetValidator(const wxValidator
& validator
)
685 if ( m_windowValidator
)
686 delete m_windowValidator
;
688 m_windowValidator
= (wxValidator
*)validator
.Clone();
690 if ( m_windowValidator
)
691 m_windowValidator
->SetWindow(this) ;
693 #endif // wxUSE_VALIDATORS
695 // ----------------------------------------------------------------------------
696 // update region testing
697 // ----------------------------------------------------------------------------
699 bool wxWindowBase::IsExposed(int x
, int y
) const
701 return m_updateRegion
.Contains(x
, y
) != wxOutRegion
;
704 bool wxWindowBase::IsExposed(int x
, int y
, int w
, int h
) const
706 return m_updateRegion
.Contains(x
, y
, w
, h
) != wxOutRegion
;
709 // ----------------------------------------------------------------------------
710 // find window by id or name
711 // ----------------------------------------------------------------------------
713 wxWindow
*wxWindowBase::FindWindow( long id
)
715 if ( id
== m_windowId
)
716 return (wxWindow
*)this;
718 wxWindowBase
*res
= (wxWindow
*)NULL
;
719 wxWindowList::Node
*node
;
720 for ( node
= m_children
.GetFirst(); node
&& !res
; node
= node
->GetNext() )
722 wxWindowBase
*child
= node
->GetData();
723 res
= child
->FindWindow( id
);
726 return (wxWindow
*)res
;
729 wxWindow
*wxWindowBase::FindWindow( const wxString
& name
)
731 if ( name
== m_windowName
)
732 return (wxWindow
*)this;
734 wxWindowBase
*res
= (wxWindow
*)NULL
;
735 wxWindowList::Node
*node
;
736 for ( node
= m_children
.GetFirst(); node
&& !res
; node
= node
->GetNext() )
738 wxWindow
*child
= node
->GetData();
739 res
= child
->FindWindow(name
);
742 return (wxWindow
*)res
;
745 // ----------------------------------------------------------------------------
746 // dialog oriented functions
747 // ----------------------------------------------------------------------------
749 void wxWindowBase::MakeModal(bool modal
)
751 // Disable all other windows
754 wxWindowList::Node
*node
= wxTopLevelWindows
.GetFirst();
757 wxWindow
*win
= node
->GetData();
761 node
= node
->GetNext();
766 bool wxWindowBase::Validate()
769 bool recurse
= (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY
) != 0;
771 wxWindowList::Node
*node
;
772 for ( node
= m_children
.GetFirst(); node
; node
= node
->GetNext() )
774 wxWindowBase
*child
= node
->GetData();
775 wxValidator
*validator
= child
->GetValidator();
776 if ( validator
&& !validator
->Validate((wxWindow
*)this) )
781 if ( recurse
&& !child
->Validate() )
786 #endif // wxUSE_VALIDATORS
791 bool wxWindowBase::TransferDataToWindow()
794 bool recurse
= (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY
) != 0;
796 wxWindowList::Node
*node
;
797 for ( node
= m_children
.GetFirst(); node
; node
= node
->GetNext() )
799 wxWindowBase
*child
= node
->GetData();
800 wxValidator
*validator
= child
->GetValidator();
801 if ( validator
&& !validator
->TransferToWindow() )
803 wxLogWarning(_("Could not transfer data to window"));
804 wxLog::FlushActive();
811 if ( !child
->TransferDataToWindow() )
813 // warning already given
818 #endif // wxUSE_VALIDATORS
823 bool wxWindowBase::TransferDataFromWindow()
826 bool recurse
= (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY
) != 0;
828 wxWindowList::Node
*node
;
829 for ( node
= m_children
.GetFirst(); node
; node
= node
->GetNext() )
831 wxWindow
*child
= node
->GetData();
832 wxValidator
*validator
= child
->GetValidator();
833 if ( validator
&& !validator
->TransferFromWindow() )
835 // nop warning here because the application is supposed to give
836 // one itself - we don't know here what might have gone wrongly
843 if ( !child
->TransferDataFromWindow() )
845 // warning already given
850 #endif // wxUSE_VALIDATORS
855 void wxWindowBase::InitDialog()
857 wxInitDialogEvent
event(GetId());
858 event
.SetEventObject( this );
859 GetEventHandler()->ProcessEvent(event
);
862 // ----------------------------------------------------------------------------
863 // context-sensitive help support
864 // ----------------------------------------------------------------------------
868 // associate this help text with this window
869 void wxWindowBase::SetHelpText(const wxString
& text
)
871 wxHelpProvider
*helpProvider
= wxHelpProvider::Get();
874 helpProvider
->AddHelp(this, text
);
878 // associate this help text with all windows with the same id as this
880 void wxWindowBase::SetHelpTextForId(const wxString
& text
)
882 wxHelpProvider
*helpProvider
= wxHelpProvider::Get();
885 helpProvider
->AddHelp(GetId(), text
);
889 // get the help string associated with this window (may be empty)
890 wxString
wxWindowBase::GetHelpText() const
893 wxHelpProvider
*helpProvider
= wxHelpProvider::Get();
896 text
= helpProvider
->GetHelp(this);
902 // show help for this window
903 void wxWindowBase::OnHelp(wxHelpEvent
& event
)
905 wxHelpProvider
*helpProvider
= wxHelpProvider::Get();
908 if ( helpProvider
->ShowHelp(this) )
910 // skip the event.Skip() below
920 // ----------------------------------------------------------------------------
922 // ----------------------------------------------------------------------------
926 void wxWindowBase::SetToolTip( const wxString
&tip
)
928 // don't create the new tooltip if we already have one
931 m_tooltip
->SetTip( tip
);
935 SetToolTip( new wxToolTip( tip
) );
938 // setting empty tooltip text does not remove the tooltip any more - use
939 // SetToolTip((wxToolTip *)NULL) for this
942 void wxWindowBase::DoSetToolTip(wxToolTip
*tooltip
)
950 #endif // wxUSE_TOOLTIPS
952 // ----------------------------------------------------------------------------
953 // constraints and sizers
954 // ----------------------------------------------------------------------------
956 #if wxUSE_CONSTRAINTS
958 void wxWindowBase::SetConstraints( wxLayoutConstraints
*constraints
)
962 UnsetConstraints(m_constraints
);
963 delete m_constraints
;
965 m_constraints
= constraints
;
968 // Make sure other windows know they're part of a 'meaningful relationship'
969 if ( m_constraints
->left
.GetOtherWindow() && (m_constraints
->left
.GetOtherWindow() != this) )
970 m_constraints
->left
.GetOtherWindow()->AddConstraintReference(this);
971 if ( m_constraints
->top
.GetOtherWindow() && (m_constraints
->top
.GetOtherWindow() != this) )
972 m_constraints
->top
.GetOtherWindow()->AddConstraintReference(this);
973 if ( m_constraints
->right
.GetOtherWindow() && (m_constraints
->right
.GetOtherWindow() != this) )
974 m_constraints
->right
.GetOtherWindow()->AddConstraintReference(this);
975 if ( m_constraints
->bottom
.GetOtherWindow() && (m_constraints
->bottom
.GetOtherWindow() != this) )
976 m_constraints
->bottom
.GetOtherWindow()->AddConstraintReference(this);
977 if ( m_constraints
->width
.GetOtherWindow() && (m_constraints
->width
.GetOtherWindow() != this) )
978 m_constraints
->width
.GetOtherWindow()->AddConstraintReference(this);
979 if ( m_constraints
->height
.GetOtherWindow() && (m_constraints
->height
.GetOtherWindow() != this) )
980 m_constraints
->height
.GetOtherWindow()->AddConstraintReference(this);
981 if ( m_constraints
->centreX
.GetOtherWindow() && (m_constraints
->centreX
.GetOtherWindow() != this) )
982 m_constraints
->centreX
.GetOtherWindow()->AddConstraintReference(this);
983 if ( m_constraints
->centreY
.GetOtherWindow() && (m_constraints
->centreY
.GetOtherWindow() != this) )
984 m_constraints
->centreY
.GetOtherWindow()->AddConstraintReference(this);
988 // This removes any dangling pointers to this window in other windows'
989 // constraintsInvolvedIn lists.
990 void wxWindowBase::UnsetConstraints(wxLayoutConstraints
*c
)
994 if ( c
->left
.GetOtherWindow() && (c
->top
.GetOtherWindow() != this) )
995 c
->left
.GetOtherWindow()->RemoveConstraintReference(this);
996 if ( c
->top
.GetOtherWindow() && (c
->top
.GetOtherWindow() != this) )
997 c
->top
.GetOtherWindow()->RemoveConstraintReference(this);
998 if ( c
->right
.GetOtherWindow() && (c
->right
.GetOtherWindow() != this) )
999 c
->right
.GetOtherWindow()->RemoveConstraintReference(this);
1000 if ( c
->bottom
.GetOtherWindow() && (c
->bottom
.GetOtherWindow() != this) )
1001 c
->bottom
.GetOtherWindow()->RemoveConstraintReference(this);
1002 if ( c
->width
.GetOtherWindow() && (c
->width
.GetOtherWindow() != this) )
1003 c
->width
.GetOtherWindow()->RemoveConstraintReference(this);
1004 if ( c
->height
.GetOtherWindow() && (c
->height
.GetOtherWindow() != this) )
1005 c
->height
.GetOtherWindow()->RemoveConstraintReference(this);
1006 if ( c
->centreX
.GetOtherWindow() && (c
->centreX
.GetOtherWindow() != this) )
1007 c
->centreX
.GetOtherWindow()->RemoveConstraintReference(this);
1008 if ( c
->centreY
.GetOtherWindow() && (c
->centreY
.GetOtherWindow() != this) )
1009 c
->centreY
.GetOtherWindow()->RemoveConstraintReference(this);
1013 // Back-pointer to other windows we're involved with, so if we delete this
1014 // window, we must delete any constraints we're involved with.
1015 void wxWindowBase::AddConstraintReference(wxWindowBase
*otherWin
)
1017 if ( !m_constraintsInvolvedIn
)
1018 m_constraintsInvolvedIn
= new wxWindowList
;
1019 if ( !m_constraintsInvolvedIn
->Find(otherWin
) )
1020 m_constraintsInvolvedIn
->Append(otherWin
);
1023 // REMOVE back-pointer to other windows we're involved with.
1024 void wxWindowBase::RemoveConstraintReference(wxWindowBase
*otherWin
)
1026 if ( m_constraintsInvolvedIn
)
1027 m_constraintsInvolvedIn
->DeleteObject(otherWin
);
1030 // Reset any constraints that mention this window
1031 void wxWindowBase::DeleteRelatedConstraints()
1033 if ( m_constraintsInvolvedIn
)
1035 wxWindowList::Node
*node
= m_constraintsInvolvedIn
->GetFirst();
1038 wxWindow
*win
= node
->GetData();
1039 wxLayoutConstraints
*constr
= win
->GetConstraints();
1041 // Reset any constraints involving this window
1044 constr
->left
.ResetIfWin(this);
1045 constr
->top
.ResetIfWin(this);
1046 constr
->right
.ResetIfWin(this);
1047 constr
->bottom
.ResetIfWin(this);
1048 constr
->width
.ResetIfWin(this);
1049 constr
->height
.ResetIfWin(this);
1050 constr
->centreX
.ResetIfWin(this);
1051 constr
->centreY
.ResetIfWin(this);
1054 wxWindowList::Node
*next
= node
->GetNext();
1059 delete m_constraintsInvolvedIn
;
1060 m_constraintsInvolvedIn
= (wxWindowList
*) NULL
;
1064 void wxWindowBase::SetSizer(wxSizer
*sizer
)
1066 if (m_windowSizer
) delete m_windowSizer
;
1068 m_windowSizer
= sizer
;
1071 bool wxWindowBase::Layout()
1073 // If there is a sizer, use it instead of the constraints
1077 GetClientSize(&w
, &h
);
1079 GetSizer()->SetDimension( 0, 0, w
, h
);
1083 wxLayoutConstraints
*constr
= GetConstraints();
1084 bool wasOk
= constr
&& constr
->AreSatisfied();
1086 ResetConstraints(); // Mark all constraints as unevaluated
1088 // if we're a top level panel (i.e. our parent is frame/dialog), our
1089 // own constraints will never be satisfied any more unless we do it
1094 while ( noChanges
> 0 )
1096 constr
->SatisfyConstraints(this, &noChanges
);
1100 DoPhase(1); // Layout children
1101 DoPhase(2); // Layout grand children
1102 SetConstraintSizes(); // Recursively set the real window sizes
1109 // Do a phase of evaluating constraints: the default behaviour. wxSizers may
1110 // do a similar thing, but also impose their own 'constraints' and order the
1111 // evaluation differently.
1112 bool wxWindowBase::LayoutPhase1(int *noChanges
)
1114 wxLayoutConstraints
*constr
= GetConstraints();
1117 return constr
->SatisfyConstraints(this, noChanges
);
1123 bool wxWindowBase::LayoutPhase2(int *noChanges
)
1133 // Do a phase of evaluating child constraints
1134 bool wxWindowBase::DoPhase(int phase
)
1136 int noIterations
= 0;
1137 int maxIterations
= 500;
1140 wxWindowList succeeded
;
1141 while ((noChanges
> 0) && (noIterations
< maxIterations
))
1145 wxWindowList::Node
*node
= GetChildren().GetFirst();
1148 wxWindow
*child
= node
->GetData();
1149 if ( !child
->IsTopLevel() )
1151 wxLayoutConstraints
*constr
= child
->GetConstraints();
1154 if ( !succeeded
.Find(child
) )
1156 int tempNoChanges
= 0;
1157 bool success
= ( (phase
== 1) ? child
->LayoutPhase1(&tempNoChanges
) : child
->LayoutPhase2(&tempNoChanges
) ) ;
1158 noChanges
+= tempNoChanges
;
1161 succeeded
.Append(child
);
1166 node
= node
->GetNext();
1175 void wxWindowBase::ResetConstraints()
1177 wxLayoutConstraints
*constr
= GetConstraints();
1180 constr
->left
.SetDone(FALSE
);
1181 constr
->top
.SetDone(FALSE
);
1182 constr
->right
.SetDone(FALSE
);
1183 constr
->bottom
.SetDone(FALSE
);
1184 constr
->width
.SetDone(FALSE
);
1185 constr
->height
.SetDone(FALSE
);
1186 constr
->centreX
.SetDone(FALSE
);
1187 constr
->centreY
.SetDone(FALSE
);
1190 wxWindowList::Node
*node
= GetChildren().GetFirst();
1193 wxWindow
*win
= node
->GetData();
1194 if ( !win
->IsTopLevel() )
1195 win
->ResetConstraints();
1196 node
= node
->GetNext();
1200 // Need to distinguish between setting the 'fake' size for windows and sizers,
1201 // and setting the real values.
1202 void wxWindowBase::SetConstraintSizes(bool recurse
)
1204 wxLayoutConstraints
*constr
= GetConstraints();
1205 if ( constr
&& constr
->AreSatisfied() )
1207 int x
= constr
->left
.GetValue();
1208 int y
= constr
->top
.GetValue();
1209 int w
= constr
->width
.GetValue();
1210 int h
= constr
->height
.GetValue();
1212 if ( (constr
->width
.GetRelationship() != wxAsIs
) ||
1213 (constr
->height
.GetRelationship() != wxAsIs
) )
1215 SetSize(x
, y
, w
, h
);
1219 // If we don't want to resize this window, just move it...
1225 wxLogDebug(wxT("Constraints not satisfied for %s named '%s'."),
1226 GetClassInfo()->GetClassName(),
1232 wxWindowList::Node
*node
= GetChildren().GetFirst();
1235 wxWindow
*win
= node
->GetData();
1236 if ( !win
->IsTopLevel() )
1237 win
->SetConstraintSizes();
1238 node
= node
->GetNext();
1243 // Only set the size/position of the constraint (if any)
1244 void wxWindowBase::SetSizeConstraint(int x
, int y
, int w
, int h
)
1246 wxLayoutConstraints
*constr
= GetConstraints();
1251 constr
->left
.SetValue(x
);
1252 constr
->left
.SetDone(TRUE
);
1256 constr
->top
.SetValue(y
);
1257 constr
->top
.SetDone(TRUE
);
1261 constr
->width
.SetValue(w
);
1262 constr
->width
.SetDone(TRUE
);
1266 constr
->height
.SetValue(h
);
1267 constr
->height
.SetDone(TRUE
);
1272 void wxWindowBase::MoveConstraint(int x
, int y
)
1274 wxLayoutConstraints
*constr
= GetConstraints();
1279 constr
->left
.SetValue(x
);
1280 constr
->left
.SetDone(TRUE
);
1284 constr
->top
.SetValue(y
);
1285 constr
->top
.SetDone(TRUE
);
1290 void wxWindowBase::GetSizeConstraint(int *w
, int *h
) const
1292 wxLayoutConstraints
*constr
= GetConstraints();
1295 *w
= constr
->width
.GetValue();
1296 *h
= constr
->height
.GetValue();
1302 void wxWindowBase::GetClientSizeConstraint(int *w
, int *h
) const
1304 wxLayoutConstraints
*constr
= GetConstraints();
1307 *w
= constr
->width
.GetValue();
1308 *h
= constr
->height
.GetValue();
1311 GetClientSize(w
, h
);
1314 void wxWindowBase::GetPositionConstraint(int *x
, int *y
) const
1316 wxLayoutConstraints
*constr
= GetConstraints();
1319 *x
= constr
->left
.GetValue();
1320 *y
= constr
->top
.GetValue();
1326 #endif // wxUSE_CONSTRAINTS
1328 // ----------------------------------------------------------------------------
1329 // do Update UI processing for child controls
1330 // ----------------------------------------------------------------------------
1332 // TODO: should this be implemented for the child window rather
1333 // than the parent? Then you can override it e.g. for wxCheckBox
1334 // to do the Right Thing rather than having to assume a fixed number
1335 // of control classes.
1336 void wxWindowBase::UpdateWindowUI()
1338 wxUpdateUIEvent
event(GetId());
1339 event
.m_eventObject
= this;
1341 if ( GetEventHandler()->ProcessEvent(event
) )
1343 if ( event
.GetSetEnabled() )
1344 Enable(event
.GetEnabled());
1346 if ( event
.GetSetText() )
1348 wxControl
*control
= wxDynamicCast(this, wxControl
);
1351 wxTextCtrl
*text
= wxDynamicCast(control
, wxTextCtrl
);
1353 text
->SetValue(event
.GetText());
1355 control
->SetLabel(event
.GetText());
1360 wxCheckBox
*checkbox
= wxDynamicCast(this, wxCheckBox
);
1363 if ( event
.GetSetChecked() )
1364 checkbox
->SetValue(event
.GetChecked());
1366 #endif // wxUSE_CHECKBOX
1369 wxRadioButton
*radiobtn
= wxDynamicCast(this, wxRadioButton
);
1372 if ( event
.GetSetChecked() )
1373 radiobtn
->SetValue(event
.GetChecked());
1375 #endif // wxUSE_RADIOBTN
1379 // ----------------------------------------------------------------------------
1380 // dialog units translations
1381 // ----------------------------------------------------------------------------
1383 wxPoint
wxWindowBase::ConvertPixelsToDialog(const wxPoint
& pt
)
1385 int charWidth
= GetCharWidth();
1386 int charHeight
= GetCharHeight();
1387 wxPoint
pt2(-1, -1);
1389 pt2
.x
= (int) ((pt
.x
* 4) / charWidth
) ;
1391 pt2
.y
= (int) ((pt
.y
* 8) / charHeight
) ;
1396 wxPoint
wxWindowBase::ConvertDialogToPixels(const wxPoint
& pt
)
1398 int charWidth
= GetCharWidth();
1399 int charHeight
= GetCharHeight();
1400 wxPoint
pt2(-1, -1);
1402 pt2
.x
= (int) ((pt
.x
* charWidth
) / 4) ;
1404 pt2
.y
= (int) ((pt
.y
* charHeight
) / 8) ;
1409 // ----------------------------------------------------------------------------
1411 // ----------------------------------------------------------------------------
1413 void wxWindowBase::DoSetClientObject( wxClientData
*data
)
1415 wxASSERT_MSG( m_clientDataType
!= ClientData_Void
,
1416 wxT("can't have both object and void client data") );
1418 if ( m_clientObject
)
1419 delete m_clientObject
;
1421 m_clientObject
= data
;
1422 m_clientDataType
= ClientData_Object
;
1425 wxClientData
*wxWindowBase::DoGetClientObject() const
1427 // it's not an error to call GetClientObject() on a window which doesn't
1428 // have client data at all - NULL will be returned
1429 wxASSERT_MSG( m_clientDataType
!= ClientData_Void
,
1430 wxT("this window doesn't have object client data") );
1432 return m_clientObject
;
1435 void wxWindowBase::DoSetClientData( void *data
)
1437 wxASSERT_MSG( m_clientDataType
!= ClientData_Object
,
1438 wxT("can't have both object and void client data") );
1440 m_clientData
= data
;
1441 m_clientDataType
= ClientData_Void
;
1444 void *wxWindowBase::DoGetClientData() const
1446 // it's not an error to call GetClientData() on a window which doesn't have
1447 // client data at all - NULL will be returned
1448 wxASSERT_MSG( m_clientDataType
!= ClientData_Object
,
1449 wxT("this window doesn't have void client data") );
1451 return m_clientData
;
1454 // ----------------------------------------------------------------------------
1456 // ----------------------------------------------------------------------------
1458 // propagate the colour change event to the subwindows
1459 void wxWindowBase::OnSysColourChanged(wxSysColourChangedEvent
& event
)
1461 wxWindowList::Node
*node
= GetChildren().GetFirst();
1464 // Only propagate to non-top-level windows
1465 wxWindow
*win
= node
->GetData();
1466 if ( !win
->IsTopLevel() )
1468 wxSysColourChangedEvent event2
;
1469 event
.m_eventObject
= win
;
1470 win
->GetEventHandler()->ProcessEvent(event2
);
1473 node
= node
->GetNext();
1477 // the default action is to populate dialog with data when it's created
1478 void wxWindowBase::OnInitDialog( wxInitDialogEvent
&WXUNUSED(event
) )
1480 TransferDataToWindow();
1483 // process Ctrl-Alt-mclick
1484 void wxWindowBase::OnMiddleClick( wxMouseEvent
& event
)
1486 if ( event
.ControlDown() && event
.AltDown() )
1488 // don't translate these strings
1490 switch ( wxGetOsVersion() )
1492 case wxMOTIF_X
: port
= _T("Motif"); break;
1493 case wxMACINTOSH
: port
= _T("Mac"); break;
1494 case wxBEOS
: port
= _T("BeOS"); break;
1498 case wxGTK_BEOS
: port
= _T("GTK"); break;
1504 case wxWIN386
: port
= _T("MS Windows"); break;
1508 case wxMGL_OS2
: port
= _T("MGL"); break;
1510 case wxOS2_PM
: port
= _T("OS/2"); break;
1511 default: port
= _T("unknown"); break;
1514 wxMessageBox(wxString::Format(
1516 " wxWindows Library (%s port)\nVersion %u.%u.%u, compiled at %s %s\n Copyright (c) 1995-2000 wxWindows team"
1525 _T("wxWindows information"),
1526 wxICON_INFORMATION
| wxOK
,
1535 // ----------------------------------------------------------------------------
1536 // list classes implementation
1537 // ----------------------------------------------------------------------------
1539 void wxWindowListNode::DeleteData()
1541 delete (wxWindow
*)GetData();