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