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