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