]> git.saurik.com Git - wxWidgets.git/blob - 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
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
66 int wxWindowBase::ms_lastControlId = -200;
67
68 IMPLEMENT_ABSTRACT_CLASS(wxWindowBase, wxEvtHandler)
69
70 // ----------------------------------------------------------------------------
71 // event table
72 // ----------------------------------------------------------------------------
73
74 BEGIN_EVENT_TABLE(wxWindowBase, wxEvtHandler)
75 EVT_SYS_COLOUR_CHANGED(wxWindowBase::OnSysColourChanged)
76 EVT_INIT_DIALOG(wxWindowBase::OnInitDialog)
77 END_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
88 void 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
153 bool 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
188 wxWindowBase::~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
257 bool wxWindowBase::Destroy()
258 {
259 delete this;
260
261 return TRUE;
262 }
263
264 bool 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
278 bool 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
306 void 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
358 void 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
390 void 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
404 bool 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
418 bool 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
435 bool wxWindowBase::IsTopLevel() const
436 {
437 return FALSE;
438 }
439
440 // ----------------------------------------------------------------------------
441 // reparenting the window
442 // ----------------------------------------------------------------------------
443
444 void 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
452 void 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
460 bool 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
496 void wxWindowBase::PushEventHandler(wxEvtHandler *handler)
497 {
498 handler->SetNextHandler(GetEventHandler());
499 SetEventHandler(handler);
500 }
501
502 wxEvtHandler *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
524 bool 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
534 bool 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
544 bool 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
560 bool 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
577 void 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__)
600 void 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
611 void 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
628 bool wxWindowBase::IsExposed(int x, int y) const
629 {
630 return m_updateRegion.Contains(x, y) != wxOutRegion;
631 }
632
633 bool 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
642 wxWindow *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
658 wxWindow *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
678 void 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
695 bool 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
713 bool 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
738 bool 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
756 void 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
769 void 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
785 void 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
801 void 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.
833 void 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.
858 void 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.
867 void wxWindowBase::RemoveConstraintReference(wxWindowBase *otherWin)
868 {
869 if ( m_constraintsInvolvedIn )
870 m_constraintsInvolvedIn->DeleteObject(otherWin);
871 }
872
873 // Reset any constraints that mention this window
874 void 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
907 void wxWindowBase::SetSizer(wxSizer *sizer)
908 {
909 if (m_windowSizer) delete m_windowSizer;
910
911 m_windowSizer = sizer;
912 }
913
914 bool 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.
945 bool 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
956 bool 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
967 bool 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
1008 void 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.
1034 void 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)
1089 void 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
1117 void 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
1135 void 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
1147 void 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
1159 void 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.
1181 void 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
1228 wxPoint 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
1241 wxPoint 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
1258 void 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
1270 wxClientData *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
1278 void 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
1287 void *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
1300 void 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
1319 void wxWindowBase::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) )
1320 {
1321 TransferDataToWindow();
1322 }
1323
1324 // ----------------------------------------------------------------------------
1325 // list classes implementation
1326 // ----------------------------------------------------------------------------
1327
1328 void wxWindowListNode::DeleteData()
1329 {
1330 delete (wxWindow *)GetData();
1331 }
1332