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