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