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