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