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