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