]> git.saurik.com Git - wxWidgets.git/blob - src/common/wincmn.cpp
Bug in wxDocument::Save logic corrected, whereby Save didn't save when not
[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 #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
272 bool wxWindowBase::Destroy()
273 {
274 delete this;
275
276 return TRUE;
277 }
278
279 bool 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
293 bool 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
321 void 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
418 void 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
435 wxSize 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
484 void 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
498 bool 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
512 bool 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
529 bool wxWindowBase::IsTopLevel() const
530 {
531 return FALSE;
532 }
533
534 // ----------------------------------------------------------------------------
535 // reparenting the window
536 // ----------------------------------------------------------------------------
537
538 void 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
551 void 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
559 bool 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
595 void wxWindowBase::PushEventHandler(wxEvtHandler *handler)
596 {
597 handler->SetNextHandler(GetEventHandler());
598 SetEventHandler(handler);
599 }
600
601 wxEvtHandler *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
623 bool 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
633 bool 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
643 bool 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
658 bool 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
675 void 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
697 void 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
713 bool wxWindowBase::IsExposed(int x, int y) const
714 {
715 return m_updateRegion.Contains(x, y) != wxOutRegion;
716 }
717
718 bool 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
727 wxWindow *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
743 wxWindow *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
763 void 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
780 bool 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
805 bool 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
837 bool 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
869 void 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
883 void 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
894 void 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)
904 wxString 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
917 void 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
940 void 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
956 void 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
972 void 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.
1004 void 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.
1029 void 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.
1038 void wxWindowBase::RemoveConstraintReference(wxWindowBase *otherWin)
1039 {
1040 if ( m_constraintsInvolvedIn )
1041 m_constraintsInvolvedIn->DeleteObject(otherWin);
1042 }
1043
1044 // Reset any constraints that mention this window
1045 void 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
1078 void wxWindowBase::SetSizer(wxSizer *sizer)
1079 {
1080 if (m_windowSizer) delete m_windowSizer;
1081
1082 m_windowSizer = sizer;
1083 }
1084
1085 bool 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.
1126 bool 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
1137 bool 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
1148 bool 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
1189 void 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.
1216 void 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)
1258 void 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
1286 void 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
1304 void 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
1316 void 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
1328 void 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.
1350 void 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
1397 wxPoint 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
1410 wxPoint 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
1427 void 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
1439 wxClientData *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
1449 void 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
1458 void *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
1473 void 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
1492 void wxWindowBase::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) )
1493 {
1494 TransferDataToWindow();
1495 }
1496
1497 // process Ctrl-Alt-mclick
1498 void 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
1553 void wxWindowListNode::DeleteData()
1554 {
1555 delete (wxWindow *)GetData();
1556 }
1557