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