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