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