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