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