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