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