]> git.saurik.com Git - wxWidgets.git/blob - src/common/wincmn.cpp
Fixed compile errors.
[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 // Center TopLevel windows over thier parent instead of the whole screen
320 void 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
347 // fits the window around the children
348 void 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();
357 if ( win->IsTopLevel() )
358 {
359 // dialogs and frames lie in different top level windows - don't
360 // deal with them here
361 continue;
362 }
363
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
381 void 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
395 bool 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
409 bool 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 }
422 // ----------------------------------------------------------------------------
423 // RTTI
424 // ----------------------------------------------------------------------------
425
426 bool wxWindowBase::IsTopLevel() const
427 {
428 return wxDynamicCast(this, wxFrame) || wxDynamicCast(this, wxDialog);
429 }
430
431 // ----------------------------------------------------------------------------
432 // reparenting the window
433 // ----------------------------------------------------------------------------
434
435 void 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
443 void 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 }
450
451 bool 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
487 void wxWindowBase::PushEventHandler(wxEvtHandler *handler)
488 {
489 handler->SetNextHandler(GetEventHandler());
490 SetEventHandler(handler);
491 }
492
493 wxEvtHandler *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
515 bool 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
525 bool 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
535 bool 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
551 bool 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
567 #if wxUSE_CARET
568 void 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,
580 _T("caret should be created associated to this window") );
581 }
582 }
583 #endif // wxUSE_CARET
584
585 #if wxUSE_VALIDATORS
586 // ----------------------------------------------------------------------------
587 // validators
588 // ----------------------------------------------------------------------------
589
590 void 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 }
600 #endif // wxUSE_VALIDATORS
601
602 // ----------------------------------------------------------------------------
603 // update region testing
604 // ----------------------------------------------------------------------------
605
606 bool wxWindowBase::IsExposed(int x, int y) const
607 {
608 return m_updateRegion.Contains(x, y) != wxOutRegion;
609 }
610
611 bool 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
620 wxWindow *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
636 wxWindow *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
656 void wxWindowBase::MakeModal(bool modal)
657 {
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 }
671 }
672
673 bool wxWindowBase::Validate()
674 {
675 #if wxUSE_VALIDATORS
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();
681 if ( validator && !validator->Validate((wxWindow *)this) )
682 {
683 return FALSE;
684 }
685 }
686 #endif // wxUSE_VALIDATORS
687
688 return TRUE;
689 }
690
691 bool wxWindowBase::TransferDataToWindow()
692 {
693 #if wxUSE_VALIDATORS
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 }
711 #endif // wxUSE_VALIDATORS
712
713 return TRUE;
714 }
715
716 bool wxWindowBase::TransferDataFromWindow()
717 {
718 #if wxUSE_VALIDATORS
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 }
729 #endif // wxUSE_VALIDATORS
730
731 return TRUE;
732 }
733
734 void 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
747 void 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
763 void 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
779 void 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.
811 void 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.
836 void 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.
845 void wxWindowBase::RemoveConstraintReference(wxWindowBase *otherWin)
846 {
847 if ( m_constraintsInvolvedIn )
848 m_constraintsInvolvedIn->DeleteObject(otherWin);
849 }
850
851 // Reset any constraints that mention this window
852 void 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
885 void wxWindowBase::SetSizer(wxSizer *sizer)
886 {
887 m_windowSizer = sizer;
888 if ( sizer )
889 sizer->SetSizerParent(this);
890 }
891
892 bool 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.
927 bool 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
938 bool 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
949 bool 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();
964 if ( !child->IsTopLevel() )
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
990 void 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();
1008 if ( !win->IsTopLevel() )
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.
1016 void 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();
1065 if ( !win->IsTopLevel() )
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.
1074 void wxWindowBase::TransformSizerToActual(int *x, int *y) const
1075 {
1076 if ( !m_sizerParent || m_sizerParent->IsTopLevel() )
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
1086 void 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
1094 void 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)
1103 void 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
1131 void 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
1149 void 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
1161 void 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
1173 void 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 // ----------------------------------------------------------------------------
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.
1195 void wxWindowBase::UpdateWindowUI()
1196 {
1197 wxWindowID id = GetId();
1198 if ( id > 0 )
1199 {
1200 wxUpdateUIEvent event(id);
1201 event.m_eventObject = this;
1202
1203 if ( GetEventHandler()->ProcessEvent(event) )
1204 {
1205 if ( event.GetSetEnabled() )
1206 Enable(event.GetEnabled());
1207
1208 if ( event.GetSetText() )
1209 {
1210 wxControl *control = wxDynamicCast(this, wxControl);
1211 if ( control )
1212 control->SetLabel(event.GetText());
1213 }
1214
1215 #if wxUSE_CHECKBOX
1216 wxCheckBox *checkbox = wxDynamicCast(this, wxCheckBox);
1217 if ( checkbox )
1218 {
1219 if ( event.GetSetChecked() )
1220 checkbox->SetValue(event.GetChecked());
1221 }
1222 #endif // wxUSE_CHECKBOX
1223
1224 #if wxUSE_RADIOBUTTON
1225 wxRadioButton *radiobtn = wxDynamicCast(this, wxRadioButton);
1226 if ( radiobtn )
1227 {
1228 if ( event.GetSetChecked() )
1229 radiobtn->SetValue(event.GetChecked());
1230 }
1231 #endif // wxUSE_RADIOBUTTON
1232 }
1233 }
1234 }
1235
1236 // ----------------------------------------------------------------------------
1237 // dialog units translations
1238 // ----------------------------------------------------------------------------
1239
1240 wxPoint wxWindowBase::ConvertPixelsToDialog(const wxPoint& pt)
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
1251 wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt)
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
1262 // ----------------------------------------------------------------------------
1263 // event handlers
1264 // ----------------------------------------------------------------------------
1265
1266 // propagate the colour change event to the subwindows
1267 void 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
1286 void wxWindowBase::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) )
1287 {
1288 TransferDataToWindow();
1289 }
1290
1291 // ----------------------------------------------------------------------------
1292 // list classes implementation
1293 // ----------------------------------------------------------------------------
1294
1295 void wxWindowListNode::DeleteData()
1296 {
1297 delete (wxWindow *)GetData();
1298 }
1299