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