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