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