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