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