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