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