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