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