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