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