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