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