]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/wincmn.cpp
forgot to check in wxHtmlProcessor::IsEnabled test in wxHtmlWindow::SetPage
[wxWidgets.git] / src / common / wincmn.cpp
... / ...
CommitLineData
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
72int wxWindowBase::ms_lastControlId = -200;
73
74IMPLEMENT_ABSTRACT_CLASS(wxWindowBase, wxEvtHandler)
75
76// ----------------------------------------------------------------------------
77// event table
78// ----------------------------------------------------------------------------
79
80BEGIN_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
89END_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
100void 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
173bool 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
213wxWindowBase::~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
282bool wxWindowBase::Destroy()
283{
284 delete this;
285
286 return TRUE;
287}
288
289bool 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
303bool 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
331void 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
404void 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
421wxSize 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
470void 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
484bool 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
498bool 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
515bool wxWindowBase::IsTopLevel() const
516{
517 return FALSE;
518}
519
520// ----------------------------------------------------------------------------
521// reparenting the window
522// ----------------------------------------------------------------------------
523
524void 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
537void 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
545bool 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
581void wxWindowBase::PushEventHandler(wxEvtHandler *handler)
582{
583 handler->SetNextHandler(GetEventHandler());
584 SetEventHandler(handler);
585}
586
587wxEvtHandler *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
609bool 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
619bool 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
629bool 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
644bool 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
661void 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
683void 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
699bool wxWindowBase::IsExposed(int x, int y) const
700{
701 return m_updateRegion.Contains(x, y) != wxOutRegion;
702}
703
704bool 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
713wxWindow *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
729wxWindow *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
749void 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
766bool 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
791bool 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
823bool 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
855void 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
869void 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
880void 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)
890wxString 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
903void 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
926void 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
942void 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
958void 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.
990void 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.
1015void 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.
1024void wxWindowBase::RemoveConstraintReference(wxWindowBase *otherWin)
1025{
1026 if ( m_constraintsInvolvedIn )
1027 m_constraintsInvolvedIn->DeleteObject(otherWin);
1028}
1029
1030// Reset any constraints that mention this window
1031void 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
1064void wxWindowBase::SetSizer(wxSizer *sizer)
1065{
1066 if (m_windowSizer) delete m_windowSizer;
1067
1068 m_windowSizer = sizer;
1069}
1070
1071bool 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.
1112bool 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
1123bool 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
1134bool 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
1175void 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.
1202void 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)
1244void 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
1272void 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
1290void 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
1302void 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
1314void 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.
1336void 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
1383wxPoint 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
1396wxPoint 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
1413void 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
1425wxClientData *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
1435void 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
1444void *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
1459void 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
1478void wxWindowBase::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) )
1479{
1480 TransferDataToWindow();
1481}
1482
1483// process Ctrl-Alt-mclick
1484void 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
1539void wxWindowListNode::DeleteData()
1540{
1541 delete (wxWindow *)GetData();
1542}
1543