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