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