]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/wincmn.cpp
<br><br><br> is now handled correctly, e.g. empty lines are inserted (unlike <p>...
[wxWidgets.git] / src / common / wincmn.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: common/window.cpp
3// Purpose: common (to all ports) wxWindow functions
4// Author: Julian Smart, Vadim Zeitlin
5// Modified by:
6// Created: 13/07/98
7// RCS-ID: $Id$
8// Copyright: (c) wxWindows team
9// Licence: wxWindows license
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#ifdef __GNUG__
21 #pragma implementation "windowbase.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
31#ifndef WX_PRECOMP
32 #include "wx/string.h"
33 #include "wx/log.h"
34 #include "wx/intl.h"
35 #include "wx/frame.h"
36 #include "wx/defs.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#endif //WX_PRECOMP
44
45#if wxUSE_CONSTRAINTS
46 #include "wx/layout.h"
47 #include "wx/sizer.h"
48#endif // wxUSE_CONSTRAINTS
49
50#if wxUSE_DRAG_AND_DROP
51 #include "wx/dnd.h"
52#endif // wxUSE_DRAG_AND_DROP
53
54#if wxUSE_TOOLTIPS
55 #include "wx/tooltip.h"
56#endif // wxUSE_TOOLTIPS
57
58#if wxUSE_CARET
59 #include "wx/caret.h"
60#endif // wxUSE_CARET
61
62// ----------------------------------------------------------------------------
63// static data
64// ----------------------------------------------------------------------------
65
66int wxWindowBase::ms_lastControlId = -200;
67
68IMPLEMENT_ABSTRACT_CLASS(wxWindowBase, wxEvtHandler)
69
70// ----------------------------------------------------------------------------
71// event table
72// ----------------------------------------------------------------------------
73
74BEGIN_EVENT_TABLE(wxWindowBase, wxEvtHandler)
75 EVT_SYS_COLOUR_CHANGED(wxWindowBase::OnSysColourChanged)
76 EVT_INIT_DIALOG(wxWindowBase::OnInitDialog)
77END_EVENT_TABLE()
78
79// ============================================================================
80// implementation of the common functionality of the wxWindow class
81// ============================================================================
82
83// ----------------------------------------------------------------------------
84// initialization
85// ----------------------------------------------------------------------------
86
87// the default initialization
88void wxWindowBase::InitBase()
89{
90 // no window yet, no parent nor children
91 m_parent = (wxWindow *)NULL;
92 m_windowId = -1;
93 m_children.DeleteContents( FALSE ); // don't auto delete node data
94
95 // no constraints on the minimal window size
96 m_minWidth =
97 m_minHeight =
98 m_maxWidth =
99 m_maxHeight = -1;
100
101 // window is created enabled but it's not visible yet
102 m_isShown = FALSE;
103 m_isEnabled = TRUE;
104
105 // no client data (yet)
106 m_clientData = NULL;
107 m_clientDataType = ClientData_None;
108
109 // the default event handler is just this window
110 m_eventHandler = this;
111
112#if wxUSE_VALIDATORS
113 // no validator
114 m_windowValidator = (wxValidator *) NULL;
115#endif // wxUSE_VALIDATORS
116
117 // use the system default colours
118 wxSystemSettings settings;
119
120 m_backgroundColour = settings.GetSystemColour(wxSYS_COLOUR_BTNFACE);
121 m_foregroundColour = *wxBLACK; // TODO take this from sys settings too?
122 m_font = *wxSWISS_FONT; // and this?
123
124 // no style bits
125 m_windowStyle = 0;
126
127 // an optimization for the event processing: checking this flag is much
128 // faster than using IsKindOf(CLASSINFO(wxWindow))
129 m_isWindow = TRUE;
130
131#if wxUSE_CONSTRAINTS
132 // no constraints whatsoever
133 m_constraints = (wxLayoutConstraints *) NULL;
134 m_constraintsInvolvedIn = (wxWindowList *) NULL;
135 m_windowSizer = (wxSizer *) NULL;
136 m_autoLayout = FALSE;
137#endif // wxUSE_CONSTRAINTS
138
139#if wxUSE_DRAG_AND_DROP
140 m_dropTarget = (wxDropTarget *)NULL;
141#endif // wxUSE_DRAG_AND_DROP
142
143#if wxUSE_TOOLTIPS
144 m_tooltip = (wxToolTip *)NULL;
145#endif // wxUSE_TOOLTIPS
146
147#if wxUSE_CARET
148 m_caret = (wxCaret *)NULL;
149#endif // wxUSE_CARET
150}
151
152// common part of window creation process
153bool wxWindowBase::CreateBase(wxWindowBase *parent,
154 wxWindowID id,
155 const wxPoint& WXUNUSED(pos),
156 const wxSize& WXUNUSED(size),
157 long style,
158#if wxUSE_VALIDATORS
159# if defined(__VISAGECPP__)
160 const wxValidator* validator,
161# else
162 const wxValidator& validator,
163# endif
164#endif
165 const wxString& name)
166{
167 // m_isWindow is set to TRUE in wxWindowBase::Init() as well as many other
168 // member variables - check that it has been called (will catch the case
169 // when a new ctor is added which doesn't call InitWindow)
170 wxASSERT_MSG( m_isWindow, wxT("Init() must have been called before!") );
171
172 // generate a new id if the user doesn't care about it
173 m_windowId = id == -1 ? NewControlId() : id;
174
175 SetName(name);
176 SetWindowStyleFlag(style);
177 SetParent(parent);
178 SetValidator(validator);
179
180 return TRUE;
181}
182
183// ----------------------------------------------------------------------------
184// destruction
185// ----------------------------------------------------------------------------
186
187// common clean up
188wxWindowBase::~wxWindowBase()
189{
190 // FIXME if these 2 cases result from programming errors in the user code
191 // we should probably assert here instead of silently fixing them
192
193 // Just in case the window has been Closed, but we're then deleting
194 // immediately: don't leave dangling pointers.
195 wxPendingDelete.DeleteObject(this);
196
197 // Just in case we've loaded a top-level window via LoadNativeDialog but
198 // we weren't a dialog class
199 wxTopLevelWindows.DeleteObject(this);
200
201 wxASSERT_MSG( GetChildren().GetCount() == 0, wxT("children not destroyed") );
202
203 // make sure that there are no dangling pointers left pointing to us
204 wxPanel *panel = wxDynamicCast(GetParent(), wxPanel);
205 if ( panel )
206 {
207 if ( panel->GetLastFocus() == this )
208 {
209 panel->SetLastFocus((wxWindow *)NULL);
210 }
211 }
212
213#if wxUSE_CARET
214 if ( m_caret )
215 delete m_caret;
216#endif // wxUSE_CARET
217
218#if wxUSE_VALIDATORS
219 if ( m_windowValidator )
220 delete m_windowValidator;
221#endif // wxUSE_VALIDATORS
222
223 // we only delete object data, not untyped
224 if ( m_clientDataType == ClientData_Object )
225 delete m_clientObject;
226
227#if wxUSE_CONSTRAINTS
228 // Have to delete constraints/sizer FIRST otherwise sizers may try to look
229 // at deleted windows as they delete themselves.
230 DeleteRelatedConstraints();
231
232 if ( m_constraints )
233 {
234 // This removes any dangling pointers to this window in other windows'
235 // constraintsInvolvedIn lists.
236 UnsetConstraints(m_constraints);
237 delete m_constraints;
238 m_constraints = NULL;
239 }
240
241 if ( m_windowSizer )
242 delete m_windowSizer;
243
244#endif // wxUSE_CONSTRAINTS
245
246#if wxUSE_DRAG_AND_DROP
247 if ( m_dropTarget )
248 delete m_dropTarget;
249#endif // wxUSE_DRAG_AND_DROP
250
251#if wxUSE_TOOLTIPS
252 if ( m_tooltip )
253 delete m_tooltip;
254#endif // wxUSE_TOOLTIPS
255}
256
257bool wxWindowBase::Destroy()
258{
259 delete this;
260
261 return TRUE;
262}
263
264bool wxWindowBase::Close(bool force)
265{
266 wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId);
267 event.SetEventObject(this);
268#if WXWIN_COMPATIBILITY
269 event.SetForce(force);
270#endif // WXWIN_COMPATIBILITY
271 event.SetCanVeto(!force);
272
273 // return FALSE if window wasn't closed because the application vetoed the
274 // close event
275 return GetEventHandler()->ProcessEvent(event) && !event.GetVeto();
276}
277
278bool wxWindowBase::DestroyChildren()
279{
280 wxWindowList::Node *node;
281 for ( ;; )
282 {
283 // we iterate until the list becomes empty
284 node = GetChildren().GetFirst();
285 if ( !node )
286 break;
287
288 wxWindow *child = node->GetData();
289
290 wxASSERT_MSG( child, wxT("children list contains empty nodes") );
291
292 delete child;
293
294 wxASSERT_MSG( !GetChildren().Find(child),
295 wxT("child didn't remove itself using RemoveChild()") );
296 }
297
298 return TRUE;
299}
300
301// ----------------------------------------------------------------------------
302// centre/fit the window
303// ----------------------------------------------------------------------------
304
305// centre the window with respect to its parent in either (or both) directions
306void wxWindowBase::Centre(int direction)
307{
308 int widthParent, heightParent;
309
310 wxWindow *parent = GetParent();
311 if ( !parent )
312 {
313 // no other choice
314 direction |= wxCENTRE_ON_SCREEN;
315 }
316
317 if ( direction & wxCENTRE_ON_SCREEN )
318 {
319 // centre with respect to the whole screen
320 wxDisplaySize(&widthParent, &heightParent);
321 }
322 else
323 {
324 // centre inside the parents rectangle
325 parent->GetClientSize(&widthParent, &heightParent);
326 }
327
328 int width, height;
329 GetSize(&width, &height);
330
331 int xNew = -1,
332 yNew = -1;
333
334 if ( direction & wxHORIZONTAL )
335 xNew = (widthParent - width)/2;
336
337 if ( direction & wxVERTICAL )
338 yNew = (heightParent - height)/2;
339
340 // controls are always centered on their parent because it doesn't make
341 // sense to centre them on the screen
342 if ( !(direction & wxCENTRE_ON_SCREEN) || wxDynamicCast(this, wxControl) )
343 {
344 // theo nly chance to get this is to have a wxControl without parent
345 wxCHECK_RET( parent, wxT("a control must have a parent") );
346
347 // adjust to the parents client area origin
348 wxPoint posParent = parent->ClientToScreen(wxPoint(0, 0));
349
350 xNew += posParent.x;
351 yNew += posParent.y;
352 }
353
354 Move(xNew, yNew);
355}
356
357// fits the window around the children
358void wxWindowBase::Fit()
359{
360 int maxX = 0,
361 maxY = 0;
362
363 for ( wxWindowList::Node *node = GetChildren().GetFirst();
364 node;
365 node = node->GetNext() )
366 {
367 wxWindow *win = node->GetData();
368 if ( win->IsTopLevel() )
369 {
370 // dialogs and frames lie in different top level windows - don't
371 // deal with them here
372 continue;
373 }
374
375 int wx, wy, ww, wh;
376 win->GetPosition(&wx, &wy);
377 win->GetSize(&ww, &wh);
378 if ( wx + ww > maxX )
379 maxX = wx + ww;
380 if ( wy + wh > maxY )
381 maxY = wy + wh;
382 }
383
384 // leave a margin
385 SetClientSize(maxX + 7, maxY + 14);
386}
387
388// set the min/max size of the window
389
390void wxWindowBase::SetSizeHints(int minW, int minH,
391 int maxW, int maxH,
392 int WXUNUSED(incW), int WXUNUSED(incH))
393{
394 m_minWidth = minW;
395 m_maxWidth = maxW;
396 m_minHeight = minH;
397 m_maxHeight = maxH;
398}
399
400// ----------------------------------------------------------------------------
401// show/hide/enable/disable the window
402// ----------------------------------------------------------------------------
403
404bool wxWindowBase::Show(bool show)
405{
406 if ( show != m_isShown )
407 {
408 m_isShown = show;
409
410 return TRUE;
411 }
412 else
413 {
414 return FALSE;
415 }
416}
417
418bool wxWindowBase::Enable(bool enable)
419{
420 if ( enable != m_isEnabled )
421 {
422 m_isEnabled = enable;
423
424 return TRUE;
425 }
426 else
427 {
428 return FALSE;
429 }
430}
431// ----------------------------------------------------------------------------
432// RTTI
433// ----------------------------------------------------------------------------
434
435bool wxWindowBase::IsTopLevel() const
436{
437 return FALSE;
438}
439
440// ----------------------------------------------------------------------------
441// reparenting the window
442// ----------------------------------------------------------------------------
443
444void wxWindowBase::AddChild(wxWindowBase *child)
445{
446 wxCHECK_RET( child, wxT("can't add a NULL child") );
447
448 GetChildren().Append(child);
449 child->SetParent(this);
450}
451
452void wxWindowBase::RemoveChild(wxWindowBase *child)
453{
454 wxCHECK_RET( child, wxT("can't remove a NULL child") );
455
456 GetChildren().DeleteObject(child);
457 child->SetParent((wxWindow *)NULL);
458}
459
460bool wxWindowBase::Reparent(wxWindowBase *newParent)
461{
462 wxWindow *oldParent = GetParent();
463 if ( newParent == oldParent )
464 {
465 // nothing done
466 return FALSE;
467 }
468
469 // unlink this window from the existing parent.
470 if ( oldParent )
471 {
472 oldParent->RemoveChild(this);
473 }
474 else
475 {
476 wxTopLevelWindows.DeleteObject(this);
477 }
478
479 // add it to the new one
480 if ( newParent )
481 {
482 newParent->AddChild(this);
483 }
484 else
485 {
486 wxTopLevelWindows.Append(this);
487 }
488
489 return TRUE;
490}
491
492// ----------------------------------------------------------------------------
493// event handler stuff
494// ----------------------------------------------------------------------------
495
496void wxWindowBase::PushEventHandler(wxEvtHandler *handler)
497{
498 handler->SetNextHandler(GetEventHandler());
499 SetEventHandler(handler);
500}
501
502wxEvtHandler *wxWindowBase::PopEventHandler(bool deleteHandler)
503{
504 wxEvtHandler *handlerA = GetEventHandler();
505 if ( handlerA )
506 {
507 wxEvtHandler *handlerB = handlerA->GetNextHandler();
508 handlerA->SetNextHandler((wxEvtHandler *)NULL);
509 SetEventHandler(handlerB);
510 if ( deleteHandler )
511 {
512 delete handlerA;
513 handlerA = (wxEvtHandler *)NULL;
514 }
515 }
516
517 return handlerA;
518}
519
520// ----------------------------------------------------------------------------
521// cursors, fonts &c
522// ----------------------------------------------------------------------------
523
524bool wxWindowBase::SetBackgroundColour( const wxColour &colour )
525{
526 if ( !colour.Ok() || (colour == m_backgroundColour) )
527 return FALSE;
528
529 m_backgroundColour = colour;
530
531 return TRUE;
532}
533
534bool wxWindowBase::SetForegroundColour( const wxColour &colour )
535{
536 if ( !colour.Ok() || (colour == m_foregroundColour) )
537 return FALSE;
538
539 m_foregroundColour = colour;
540
541 return TRUE;
542}
543
544bool wxWindowBase::SetCursor(const wxCursor& cursor)
545{
546 // don't try to set invalid cursor, always fall back to the default
547 const wxCursor& cursorOk = cursor.Ok() ? cursor : *wxSTANDARD_CURSOR;
548
549 if ( (wxCursor&)cursorOk == m_cursor )
550 {
551 // no change
552 return FALSE;
553 }
554
555 m_cursor = cursorOk;
556
557 return TRUE;
558}
559
560bool wxWindowBase::SetFont(const wxFont& font)
561{
562 // don't try to set invalid font, always fall back to the default
563 const wxFont& fontOk = font.Ok() ? font : *wxSWISS_FONT;
564
565 if ( (wxFont&)fontOk == m_font )
566 {
567 // no change
568 return FALSE;
569 }
570
571 m_font = fontOk;
572
573 return TRUE;
574}
575
576#if wxUSE_CARET
577void wxWindowBase::SetCaret(wxCaret *caret)
578{
579 if ( m_caret )
580 {
581 delete m_caret;
582 }
583
584 m_caret = caret;
585
586 if ( m_caret )
587 {
588 wxASSERT_MSG( m_caret->GetWindow() == this,
589 wxT("caret should be created associated to this window") );
590 }
591}
592#endif // wxUSE_CARET
593
594#if wxUSE_VALIDATORS
595// ----------------------------------------------------------------------------
596// validators
597// ----------------------------------------------------------------------------
598
599# if defined(__VISAGECPP__)
600void wxWindowBase::SetValidator(const wxValidator* validator)
601{
602 if ( m_windowValidator )
603 delete m_windowValidator;
604
605 m_windowValidator = (wxValidator *)validator->Clone();
606
607 if ( m_windowValidator )
608 m_windowValidator->SetWindow(this) ;
609}
610# else
611void wxWindowBase::SetValidator(const wxValidator& validator)
612{
613 if ( m_windowValidator )
614 delete m_windowValidator;
615
616 m_windowValidator = (wxValidator *)validator.Clone();
617
618 if ( m_windowValidator )
619 m_windowValidator->SetWindow(this) ;
620}
621# endif // __VISAGECPP__
622#endif // wxUSE_VALIDATORS
623
624// ----------------------------------------------------------------------------
625// update region testing
626// ----------------------------------------------------------------------------
627
628bool wxWindowBase::IsExposed(int x, int y) const
629{
630 return m_updateRegion.Contains(x, y) != wxOutRegion;
631}
632
633bool wxWindowBase::IsExposed(int x, int y, int w, int h) const
634{
635 return m_updateRegion.Contains(x, y, w, h) != wxOutRegion;
636}
637
638// ----------------------------------------------------------------------------
639// find window by id or name
640// ----------------------------------------------------------------------------
641
642wxWindow *wxWindowBase::FindWindow( long id )
643{
644 if ( id == m_windowId )
645 return (wxWindow *)this;
646
647 wxWindowBase *res = (wxWindow *)NULL;
648 wxWindowList::Node *node;
649 for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() )
650 {
651 wxWindowBase *child = node->GetData();
652 res = child->FindWindow( id );
653 }
654
655 return (wxWindow *)res;
656}
657
658wxWindow *wxWindowBase::FindWindow( const wxString& name )
659{
660 if ( name == m_windowName )
661 return (wxWindow *)this;
662
663 wxWindowBase *res = (wxWindow *)NULL;
664 wxWindowList::Node *node;
665 for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() )
666 {
667 wxWindow *child = node->GetData();
668 res = child->FindWindow(name);
669 }
670
671 return (wxWindow *)res;
672}
673
674// ----------------------------------------------------------------------------
675// dialog oriented functions
676// ----------------------------------------------------------------------------
677
678void wxWindowBase::MakeModal(bool modal)
679{
680 // Disable all other windows
681 if ( IsTopLevel() )
682 {
683 wxWindowList::Node *node = wxTopLevelWindows.GetFirst();
684 while (node)
685 {
686 wxWindow *win = node->GetData();
687 if (win != this)
688 win->Enable(!modal);
689
690 node = node->GetNext();
691 }
692 }
693}
694
695bool wxWindowBase::Validate()
696{
697#if wxUSE_VALIDATORS
698 wxWindowList::Node *node;
699 for ( node = m_children.GetFirst(); node; node = node->GetNext() )
700 {
701 wxWindowBase *child = node->GetData();
702 wxValidator *validator = child->GetValidator();
703 if ( validator && !validator->Validate((wxWindow *)this) )
704 {
705 return FALSE;
706 }
707 }
708#endif // wxUSE_VALIDATORS
709
710 return TRUE;
711}
712
713bool wxWindowBase::TransferDataToWindow()
714{
715#if wxUSE_VALIDATORS
716 wxWindowList::Node *node;
717 for ( node = m_children.GetFirst(); node; node = node->GetNext() )
718 {
719 wxWindowBase *child = node->GetData();
720 wxValidator *validator = child->GetValidator();
721 if ( validator && !validator->TransferToWindow() )
722 {
723 wxLog *log = wxLog::GetActiveTarget();
724 if ( log )
725 {
726 wxLogWarning(_("Could not transfer data to window"));
727 log->Flush();
728 }
729
730 return FALSE;
731 }
732 }
733#endif // wxUSE_VALIDATORS
734
735 return TRUE;
736}
737
738bool wxWindowBase::TransferDataFromWindow()
739{
740#if wxUSE_VALIDATORS
741 wxWindowList::Node *node;
742 for ( node = m_children.GetFirst(); node; node = node->GetNext() )
743 {
744 wxWindow *child = node->GetData();
745 if ( child->GetValidator() &&
746 !child->GetValidator()->TransferFromWindow() )
747 {
748 return FALSE;
749 }
750 }
751#endif // wxUSE_VALIDATORS
752
753 return TRUE;
754}
755
756void wxWindowBase::InitDialog()
757{
758 wxInitDialogEvent event(GetId());
759 event.SetEventObject( this );
760 GetEventHandler()->ProcessEvent(event);
761}
762
763// ----------------------------------------------------------------------------
764// tooltips
765// ----------------------------------------------------------------------------
766
767#if wxUSE_TOOLTIPS
768
769void wxWindowBase::SetToolTip( const wxString &tip )
770{
771 // don't create the new tooltip if we already have one
772 if ( m_tooltip )
773 {
774 m_tooltip->SetTip( tip );
775 }
776 else
777 {
778 SetToolTip( new wxToolTip( tip ) );
779 }
780
781 // setting empty tooltip text does not remove the tooltip any more - use
782 // SetToolTip((wxToolTip *)NULL) for this
783}
784
785void wxWindowBase::DoSetToolTip(wxToolTip *tooltip)
786{
787 if ( m_tooltip )
788 delete m_tooltip;
789
790 m_tooltip = tooltip;
791}
792
793#endif // wxUSE_TOOLTIPS
794
795// ----------------------------------------------------------------------------
796// constraints and sizers
797// ----------------------------------------------------------------------------
798
799#if wxUSE_CONSTRAINTS
800
801void wxWindowBase::SetConstraints( wxLayoutConstraints *constraints )
802{
803 if ( m_constraints )
804 {
805 UnsetConstraints(m_constraints);
806 delete m_constraints;
807 }
808 m_constraints = constraints;
809 if ( m_constraints )
810 {
811 // Make sure other windows know they're part of a 'meaningful relationship'
812 if ( m_constraints->left.GetOtherWindow() && (m_constraints->left.GetOtherWindow() != this) )
813 m_constraints->left.GetOtherWindow()->AddConstraintReference(this);
814 if ( m_constraints->top.GetOtherWindow() && (m_constraints->top.GetOtherWindow() != this) )
815 m_constraints->top.GetOtherWindow()->AddConstraintReference(this);
816 if ( m_constraints->right.GetOtherWindow() && (m_constraints->right.GetOtherWindow() != this) )
817 m_constraints->right.GetOtherWindow()->AddConstraintReference(this);
818 if ( m_constraints->bottom.GetOtherWindow() && (m_constraints->bottom.GetOtherWindow() != this) )
819 m_constraints->bottom.GetOtherWindow()->AddConstraintReference(this);
820 if ( m_constraints->width.GetOtherWindow() && (m_constraints->width.GetOtherWindow() != this) )
821 m_constraints->width.GetOtherWindow()->AddConstraintReference(this);
822 if ( m_constraints->height.GetOtherWindow() && (m_constraints->height.GetOtherWindow() != this) )
823 m_constraints->height.GetOtherWindow()->AddConstraintReference(this);
824 if ( m_constraints->centreX.GetOtherWindow() && (m_constraints->centreX.GetOtherWindow() != this) )
825 m_constraints->centreX.GetOtherWindow()->AddConstraintReference(this);
826 if ( m_constraints->centreY.GetOtherWindow() && (m_constraints->centreY.GetOtherWindow() != this) )
827 m_constraints->centreY.GetOtherWindow()->AddConstraintReference(this);
828 }
829}
830
831// This removes any dangling pointers to this window in other windows'
832// constraintsInvolvedIn lists.
833void wxWindowBase::UnsetConstraints(wxLayoutConstraints *c)
834{
835 if ( c )
836 {
837 if ( c->left.GetOtherWindow() && (c->top.GetOtherWindow() != this) )
838 c->left.GetOtherWindow()->RemoveConstraintReference(this);
839 if ( c->top.GetOtherWindow() && (c->top.GetOtherWindow() != this) )
840 c->top.GetOtherWindow()->RemoveConstraintReference(this);
841 if ( c->right.GetOtherWindow() && (c->right.GetOtherWindow() != this) )
842 c->right.GetOtherWindow()->RemoveConstraintReference(this);
843 if ( c->bottom.GetOtherWindow() && (c->bottom.GetOtherWindow() != this) )
844 c->bottom.GetOtherWindow()->RemoveConstraintReference(this);
845 if ( c->width.GetOtherWindow() && (c->width.GetOtherWindow() != this) )
846 c->width.GetOtherWindow()->RemoveConstraintReference(this);
847 if ( c->height.GetOtherWindow() && (c->height.GetOtherWindow() != this) )
848 c->height.GetOtherWindow()->RemoveConstraintReference(this);
849 if ( c->centreX.GetOtherWindow() && (c->centreX.GetOtherWindow() != this) )
850 c->centreX.GetOtherWindow()->RemoveConstraintReference(this);
851 if ( c->centreY.GetOtherWindow() && (c->centreY.GetOtherWindow() != this) )
852 c->centreY.GetOtherWindow()->RemoveConstraintReference(this);
853 }
854}
855
856// Back-pointer to other windows we're involved with, so if we delete this
857// window, we must delete any constraints we're involved with.
858void wxWindowBase::AddConstraintReference(wxWindowBase *otherWin)
859{
860 if ( !m_constraintsInvolvedIn )
861 m_constraintsInvolvedIn = new wxWindowList;
862 if ( !m_constraintsInvolvedIn->Find(otherWin) )
863 m_constraintsInvolvedIn->Append(otherWin);
864}
865
866// REMOVE back-pointer to other windows we're involved with.
867void wxWindowBase::RemoveConstraintReference(wxWindowBase *otherWin)
868{
869 if ( m_constraintsInvolvedIn )
870 m_constraintsInvolvedIn->DeleteObject(otherWin);
871}
872
873// Reset any constraints that mention this window
874void wxWindowBase::DeleteRelatedConstraints()
875{
876 if ( m_constraintsInvolvedIn )
877 {
878 wxWindowList::Node *node = m_constraintsInvolvedIn->GetFirst();
879 while (node)
880 {
881 wxWindow *win = node->GetData();
882 wxLayoutConstraints *constr = win->GetConstraints();
883
884 // Reset any constraints involving this window
885 if ( constr )
886 {
887 constr->left.ResetIfWin(this);
888 constr->top.ResetIfWin(this);
889 constr->right.ResetIfWin(this);
890 constr->bottom.ResetIfWin(this);
891 constr->width.ResetIfWin(this);
892 constr->height.ResetIfWin(this);
893 constr->centreX.ResetIfWin(this);
894 constr->centreY.ResetIfWin(this);
895 }
896
897 wxWindowList::Node *next = node->GetNext();
898 delete node;
899 node = next;
900 }
901
902 delete m_constraintsInvolvedIn;
903 m_constraintsInvolvedIn = (wxWindowList *) NULL;
904 }
905}
906
907void wxWindowBase::SetSizer(wxSizer *sizer)
908{
909 if (m_windowSizer) delete m_windowSizer;
910
911 m_windowSizer = sizer;
912}
913
914bool wxWindowBase::Layout()
915{
916 int w, h;
917 GetClientSize(&w, &h);
918
919 // If there is a sizer, use it instead of the constraints
920 if ( GetSizer() )
921 {
922 GetSizer()->SetDimension( 0, 0, w, h );
923 return TRUE;
924 }
925
926 if ( GetConstraints() )
927 {
928 GetConstraints()->width.SetValue(w);
929 GetConstraints()->height.SetValue(h);
930 }
931
932 // Evaluate child constraints
933 ResetConstraints(); // Mark all constraints as unevaluated
934 DoPhase(1); // Just one phase need if no sizers involved
935 DoPhase(2);
936 SetConstraintSizes(); // Recursively set the real window sizes
937
938 return TRUE;
939}
940
941
942// Do a phase of evaluating constraints: the default behaviour. wxSizers may
943// do a similar thing, but also impose their own 'constraints' and order the
944// evaluation differently.
945bool wxWindowBase::LayoutPhase1(int *noChanges)
946{
947 wxLayoutConstraints *constr = GetConstraints();
948 if ( constr )
949 {
950 return constr->SatisfyConstraints(this, noChanges);
951 }
952 else
953 return TRUE;
954}
955
956bool wxWindowBase::LayoutPhase2(int *noChanges)
957{
958 *noChanges = 0;
959
960 // Layout children
961 DoPhase(1);
962 DoPhase(2);
963 return TRUE;
964}
965
966// Do a phase of evaluating child constraints
967bool wxWindowBase::DoPhase(int phase)
968{
969 int noIterations = 0;
970 int maxIterations = 500;
971 int noChanges = 1;
972 int noFailures = 0;
973 wxWindowList succeeded;
974 while ((noChanges > 0) && (noIterations < maxIterations))
975 {
976 noChanges = 0;
977 noFailures = 0;
978 wxWindowList::Node *node = GetChildren().GetFirst();
979 while (node)
980 {
981 wxWindow *child = node->GetData();
982 if ( !child->IsTopLevel() )
983 {
984 wxLayoutConstraints *constr = child->GetConstraints();
985 if ( constr )
986 {
987 if ( !succeeded.Find(child) )
988 {
989 int tempNoChanges = 0;
990 bool success = ( (phase == 1) ? child->LayoutPhase1(&tempNoChanges) : child->LayoutPhase2(&tempNoChanges) ) ;
991 noChanges += tempNoChanges;
992 if ( success )
993 {
994 succeeded.Append(child);
995 }
996 }
997 }
998 }
999 node = node->GetNext();
1000 }
1001
1002 noIterations++;
1003 }
1004
1005 return TRUE;
1006}
1007
1008void wxWindowBase::ResetConstraints()
1009{
1010 wxLayoutConstraints *constr = GetConstraints();
1011 if ( constr )
1012 {
1013 constr->left.SetDone(FALSE);
1014 constr->top.SetDone(FALSE);
1015 constr->right.SetDone(FALSE);
1016 constr->bottom.SetDone(FALSE);
1017 constr->width.SetDone(FALSE);
1018 constr->height.SetDone(FALSE);
1019 constr->centreX.SetDone(FALSE);
1020 constr->centreY.SetDone(FALSE);
1021 }
1022 wxWindowList::Node *node = GetChildren().GetFirst();
1023 while (node)
1024 {
1025 wxWindow *win = node->GetData();
1026 if ( !win->IsTopLevel() )
1027 win->ResetConstraints();
1028 node = node->GetNext();
1029 }
1030}
1031
1032// Need to distinguish between setting the 'fake' size for windows and sizers,
1033// and setting the real values.
1034void wxWindowBase::SetConstraintSizes(bool recurse)
1035{
1036 wxLayoutConstraints *constr = GetConstraints();
1037 if ( constr && constr->left.GetDone() && constr->right.GetDone( ) &&
1038 constr->width.GetDone() && constr->height.GetDone())
1039 {
1040 int x = constr->left.GetValue();
1041 int y = constr->top.GetValue();
1042 int w = constr->width.GetValue();
1043 int h = constr->height.GetValue();
1044
1045 if ( (constr->width.GetRelationship() != wxAsIs ) ||
1046 (constr->height.GetRelationship() != wxAsIs) )
1047 {
1048 SetSize(x, y, w, h);
1049 }
1050 else
1051 {
1052 // If we don't want to resize this window, just move it...
1053 Move(x, y);
1054 }
1055 }
1056 else if ( constr )
1057 {
1058 wxChar *windowClass = GetClassInfo()->GetClassName();
1059
1060 wxString winName;
1061 if ( GetName() == wxT("") )
1062 winName = wxT("unnamed");
1063 else
1064 winName = GetName();
1065 wxLogDebug( wxT("Constraint(s) not satisfied for window of type %s, name %s:\n"),
1066 (const wxChar *)windowClass,
1067 (const wxChar *)winName);
1068 if ( !constr->left.GetDone()) wxLogDebug( wxT(" unsatisfied 'left' constraint.\n") );
1069 if ( !constr->right.GetDone()) wxLogDebug( wxT(" unsatisfied 'right' constraint.\n") );
1070 if ( !constr->width.GetDone()) wxLogDebug( wxT(" unsatisfied 'width' constraint.\n") );
1071 if ( !constr->height.GetDone()) wxLogDebug( wxT(" unsatisfied 'height' constraint.\n") );
1072 wxLogDebug( wxT("Please check constraints: try adding AsIs() constraints.\n") );
1073 }
1074
1075 if ( recurse )
1076 {
1077 wxWindowList::Node *node = GetChildren().GetFirst();
1078 while (node)
1079 {
1080 wxWindow *win = node->GetData();
1081 if ( !win->IsTopLevel() )
1082 win->SetConstraintSizes();
1083 node = node->GetNext();
1084 }
1085 }
1086}
1087
1088// Only set the size/position of the constraint (if any)
1089void wxWindowBase::SetSizeConstraint(int x, int y, int w, int h)
1090{
1091 wxLayoutConstraints *constr = GetConstraints();
1092 if ( constr )
1093 {
1094 if ( x != -1 )
1095 {
1096 constr->left.SetValue(x);
1097 constr->left.SetDone(TRUE);
1098 }
1099 if ( y != -1 )
1100 {
1101 constr->top.SetValue(y);
1102 constr->top.SetDone(TRUE);
1103 }
1104 if ( w != -1 )
1105 {
1106 constr->width.SetValue(w);
1107 constr->width.SetDone(TRUE);
1108 }
1109 if ( h != -1 )
1110 {
1111 constr->height.SetValue(h);
1112 constr->height.SetDone(TRUE);
1113 }
1114 }
1115}
1116
1117void wxWindowBase::MoveConstraint(int x, int y)
1118{
1119 wxLayoutConstraints *constr = GetConstraints();
1120 if ( constr )
1121 {
1122 if ( x != -1 )
1123 {
1124 constr->left.SetValue(x);
1125 constr->left.SetDone(TRUE);
1126 }
1127 if ( y != -1 )
1128 {
1129 constr->top.SetValue(y);
1130 constr->top.SetDone(TRUE);
1131 }
1132 }
1133}
1134
1135void wxWindowBase::GetSizeConstraint(int *w, int *h) const
1136{
1137 wxLayoutConstraints *constr = GetConstraints();
1138 if ( constr )
1139 {
1140 *w = constr->width.GetValue();
1141 *h = constr->height.GetValue();
1142 }
1143 else
1144 GetSize(w, h);
1145}
1146
1147void wxWindowBase::GetClientSizeConstraint(int *w, int *h) const
1148{
1149 wxLayoutConstraints *constr = GetConstraints();
1150 if ( constr )
1151 {
1152 *w = constr->width.GetValue();
1153 *h = constr->height.GetValue();
1154 }
1155 else
1156 GetClientSize(w, h);
1157}
1158
1159void wxWindowBase::GetPositionConstraint(int *x, int *y) const
1160{
1161 wxLayoutConstraints *constr = GetConstraints();
1162 if ( constr )
1163 {
1164 *x = constr->left.GetValue();
1165 *y = constr->top.GetValue();
1166 }
1167 else
1168 GetPosition(x, y);
1169}
1170
1171#endif // wxUSE_CONSTRAINTS
1172
1173// ----------------------------------------------------------------------------
1174// do Update UI processing for child controls
1175// ----------------------------------------------------------------------------
1176
1177// TODO: should this be implemented for the child window rather
1178// than the parent? Then you can override it e.g. for wxCheckBox
1179// to do the Right Thing rather than having to assume a fixed number
1180// of control classes.
1181void wxWindowBase::UpdateWindowUI()
1182{
1183 wxUpdateUIEvent event(GetId());
1184 event.m_eventObject = this;
1185
1186 if ( GetEventHandler()->ProcessEvent(event) )
1187 {
1188 if ( event.GetSetEnabled() )
1189 Enable(event.GetEnabled());
1190
1191 if ( event.GetSetText() )
1192 {
1193 wxControl *control = wxDynamicCast(this, wxControl);
1194 if ( control )
1195 {
1196 wxTextCtrl *text = wxDynamicCast(control, wxTextCtrl);
1197 if ( text )
1198 text->SetValue(event.GetText());
1199 else
1200 control->SetLabel(event.GetText());
1201 }
1202 }
1203
1204#if wxUSE_CHECKBOX
1205 wxCheckBox *checkbox = wxDynamicCast(this, wxCheckBox);
1206 if ( checkbox )
1207 {
1208 if ( event.GetSetChecked() )
1209 checkbox->SetValue(event.GetChecked());
1210 }
1211#endif // wxUSE_CHECKBOX
1212
1213#if wxUSE_RADIOBUTTON
1214 wxRadioButton *radiobtn = wxDynamicCast(this, wxRadioButton);
1215 if ( radiobtn )
1216 {
1217 if ( event.GetSetChecked() )
1218 radiobtn->SetValue(event.GetChecked());
1219 }
1220#endif // wxUSE_RADIOBUTTON
1221 }
1222}
1223
1224// ----------------------------------------------------------------------------
1225// dialog units translations
1226// ----------------------------------------------------------------------------
1227
1228wxPoint wxWindowBase::ConvertPixelsToDialog(const wxPoint& pt)
1229{
1230 int charWidth = GetCharWidth();
1231 int charHeight = GetCharHeight();
1232 wxPoint pt2(-1, -1);
1233 if (pt.x != -1)
1234 pt2.x = (int) ((pt.x * 4) / charWidth) ;
1235 if (pt.y != -1)
1236 pt2.y = (int) ((pt.y * 8) / charHeight) ;
1237
1238 return pt2;
1239}
1240
1241wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt)
1242{
1243 int charWidth = GetCharWidth();
1244 int charHeight = GetCharHeight();
1245 wxPoint pt2(-1, -1);
1246 if (pt.x != -1)
1247 pt2.x = (int) ((pt.x * charWidth) / 4) ;
1248 if (pt.y != -1)
1249 pt2.y = (int) ((pt.y * charHeight) / 8) ;
1250
1251 return pt2;
1252}
1253
1254// ----------------------------------------------------------------------------
1255// client data
1256// ----------------------------------------------------------------------------
1257
1258void wxWindowBase::DoSetClientObject( wxClientData *data )
1259{
1260 wxASSERT_MSG( m_clientDataType != ClientData_Void,
1261 wxT("can't have both object and void client data") );
1262
1263 if ( m_clientObject )
1264 delete m_clientObject;
1265
1266 m_clientObject = data;
1267 m_clientDataType = ClientData_Object;
1268}
1269
1270wxClientData *wxWindowBase::DoGetClientObject() const
1271{
1272 wxASSERT_MSG( m_clientDataType == ClientData_Object,
1273 wxT("this window doesn't have object client data") );
1274
1275 return m_clientObject;
1276}
1277
1278void wxWindowBase::DoSetClientData( void *data )
1279{
1280 wxASSERT_MSG( m_clientDataType != ClientData_Object,
1281 wxT("can't have both object and void client data") );
1282
1283 m_clientData = data;
1284 m_clientDataType = ClientData_Void;
1285}
1286
1287void *wxWindowBase::DoGetClientData() const
1288{
1289 wxASSERT_MSG( m_clientDataType == ClientData_Void,
1290 wxT("this window doesn't have void client data") );
1291
1292 return m_clientData;
1293}
1294
1295// ----------------------------------------------------------------------------
1296// event handlers
1297// ----------------------------------------------------------------------------
1298
1299// propagate the colour change event to the subwindows
1300void wxWindowBase::OnSysColourChanged(wxSysColourChangedEvent& event)
1301{
1302 wxWindowList::Node *node = GetChildren().GetFirst();
1303 while ( node )
1304 {
1305 // Only propagate to non-top-level windows
1306 wxWindow *win = node->GetData();
1307 if ( !win->IsTopLevel() )
1308 {
1309 wxSysColourChangedEvent event2;
1310 event.m_eventObject = win;
1311 win->GetEventHandler()->ProcessEvent(event2);
1312 }
1313
1314 node = node->GetNext();
1315 }
1316}
1317
1318// the default action is to populate dialog with data when it's created
1319void wxWindowBase::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) )
1320{
1321 TransferDataToWindow();
1322}
1323
1324// ----------------------------------------------------------------------------
1325// list classes implementation
1326// ----------------------------------------------------------------------------
1327
1328void wxWindowListNode::DeleteData()
1329{
1330 delete (wxWindow *)GetData();
1331}
1332