]> git.saurik.com Git - wxWidgets.git/blob - src/common/wincmn.cpp
more user-friendly error message
[wxWidgets.git] / src / common / wincmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/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) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/string.h"
29 #include "wx/log.h"
30 #include "wx/intl.h"
31 #include "wx/frame.h"
32 #include "wx/window.h"
33 #include "wx/control.h"
34 #include "wx/checkbox.h"
35 #include "wx/radiobut.h"
36 #include "wx/statbox.h"
37 #include "wx/textctrl.h"
38 #include "wx/settings.h"
39 #include "wx/dialog.h"
40 #include "wx/msgdlg.h"
41 #include "wx/msgout.h"
42 #include "wx/statusbr.h"
43 #include "wx/toolbar.h"
44 #include "wx/dcclient.h"
45 #include "wx/scrolbar.h"
46 #include "wx/layout.h"
47 #include "wx/sizer.h"
48 #include "wx/menu.h"
49 #endif //WX_PRECOMP
50
51 #if wxUSE_DRAG_AND_DROP
52 #include "wx/dnd.h"
53 #endif // wxUSE_DRAG_AND_DROP
54
55 #if wxUSE_ACCESSIBILITY
56 #include "wx/access.h"
57 #endif
58
59 #if wxUSE_HELP
60 #include "wx/cshelp.h"
61 #endif // wxUSE_HELP
62
63 #if wxUSE_TOOLTIPS
64 #include "wx/tooltip.h"
65 #endif // wxUSE_TOOLTIPS
66
67 #if wxUSE_CARET
68 #include "wx/caret.h"
69 #endif // wxUSE_CARET
70
71 #if wxUSE_SYSTEM_OPTIONS
72 #include "wx/sysopt.h"
73 #endif
74
75 // For reporting compile- and runtime version of GTK+ in the ctrl+alt+mclick dialog.
76 // The gtk includes don't pull any other headers in, at least not on my system - MR
77 #ifdef __WXGTK__
78 #ifdef __WXGTK20__
79 #include <gtk/gtkversion.h>
80 #else
81 #include <gtk/gtkfeatures.h>
82 #endif
83 #endif
84
85 #include "wx/platinfo.h"
86
87 // Windows List
88 WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows;
89
90 // globals
91 #if wxUSE_MENUS
92 wxMenu *wxCurrentPopupMenu = NULL;
93 #endif // wxUSE_MENUS
94
95 // ----------------------------------------------------------------------------
96 // static data
97 // ----------------------------------------------------------------------------
98
99
100 IMPLEMENT_ABSTRACT_CLASS(wxWindowBase, wxEvtHandler)
101
102 // ----------------------------------------------------------------------------
103 // event table
104 // ----------------------------------------------------------------------------
105
106 BEGIN_EVENT_TABLE(wxWindowBase, wxEvtHandler)
107 EVT_SYS_COLOUR_CHANGED(wxWindowBase::OnSysColourChanged)
108 EVT_INIT_DIALOG(wxWindowBase::OnInitDialog)
109 EVT_MIDDLE_DOWN(wxWindowBase::OnMiddleClick)
110
111 #if wxUSE_HELP
112 EVT_HELP(wxID_ANY, wxWindowBase::OnHelp)
113 #endif // wxUSE_HELP
114
115 END_EVENT_TABLE()
116
117 // ============================================================================
118 // implementation of the common functionality of the wxWindow class
119 // ============================================================================
120
121 // ----------------------------------------------------------------------------
122 // initialization
123 // ----------------------------------------------------------------------------
124
125 // the default initialization
126 wxWindowBase::wxWindowBase()
127 {
128 // no window yet, no parent nor children
129 m_parent = NULL;
130 m_windowId = wxID_ANY;
131
132 // no constraints on the minimal window size
133 m_minWidth =
134 m_maxWidth = wxDefaultCoord;
135 m_minHeight =
136 m_maxHeight = wxDefaultCoord;
137
138 // invalidiated cache value
139 m_bestSizeCache = wxDefaultSize;
140
141 // window are created enabled and visible by default
142 m_isShown =
143 m_isEnabled = true;
144
145 // the default event handler is just this window
146 m_eventHandler = this;
147
148 #if wxUSE_VALIDATORS
149 // no validator
150 m_windowValidator = NULL;
151 #endif // wxUSE_VALIDATORS
152
153 // the colours/fonts are default for now, so leave m_font,
154 // m_backgroundColour and m_foregroundColour uninitialized and set those
155 m_hasBgCol =
156 m_hasFgCol =
157 m_hasFont = false;
158 m_inheritBgCol =
159 m_inheritFgCol =
160 m_inheritFont = false;
161
162 // no style bits
163 m_exStyle =
164 m_windowStyle = 0;
165
166 m_backgroundStyle = wxBG_STYLE_SYSTEM;
167
168 #if wxUSE_CONSTRAINTS
169 // no constraints whatsoever
170 m_constraints = NULL;
171 m_constraintsInvolvedIn = NULL;
172 #endif // wxUSE_CONSTRAINTS
173
174 m_windowSizer = NULL;
175 m_containingSizer = NULL;
176 m_autoLayout = false;
177
178 #if wxUSE_DRAG_AND_DROP
179 m_dropTarget = NULL;
180 #endif // wxUSE_DRAG_AND_DROP
181
182 #if wxUSE_TOOLTIPS
183 m_tooltip = NULL;
184 #endif // wxUSE_TOOLTIPS
185
186 #if wxUSE_CARET
187 m_caret = NULL;
188 #endif // wxUSE_CARET
189
190 #if wxUSE_PALETTE
191 m_hasCustomPalette = false;
192 #endif // wxUSE_PALETTE
193
194 #if wxUSE_ACCESSIBILITY
195 m_accessible = NULL;
196 #endif
197
198 m_virtualSize = wxDefaultSize;
199
200 m_scrollHelper = NULL;
201
202 m_windowVariant = wxWINDOW_VARIANT_NORMAL;
203 #if wxUSE_SYSTEM_OPTIONS
204 if ( wxSystemOptions::HasOption(wxWINDOW_DEFAULT_VARIANT) )
205 {
206 m_windowVariant = (wxWindowVariant) wxSystemOptions::GetOptionInt( wxWINDOW_DEFAULT_VARIANT ) ;
207 }
208 #endif
209
210 // Whether we're using the current theme for this window (wxGTK only for now)
211 m_themeEnabled = false;
212
213 // This is set to true by SendDestroyEvent() which should be called by the
214 // most derived class to ensure that the destruction event is sent as soon
215 // as possible to allow its handlers to still see the undestroyed window
216 m_isBeingDeleted = false;
217
218 m_freezeCount = 0;
219 }
220
221 // common part of window creation process
222 bool wxWindowBase::CreateBase(wxWindowBase *parent,
223 wxWindowID id,
224 const wxPoint& WXUNUSED(pos),
225 const wxSize& WXUNUSED(size),
226 long style,
227 const wxValidator& wxVALIDATOR_PARAM(validator),
228 const wxString& name)
229 {
230 #if wxUSE_STATBOX
231 // wxGTK doesn't allow to create controls with static box as the parent so
232 // this will result in a crash when the program is ported to wxGTK so warn
233 // the user about it
234
235 // if you get this assert, the correct solution is to create the controls
236 // as siblings of the static box
237 wxASSERT_MSG( !parent || !wxDynamicCast(parent, wxStaticBox),
238 _T("wxStaticBox can't be used as a window parent!") );
239 #endif // wxUSE_STATBOX
240
241 // ids are limited to 16 bits under MSW so if you care about portability,
242 // it's not a good idea to use ids out of this range (and negative ids are
243 // reserved for wxWidgets own usage)
244 wxASSERT_MSG( id == wxID_ANY || (id >= 0 && id < 32767) ||
245 (id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST),
246 _T("invalid id value") );
247
248 // generate a new id if the user doesn't care about it
249 if ( id == wxID_ANY )
250 {
251 m_windowId = NewControlId();
252 }
253 else // valid id specified
254 {
255 m_windowId = id;
256 }
257
258 // don't use SetWindowStyleFlag() here, this function should only be called
259 // to change the flag after creation as it tries to reflect the changes in
260 // flags by updating the window dynamically and we don't need this here
261 m_windowStyle = style;
262
263 SetName(name);
264 SetParent(parent);
265
266 #if wxUSE_VALIDATORS
267 SetValidator(validator);
268 #endif // wxUSE_VALIDATORS
269
270 // if the parent window has wxWS_EX_VALIDATE_RECURSIVELY set, we want to
271 // have it too - like this it's possible to set it only in the top level
272 // dialog/frame and all children will inherit it by defult
273 if ( parent && (parent->GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) )
274 {
275 SetExtraStyle(GetExtraStyle() | wxWS_EX_VALIDATE_RECURSIVELY);
276 }
277
278 return true;
279 }
280
281 bool wxWindowBase::ToggleWindowStyle(int flag)
282 {
283 wxASSERT_MSG( flag, _T("flags with 0 value can't be toggled") );
284
285 bool rc;
286 long style = GetWindowStyleFlag();
287 if ( style & flag )
288 {
289 style &= ~flag;
290 rc = false;
291 }
292 else // currently off
293 {
294 style |= flag;
295 rc = true;
296 }
297
298 SetWindowStyleFlag(style);
299
300 return rc;
301 }
302
303 // ----------------------------------------------------------------------------
304 // destruction
305 // ----------------------------------------------------------------------------
306
307 // common clean up
308 wxWindowBase::~wxWindowBase()
309 {
310 wxASSERT_MSG( GetCapture() != this, wxT("attempt to destroy window with mouse capture") );
311
312 // FIXME if these 2 cases result from programming errors in the user code
313 // we should probably assert here instead of silently fixing them
314
315 // Just in case the window has been Closed, but we're then deleting
316 // immediately: don't leave dangling pointers.
317 wxPendingDelete.DeleteObject(this);
318
319 // Just in case we've loaded a top-level window via LoadNativeDialog but
320 // we weren't a dialog class
321 wxTopLevelWindows.DeleteObject((wxWindow*)this);
322
323 #if wxUSE_MENUS
324 // The associated popup menu can still be alive, disassociate from it in
325 // this case
326 if ( wxCurrentPopupMenu && wxCurrentPopupMenu->GetInvokingWindow() == this )
327 wxCurrentPopupMenu->SetInvokingWindow(NULL);
328 #endif // wxUSE_MENUS
329
330 wxASSERT_MSG( GetChildren().GetCount() == 0, wxT("children not destroyed") );
331
332 // notify the parent about this window destruction
333 if ( m_parent )
334 m_parent->RemoveChild(this);
335
336 #if wxUSE_CARET
337 delete m_caret;
338 #endif // wxUSE_CARET
339
340 #if wxUSE_VALIDATORS
341 delete m_windowValidator;
342 #endif // wxUSE_VALIDATORS
343
344 #if wxUSE_CONSTRAINTS
345 // Have to delete constraints/sizer FIRST otherwise sizers may try to look
346 // at deleted windows as they delete themselves.
347 DeleteRelatedConstraints();
348
349 if ( m_constraints )
350 {
351 // This removes any dangling pointers to this window in other windows'
352 // constraintsInvolvedIn lists.
353 UnsetConstraints(m_constraints);
354 delete m_constraints;
355 m_constraints = NULL;
356 }
357 #endif // wxUSE_CONSTRAINTS
358
359 if ( m_containingSizer )
360 m_containingSizer->Detach( (wxWindow*)this );
361
362 delete m_windowSizer;
363
364 #if wxUSE_DRAG_AND_DROP
365 delete m_dropTarget;
366 #endif // wxUSE_DRAG_AND_DROP
367
368 #if wxUSE_TOOLTIPS
369 delete m_tooltip;
370 #endif // wxUSE_TOOLTIPS
371
372 #if wxUSE_ACCESSIBILITY
373 delete m_accessible;
374 #endif
375
376 #if wxUSE_HELP
377 // NB: this has to be called unconditionally, because we don't know
378 // whether this window has associated help text or not
379 wxHelpProvider *helpProvider = wxHelpProvider::Get();
380 if ( helpProvider )
381 helpProvider->RemoveHelp(this);
382 #endif
383 }
384
385 bool wxWindowBase::IsBeingDeleted() const
386 {
387 return m_isBeingDeleted ||
388 (!IsTopLevel() && m_parent && m_parent->IsBeingDeleted());
389 }
390
391 void wxWindowBase::SendDestroyEvent()
392 {
393 if ( m_isBeingDeleted )
394 {
395 // we could have been already called from a more derived class dtor,
396 // e.g. ~wxTLW calls us and so does ~wxWindow and the latter call
397 // should be simply ignored
398 return;
399 }
400
401 m_isBeingDeleted = true;
402
403 wxWindowDestroyEvent event;
404 event.SetEventObject(this);
405 event.SetId(GetId());
406 GetEventHandler()->ProcessEvent(event);
407 }
408
409 bool wxWindowBase::Destroy()
410 {
411 SendDestroyEvent();
412
413 delete this;
414
415 return true;
416 }
417
418 bool wxWindowBase::Close(bool force)
419 {
420 wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId);
421 event.SetEventObject(this);
422 event.SetCanVeto(!force);
423
424 // return false if window wasn't closed because the application vetoed the
425 // close event
426 return HandleWindowEvent(event) && !event.GetVeto();
427 }
428
429 bool wxWindowBase::DestroyChildren()
430 {
431 wxWindowList::compatibility_iterator node;
432 for ( ;; )
433 {
434 // we iterate until the list becomes empty
435 node = GetChildren().GetFirst();
436 if ( !node )
437 break;
438
439 wxWindow *child = node->GetData();
440
441 // note that we really want to delete it immediately so don't call the
442 // possible overridden Destroy() version which might not delete the
443 // child immediately resulting in problems with our (top level) child
444 // outliving its parent
445 child->wxWindowBase::Destroy();
446
447 wxASSERT_MSG( !GetChildren().Find(child),
448 wxT("child didn't remove itself using RemoveChild()") );
449 }
450
451 return true;
452 }
453
454 // ----------------------------------------------------------------------------
455 // size/position related methods
456 // ----------------------------------------------------------------------------
457
458 // centre the window with respect to its parent in either (or both) directions
459 void wxWindowBase::DoCentre(int dir)
460 {
461 wxCHECK_RET( !(dir & wxCENTRE_ON_SCREEN) && GetParent(),
462 _T("this method only implements centering child windows") );
463
464 SetSize(GetRect().CentreIn(GetParent()->GetClientSize(), dir));
465 }
466
467 // fits the window around the children
468 void wxWindowBase::Fit()
469 {
470 if ( !GetChildren().empty() )
471 {
472 SetSize(GetBestSize());
473 }
474 //else: do nothing if we have no children
475 }
476
477 // fits virtual size (ie. scrolled area etc.) around children
478 void wxWindowBase::FitInside()
479 {
480 if ( GetChildren().GetCount() > 0 )
481 {
482 SetVirtualSize( GetBestVirtualSize() );
483 }
484 }
485
486 // On Mac, scrollbars are explicitly children.
487 #ifdef __WXMAC__
488 static bool wxHasRealChildren(const wxWindowBase* win)
489 {
490 int realChildCount = 0;
491
492 for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
493 node;
494 node = node->GetNext() )
495 {
496 wxWindow *win = node->GetData();
497 if ( !win->IsTopLevel() && win->IsShown() && !win->IsKindOf(CLASSINFO(wxScrollBar)))
498 realChildCount ++;
499 }
500 return (realChildCount > 0);
501 }
502 #endif
503
504 void wxWindowBase::InvalidateBestSize()
505 {
506 m_bestSizeCache = wxDefaultSize;
507
508 // parent's best size calculation may depend on its children's
509 // as long as child window we are in is not top level window itself
510 // (because the TLW size is never resized automatically)
511 // so let's invalidate it as well to be safe:
512 if (m_parent && !IsTopLevel())
513 m_parent->InvalidateBestSize();
514 }
515
516 // return the size best suited for the current window
517 wxSize wxWindowBase::DoGetBestSize() const
518 {
519 wxSize best;
520
521 if ( m_windowSizer )
522 {
523 best = m_windowSizer->GetMinSize();
524 }
525 #if wxUSE_CONSTRAINTS
526 else if ( m_constraints )
527 {
528 wxConstCast(this, wxWindowBase)->SatisfyConstraints();
529
530 // our minimal acceptable size is such that all our windows fit inside
531 int maxX = 0,
532 maxY = 0;
533
534 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
535 node;
536 node = node->GetNext() )
537 {
538 wxLayoutConstraints *c = node->GetData()->GetConstraints();
539 if ( !c )
540 {
541 // it's not normal that we have an unconstrained child, but
542 // what can we do about it?
543 continue;
544 }
545
546 int x = c->right.GetValue(),
547 y = c->bottom.GetValue();
548
549 if ( x > maxX )
550 maxX = x;
551
552 if ( y > maxY )
553 maxY = y;
554
555 // TODO: we must calculate the overlaps somehow, otherwise we
556 // will never return a size bigger than the current one :-(
557 }
558
559 best = wxSize(maxX, maxY);
560 }
561 #endif // wxUSE_CONSTRAINTS
562 else if ( !GetChildren().empty()
563 #ifdef __WXMAC__
564 && wxHasRealChildren(this)
565 #endif
566 )
567 {
568 // our minimal acceptable size is such that all our visible child
569 // windows fit inside
570 int maxX = 0,
571 maxY = 0;
572
573 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
574 node;
575 node = node->GetNext() )
576 {
577 wxWindow *win = node->GetData();
578 if ( win->IsTopLevel()
579 || !win->IsShown()
580 #if wxUSE_STATUSBAR
581 || wxDynamicCast(win, wxStatusBar)
582 #endif // wxUSE_STATUSBAR
583 )
584 {
585 // dialogs and frames lie in different top level windows -
586 // don't deal with them here; as for the status bars, they
587 // don't lie in the client area at all
588 continue;
589 }
590
591 int wx, wy, ww, wh;
592 win->GetPosition(&wx, &wy);
593
594 // if the window hadn't been positioned yet, assume that it is in
595 // the origin
596 if ( wx == wxDefaultCoord )
597 wx = 0;
598 if ( wy == wxDefaultCoord )
599 wy = 0;
600
601 win->GetSize(&ww, &wh);
602 if ( wx + ww > maxX )
603 maxX = wx + ww;
604 if ( wy + wh > maxY )
605 maxY = wy + wh;
606 }
607
608 best = wxSize(maxX, maxY);
609 }
610 else // ! has children
611 {
612 // for a generic window there is no natural best size so, if the
613 // minimal size is not set, use the current size but take care to
614 // remember it as minimal size for the next time because our best size
615 // should be constant: otherwise we could get into a situation when the
616 // window is initially at some size, then expanded to a larger size and
617 // then, when the containing window is shrunk back (because our initial
618 // best size had been used for computing the parent min size), we can't
619 // be shrunk back any more because our best size is now bigger
620 wxSize size = GetMinSize();
621 if ( !size.IsFullySpecified() )
622 {
623 size.SetDefaults(GetSize());
624 wxConstCast(this, wxWindowBase)->SetMinSize(size);
625 }
626
627 // return as-is, unadjusted by the client size difference.
628 return size;
629 }
630
631 // Add any difference between size and client size
632 wxSize diff = GetSize() - GetClientSize();
633 best.x += wxMax(0, diff.x);
634 best.y += wxMax(0, diff.y);
635
636 return best;
637 }
638
639 // helper of GetWindowBorderSize(): as many ports don't implement support for
640 // wxSYS_BORDER/EDGE_X/Y metrics in their wxSystemSettings, use hard coded
641 // fallbacks in this case
642 static int wxGetMetricOrDefault(wxSystemMetric what, const wxWindowBase* win)
643 {
644 int rc = wxSystemSettings::GetMetric(
645 what, static_cast<wxWindow*>(const_cast<wxWindowBase*>(win)));
646 if ( rc == -1 )
647 {
648 switch ( what )
649 {
650 case wxSYS_BORDER_X:
651 case wxSYS_BORDER_Y:
652 // 2D border is by default 1 pixel wide
653 rc = 1;
654 break;
655
656 case wxSYS_EDGE_X:
657 case wxSYS_EDGE_Y:
658 // 3D borders are by default 2 pixels
659 rc = 2;
660 break;
661
662 default:
663 wxFAIL_MSG( _T("unexpected wxGetMetricOrDefault() argument") );
664 rc = 0;
665 }
666 }
667
668 return rc;
669 }
670
671 wxSize wxWindowBase::GetWindowBorderSize() const
672 {
673 wxSize size;
674
675 switch ( GetBorder() )
676 {
677 case wxBORDER_NONE:
678 // nothing to do, size is already (0, 0)
679 break;
680
681 case wxBORDER_SIMPLE:
682 case wxBORDER_STATIC:
683 size.x = wxGetMetricOrDefault(wxSYS_BORDER_X, this);
684 size.y = wxGetMetricOrDefault(wxSYS_BORDER_Y, this);
685 break;
686
687 case wxBORDER_SUNKEN:
688 case wxBORDER_RAISED:
689 size.x = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_X, this),
690 wxGetMetricOrDefault(wxSYS_BORDER_X, this));
691 size.y = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_Y, this),
692 wxGetMetricOrDefault(wxSYS_BORDER_Y, this));
693 break;
694
695 case wxBORDER_DOUBLE:
696 size.x = wxGetMetricOrDefault(wxSYS_EDGE_X, this) +
697 wxGetMetricOrDefault(wxSYS_BORDER_X, this);
698 size.y = wxGetMetricOrDefault(wxSYS_EDGE_Y, this) +
699 wxGetMetricOrDefault(wxSYS_BORDER_Y, this);
700 break;
701
702 default:
703 wxFAIL_MSG(_T("Unknown border style."));
704 break;
705 }
706
707 // we have borders on both sides
708 return size*2;
709 }
710
711 wxSize wxWindowBase::GetEffectiveMinSize() const
712 {
713 // merge the best size with the min size, giving priority to the min size
714 wxSize min = GetMinSize();
715
716 if (min.x == wxDefaultCoord || min.y == wxDefaultCoord)
717 {
718 wxSize best = GetBestSize();
719 if (min.x == wxDefaultCoord) min.x = best.x;
720 if (min.y == wxDefaultCoord) min.y = best.y;
721 }
722
723 return min;
724 }
725
726 wxSize wxWindowBase::GetBestSize() const
727 {
728 if ((!m_windowSizer) && (m_bestSizeCache.IsFullySpecified()))
729 return m_bestSizeCache;
730
731 return DoGetBestSize();
732 }
733
734 void wxWindowBase::SetMinSize(const wxSize& minSize)
735 {
736 m_minWidth = minSize.x;
737 m_minHeight = minSize.y;
738 }
739
740 void wxWindowBase::SetMaxSize(const wxSize& maxSize)
741 {
742 m_maxWidth = maxSize.x;
743 m_maxHeight = maxSize.y;
744 }
745
746 void wxWindowBase::SetInitialSize(const wxSize& size)
747 {
748 // Set the min size to the size passed in. This will usually either be
749 // wxDefaultSize or the size passed to this window's ctor/Create function.
750 SetMinSize(size);
751
752 // Merge the size with the best size if needed
753 wxSize best = GetEffectiveMinSize();
754
755 // If the current size doesn't match then change it
756 if (GetSize() != best)
757 SetSize(best);
758 }
759
760
761 // by default the origin is not shifted
762 wxPoint wxWindowBase::GetClientAreaOrigin() const
763 {
764 return wxPoint(0,0);
765 }
766
767 wxSize wxWindowBase::ClientToWindowSize(const wxSize& size) const
768 {
769 const wxSize diff(GetSize() - GetClientSize());
770
771 return wxSize(size.x == -1 ? -1 : size.x + diff.x,
772 size.y == -1 ? -1 : size.y + diff.y);
773 }
774
775 wxSize wxWindowBase::WindowToClientSize(const wxSize& size) const
776 {
777 const wxSize diff(GetSize() - GetClientSize());
778
779 return wxSize(size.x == -1 ? -1 : size.x - diff.x,
780 size.y == -1 ? -1 : size.y - diff.y);
781 }
782
783 void wxWindowBase::SetWindowVariant( wxWindowVariant variant )
784 {
785 if ( m_windowVariant != variant )
786 {
787 m_windowVariant = variant;
788
789 DoSetWindowVariant(variant);
790 }
791 }
792
793 void wxWindowBase::DoSetWindowVariant( wxWindowVariant variant )
794 {
795 // adjust the font height to correspond to our new variant (notice that
796 // we're only called if something really changed)
797 wxFont font = GetFont();
798 int size = font.GetPointSize();
799 switch ( variant )
800 {
801 case wxWINDOW_VARIANT_NORMAL:
802 break;
803
804 case wxWINDOW_VARIANT_SMALL:
805 size *= 3;
806 size /= 4;
807 break;
808
809 case wxWINDOW_VARIANT_MINI:
810 size *= 2;
811 size /= 3;
812 break;
813
814 case wxWINDOW_VARIANT_LARGE:
815 size *= 5;
816 size /= 4;
817 break;
818
819 default:
820 wxFAIL_MSG(_T("unexpected window variant"));
821 break;
822 }
823
824 font.SetPointSize(size);
825 SetFont(font);
826 }
827
828 void wxWindowBase::DoSetSizeHints( int minW, int minH,
829 int maxW, int maxH,
830 int WXUNUSED(incW), int WXUNUSED(incH) )
831 {
832 wxCHECK_RET( (minW == wxDefaultCoord || maxW == wxDefaultCoord || minW <= maxW) &&
833 (minH == wxDefaultCoord || maxH == wxDefaultCoord || minH <= maxH),
834 _T("min width/height must be less than max width/height!") );
835
836 m_minWidth = minW;
837 m_maxWidth = maxW;
838 m_minHeight = minH;
839 m_maxHeight = maxH;
840 }
841
842
843 #if WXWIN_COMPATIBILITY_2_8
844 void wxWindowBase::SetVirtualSizeHints(int WXUNUSED(minW), int WXUNUSED(minH),
845 int WXUNUSED(maxW), int WXUNUSED(maxH))
846 {
847 }
848
849 void wxWindowBase::SetVirtualSizeHints(const wxSize& WXUNUSED(minsize),
850 const wxSize& WXUNUSED(maxsize))
851 {
852 }
853 #endif // WXWIN_COMPATIBILITY_2_8
854
855 void wxWindowBase::DoSetVirtualSize( int x, int y )
856 {
857 m_virtualSize = wxSize(x, y);
858 }
859
860 wxSize wxWindowBase::DoGetVirtualSize() const
861 {
862 // we should use the entire client area so if it is greater than our
863 // virtual size, expand it to fit (otherwise if the window is big enough we
864 // wouldn't be using parts of it)
865 wxSize size = GetClientSize();
866 if ( m_virtualSize.x > size.x )
867 size.x = m_virtualSize.x;
868
869 if ( m_virtualSize.y >= size.y )
870 size.y = m_virtualSize.y;
871
872 return size;
873 }
874
875 void wxWindowBase::DoGetScreenPosition(int *x, int *y) const
876 {
877 // screen position is the same as (0, 0) in client coords for non TLWs (and
878 // TLWs override this method)
879 if ( x )
880 *x = 0;
881 if ( y )
882 *y = 0;
883
884 ClientToScreen(x, y);
885 }
886
887 void wxWindowBase::SendSizeEvent(int flags)
888 {
889 wxSizeEvent event(GetSize(), GetId());
890 event.SetEventObject(this);
891 if ( flags & wxSEND_EVENT_POST )
892 wxPostEvent(this, event);
893 else
894 HandleWindowEvent(event);
895 }
896
897 void wxWindowBase::SendSizeEventToParent(int flags)
898 {
899 wxWindow * const parent = GetParent();
900 if ( parent && !parent->IsBeingDeleted() )
901 parent->SendSizeEvent(flags);
902 }
903
904 // ----------------------------------------------------------------------------
905 // show/hide/enable/disable the window
906 // ----------------------------------------------------------------------------
907
908 bool wxWindowBase::Show(bool show)
909 {
910 if ( show != m_isShown )
911 {
912 m_isShown = show;
913
914 return true;
915 }
916 else
917 {
918 return false;
919 }
920 }
921
922 bool wxWindowBase::IsEnabled() const
923 {
924 return IsThisEnabled() && (IsTopLevel() || !GetParent() || GetParent()->IsEnabled());
925 }
926
927 void wxWindowBase::NotifyWindowOnEnableChange(bool enabled)
928 {
929 #ifndef wxHAS_NATIVE_ENABLED_MANAGEMENT
930 DoEnable(enabled);
931 #endif // !defined(wxHAS_NATIVE_ENABLED_MANAGEMENT)
932
933 OnEnabled(enabled);
934
935 // If we are top-level then the logic doesn't apply - otherwise
936 // showing a modal dialog would result in total greying out (and ungreying
937 // out later) of everything which would be really ugly
938 if ( IsTopLevel() )
939 return;
940
941 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
942 node;
943 node = node->GetNext() )
944 {
945 wxWindowBase * const child = node->GetData();
946 if ( !child->IsTopLevel() && child->IsThisEnabled() )
947 child->NotifyWindowOnEnableChange(enabled);
948 }
949 }
950
951 bool wxWindowBase::Enable(bool enable)
952 {
953 if ( enable == IsThisEnabled() )
954 return false;
955
956 m_isEnabled = enable;
957
958 #ifdef wxHAS_NATIVE_ENABLED_MANAGEMENT
959 DoEnable(enable);
960 #else // !defined(wxHAS_NATIVE_ENABLED_MANAGEMENT)
961 wxWindowBase * const parent = GetParent();
962 if( !IsTopLevel() && parent && !parent->IsEnabled() )
963 {
964 return true;
965 }
966 #endif // !defined(wxHAS_NATIVE_ENABLED_MANAGEMENT)
967
968 NotifyWindowOnEnableChange(enable);
969
970 return true;
971 }
972
973 bool wxWindowBase::IsShownOnScreen() const
974 {
975 // A window is shown on screen if it itself is shown and so are all its
976 // parents. But if a window is toplevel one, then its always visible on
977 // screen if IsShown() returns true, even if it has a hidden parent.
978 return IsShown() &&
979 (IsTopLevel() || GetParent() == NULL || GetParent()->IsShownOnScreen());
980 }
981
982 // ----------------------------------------------------------------------------
983 // RTTI
984 // ----------------------------------------------------------------------------
985
986 bool wxWindowBase::IsTopLevel() const
987 {
988 return false;
989 }
990
991 // ----------------------------------------------------------------------------
992 // Freeze/Thaw
993 // ----------------------------------------------------------------------------
994
995 void wxWindowBase::Freeze()
996 {
997 if ( !m_freezeCount++ )
998 {
999 // physically freeze this window:
1000 DoFreeze();
1001
1002 // and recursively freeze all children:
1003 for ( wxWindowList::iterator i = GetChildren().begin();
1004 i != GetChildren().end(); ++i )
1005 {
1006 wxWindow *child = *i;
1007 if ( child->IsTopLevel() )
1008 continue;
1009
1010 child->Freeze();
1011 }
1012 }
1013 }
1014
1015 void wxWindowBase::Thaw()
1016 {
1017 wxASSERT_MSG( m_freezeCount, "Thaw() without matching Freeze()" );
1018
1019 if ( !--m_freezeCount )
1020 {
1021 // recursively thaw all children:
1022 for ( wxWindowList::iterator i = GetChildren().begin();
1023 i != GetChildren().end(); ++i )
1024 {
1025 wxWindow *child = *i;
1026 if ( child->IsTopLevel() )
1027 continue;
1028
1029 child->Thaw();
1030 }
1031
1032 // physically thaw this window:
1033 DoThaw();
1034 }
1035 }
1036
1037 // ----------------------------------------------------------------------------
1038 // reparenting the window
1039 // ----------------------------------------------------------------------------
1040
1041 void wxWindowBase::AddChild(wxWindowBase *child)
1042 {
1043 wxCHECK_RET( child, wxT("can't add a NULL child") );
1044
1045 // this should never happen and it will lead to a crash later if it does
1046 // because RemoveChild() will remove only one node from the children list
1047 // and the other(s) one(s) will be left with dangling pointers in them
1048 wxASSERT_MSG( !GetChildren().Find((wxWindow*)child), _T("AddChild() called twice") );
1049
1050 GetChildren().Append((wxWindow*)child);
1051 child->SetParent(this);
1052
1053 // adding a child while frozen will assert when thawed, so freeze it as if
1054 // it had been already present when we were frozen
1055 if ( IsFrozen() && !child->IsTopLevel() )
1056 child->Freeze();
1057 }
1058
1059 void wxWindowBase::RemoveChild(wxWindowBase *child)
1060 {
1061 wxCHECK_RET( child, wxT("can't remove a NULL child") );
1062
1063 // removing a child while frozen may result in permanently frozen window
1064 // if used e.g. from Reparent(), so thaw it
1065 //
1066 // NB: IsTopLevel() doesn't return true any more when a TLW child is being
1067 // removed from its ~wxWindowBase, so check for IsBeingDeleted() too
1068 if ( IsFrozen() && !child->IsBeingDeleted() && !child->IsTopLevel() )
1069 child->Thaw();
1070
1071 GetChildren().DeleteObject((wxWindow *)child);
1072 child->SetParent(NULL);
1073 }
1074
1075 bool wxWindowBase::Reparent(wxWindowBase *newParent)
1076 {
1077 wxWindow *oldParent = GetParent();
1078 if ( newParent == oldParent )
1079 {
1080 // nothing done
1081 return false;
1082 }
1083
1084 const bool oldEnabledState = IsEnabled();
1085
1086 // unlink this window from the existing parent.
1087 if ( oldParent )
1088 {
1089 oldParent->RemoveChild(this);
1090 }
1091 else
1092 {
1093 wxTopLevelWindows.DeleteObject((wxWindow *)this);
1094 }
1095
1096 // add it to the new one
1097 if ( newParent )
1098 {
1099 newParent->AddChild(this);
1100 }
1101 else
1102 {
1103 wxTopLevelWindows.Append((wxWindow *)this);
1104 }
1105
1106 // We need to notify window (and its subwindows) if by changing the parent
1107 // we also change our enabled/disabled status.
1108 const bool newEnabledState = IsEnabled();
1109 if ( newEnabledState != oldEnabledState )
1110 {
1111 NotifyWindowOnEnableChange(newEnabledState);
1112 }
1113
1114 return true;
1115 }
1116
1117 // ----------------------------------------------------------------------------
1118 // event handler stuff
1119 // ----------------------------------------------------------------------------
1120
1121 void wxWindowBase::SetEventHandler(wxEvtHandler *handler)
1122 {
1123 wxCHECK_RET(handler != NULL, "SetEventHandler(NULL) called");
1124
1125 m_eventHandler = handler;
1126 }
1127
1128 void wxWindowBase::SetNextHandler(wxEvtHandler *WXUNUSED(handler))
1129 {
1130 // disable wxEvtHandler chain mechanism for wxWindows:
1131 // wxWindow uses its own stack mechanism which doesn't mix well with wxEvtHandler's one
1132
1133 wxFAIL_MSG("wxWindow cannot be part of a wxEvtHandler chain");
1134 }
1135 void wxWindowBase::SetPreviousHandler(wxEvtHandler *WXUNUSED(handler))
1136 {
1137 // we can't simply wxFAIL here as in SetNextHandler: in fact the last
1138 // handler of our stack when is destroyed will be Unlink()ed and thus
1139 // will call this function to update the pointer of this window...
1140
1141 //wxFAIL_MSG("wxWindow cannot be part of a wxEvtHandler chain");
1142 }
1143
1144 void wxWindowBase::PushEventHandler(wxEvtHandler *handlerToPush)
1145 {
1146 wxCHECK_RET( handlerToPush != NULL, "PushEventHandler(NULL) called" );
1147
1148 // the new handler is going to be part of the wxWindow stack of event handlers:
1149 // it can't be part also of an event handler double-linked chain:
1150 wxASSERT_MSG(handlerToPush->IsUnlinked(),
1151 "The handler being pushed in the wxWindow stack shouldn't be part of "
1152 "a wxEvtHandler chain; call Unlink() on it first");
1153
1154 wxEvtHandler *handlerOld = GetEventHandler();
1155 wxCHECK_RET( handlerOld, "an old event handler is NULL?" );
1156
1157 // now use wxEvtHandler double-linked list to implement a stack:
1158 handlerToPush->SetNextHandler(handlerOld);
1159
1160 if (handlerOld != this)
1161 handlerOld->SetPreviousHandler(handlerToPush);
1162
1163 SetEventHandler(handlerToPush);
1164
1165 #ifdef __WXDEBUG__
1166 // final checks of the operations done above:
1167 wxASSERT_MSG( handlerToPush->GetPreviousHandler() == NULL,
1168 "the first handler of the wxWindow stack should have no previous handlers set" );
1169 wxASSERT_MSG( handlerToPush->GetNextHandler() != NULL,
1170 "the first handler of the wxWindow stack should have non-NULL next handler" );
1171
1172 wxEvtHandler* pLast = handlerToPush;
1173 while (pLast && pLast != this)
1174 pLast = pLast->GetNextHandler();
1175 wxASSERT_MSG( pLast->GetNextHandler() == NULL,
1176 "the last handler of the wxWindow stack should have this window as next handler" );
1177 #endif
1178 }
1179
1180 wxEvtHandler *wxWindowBase::PopEventHandler(bool deleteHandler)
1181 {
1182 // we need to pop the wxWindow stack, i.e. we need to remove the first handler
1183
1184 wxEvtHandler *firstHandler = GetEventHandler();
1185 wxCHECK_MSG( firstHandler != NULL, NULL, "wxWindow cannot have a NULL event handler" );
1186 wxCHECK_MSG( firstHandler != this, NULL, "cannot pop the wxWindow itself" );
1187 wxCHECK_MSG( firstHandler->GetPreviousHandler() == NULL, NULL,
1188 "the first handler of the wxWindow stack should have no previous handlers set" );
1189
1190 wxEvtHandler *secondHandler = firstHandler->GetNextHandler();
1191 wxCHECK_MSG( secondHandler != NULL, NULL,
1192 "the first handler of the wxWindow stack should have non-NULL next handler" );
1193
1194 firstHandler->SetNextHandler(NULL);
1195 secondHandler->SetPreviousHandler(NULL);
1196
1197 // now firstHandler is completely unlinked; set secondHandler as the new window event handler
1198 SetEventHandler(secondHandler);
1199
1200 if ( deleteHandler )
1201 {
1202 delete firstHandler;
1203 firstHandler = NULL;
1204 }
1205
1206 return firstHandler;
1207 }
1208
1209 bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handlerToRemove)
1210 {
1211 wxCHECK_MSG( handlerToRemove != NULL, false, "RemoveEventHandler(NULL) called" );
1212 wxCHECK_MSG( handlerToRemove != this, false, "Cannot remove the window itself" );
1213
1214 if (handlerToRemove == GetEventHandler())
1215 {
1216 // removing the first event handler is equivalent to "popping" the stack
1217 PopEventHandler(false);
1218 return true;
1219 }
1220
1221 // NOTE: the wxWindow event handler list is always terminated with "this" handler
1222 wxEvtHandler *handlerCur = GetEventHandler()->GetNextHandler();
1223 while ( handlerCur != this )
1224 {
1225 wxEvtHandler *handlerNext = handlerCur->GetNextHandler();
1226
1227 if ( handlerCur == handlerToRemove )
1228 {
1229 handlerCur->Unlink();
1230
1231 wxASSERT_MSG( handlerCur != GetEventHandler(),
1232 "the case Remove == Pop should was already handled" );
1233 return true;
1234 }
1235
1236 handlerCur = handlerNext;
1237 }
1238
1239 wxFAIL_MSG( _T("where has the event handler gone?") );
1240
1241 return false;
1242 }
1243
1244 bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
1245 {
1246 // SafelyProcessEvent() will handle exceptions nicely
1247 return GetEventHandler()->SafelyProcessEvent(event);
1248 }
1249
1250 // ----------------------------------------------------------------------------
1251 // colours, fonts &c
1252 // ----------------------------------------------------------------------------
1253
1254 void wxWindowBase::InheritAttributes()
1255 {
1256 const wxWindowBase * const parent = GetParent();
1257 if ( !parent )
1258 return;
1259
1260 // we only inherit attributes which had been explicitly set for the parent
1261 // which ensures that this only happens if the user really wants it and
1262 // not by default which wouldn't make any sense in modern GUIs where the
1263 // controls don't all use the same fonts (nor colours)
1264 if ( parent->m_inheritFont && !m_hasFont )
1265 SetFont(parent->GetFont());
1266
1267 // in addition, there is a possibility to explicitly forbid inheriting
1268 // colours at each class level by overriding ShouldInheritColours()
1269 if ( ShouldInheritColours() )
1270 {
1271 if ( parent->m_inheritFgCol && !m_hasFgCol )
1272 SetForegroundColour(parent->GetForegroundColour());
1273
1274 // inheriting (solid) background colour is wrong as it totally breaks
1275 // any kind of themed backgrounds
1276 //
1277 // instead, the controls should use the same background as their parent
1278 // (ideally by not drawing it at all)
1279 #if 0
1280 if ( parent->m_inheritBgCol && !m_hasBgCol )
1281 SetBackgroundColour(parent->GetBackgroundColour());
1282 #endif // 0
1283 }
1284 }
1285
1286 /* static */ wxVisualAttributes
1287 wxWindowBase::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
1288 {
1289 // it is important to return valid values for all attributes from here,
1290 // GetXXX() below rely on this
1291 wxVisualAttributes attrs;
1292 attrs.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
1293 attrs.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
1294
1295 // On Smartphone/PocketPC, wxSYS_COLOUR_WINDOW is a better reflection of
1296 // the usual background colour than wxSYS_COLOUR_BTNFACE.
1297 // It's a pity that wxSYS_COLOUR_WINDOW isn't always a suitable background
1298 // colour on other platforms.
1299
1300 #if defined(__WXWINCE__) && (defined(__SMARTPHONE__) || defined(__POCKETPC__))
1301 attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
1302 #else
1303 attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
1304 #endif
1305 return attrs;
1306 }
1307
1308 wxColour wxWindowBase::GetBackgroundColour() const
1309 {
1310 if ( !m_backgroundColour.IsOk() )
1311 {
1312 wxASSERT_MSG( !m_hasBgCol, _T("we have invalid explicit bg colour?") );
1313
1314 // get our default background colour
1315 wxColour colBg = GetDefaultAttributes().colBg;
1316
1317 // we must return some valid colour to avoid redoing this every time
1318 // and also to avoid surprizing the applications written for older
1319 // wxWidgets versions where GetBackgroundColour() always returned
1320 // something -- so give them something even if it doesn't make sense
1321 // for this window (e.g. it has a themed background)
1322 if ( !colBg.Ok() )
1323 colBg = GetClassDefaultAttributes().colBg;
1324
1325 return colBg;
1326 }
1327 else
1328 return m_backgroundColour;
1329 }
1330
1331 wxColour wxWindowBase::GetForegroundColour() const
1332 {
1333 // logic is the same as above
1334 if ( !m_hasFgCol && !m_foregroundColour.Ok() )
1335 {
1336 wxColour colFg = GetDefaultAttributes().colFg;
1337
1338 if ( !colFg.IsOk() )
1339 colFg = GetClassDefaultAttributes().colFg;
1340
1341 return colFg;
1342 }
1343 else
1344 return m_foregroundColour;
1345 }
1346
1347 bool wxWindowBase::SetBackgroundColour( const wxColour &colour )
1348 {
1349 if ( colour == m_backgroundColour )
1350 return false;
1351
1352 m_hasBgCol = colour.IsOk();
1353 if ( m_backgroundStyle != wxBG_STYLE_CUSTOM )
1354 m_backgroundStyle = m_hasBgCol ? wxBG_STYLE_COLOUR : wxBG_STYLE_SYSTEM;
1355
1356 m_inheritBgCol = m_hasBgCol;
1357 m_backgroundColour = colour;
1358 SetThemeEnabled( !m_hasBgCol && !m_foregroundColour.Ok() );
1359 return true;
1360 }
1361
1362 bool wxWindowBase::SetForegroundColour( const wxColour &colour )
1363 {
1364 if (colour == m_foregroundColour )
1365 return false;
1366
1367 m_hasFgCol = colour.IsOk();
1368 m_inheritFgCol = m_hasFgCol;
1369 m_foregroundColour = colour;
1370 SetThemeEnabled( !m_hasFgCol && !m_backgroundColour.Ok() );
1371 return true;
1372 }
1373
1374 bool wxWindowBase::SetCursor(const wxCursor& cursor)
1375 {
1376 // setting an invalid cursor is ok, it means that we don't have any special
1377 // cursor
1378 if ( m_cursor.IsSameAs(cursor) )
1379 {
1380 // no change
1381 return false;
1382 }
1383
1384 m_cursor = cursor;
1385
1386 return true;
1387 }
1388
1389 wxFont wxWindowBase::GetFont() const
1390 {
1391 // logic is the same as in GetBackgroundColour()
1392 if ( !m_font.IsOk() )
1393 {
1394 wxASSERT_MSG( !m_hasFont, _T("we have invalid explicit font?") );
1395
1396 wxFont font = GetDefaultAttributes().font;
1397 if ( !font.IsOk() )
1398 font = GetClassDefaultAttributes().font;
1399
1400 return font;
1401 }
1402 else
1403 return m_font;
1404 }
1405
1406 bool wxWindowBase::SetFont(const wxFont& font)
1407 {
1408 if ( font == m_font )
1409 {
1410 // no change
1411 return false;
1412 }
1413
1414 m_font = font;
1415 m_hasFont = font.IsOk();
1416 m_inheritFont = m_hasFont;
1417
1418 InvalidateBestSize();
1419
1420 return true;
1421 }
1422
1423 #if wxUSE_PALETTE
1424
1425 void wxWindowBase::SetPalette(const wxPalette& pal)
1426 {
1427 m_hasCustomPalette = true;
1428 m_palette = pal;
1429
1430 // VZ: can anyone explain me what do we do here?
1431 wxWindowDC d((wxWindow *) this);
1432 d.SetPalette(pal);
1433 }
1434
1435 wxWindow *wxWindowBase::GetAncestorWithCustomPalette() const
1436 {
1437 wxWindow *win = (wxWindow *)this;
1438 while ( win && !win->HasCustomPalette() )
1439 {
1440 win = win->GetParent();
1441 }
1442
1443 return win;
1444 }
1445
1446 #endif // wxUSE_PALETTE
1447
1448 #if wxUSE_CARET
1449 void wxWindowBase::SetCaret(wxCaret *caret)
1450 {
1451 if ( m_caret )
1452 {
1453 delete m_caret;
1454 }
1455
1456 m_caret = caret;
1457
1458 if ( m_caret )
1459 {
1460 wxASSERT_MSG( m_caret->GetWindow() == this,
1461 wxT("caret should be created associated to this window") );
1462 }
1463 }
1464 #endif // wxUSE_CARET
1465
1466 #if wxUSE_VALIDATORS
1467 // ----------------------------------------------------------------------------
1468 // validators
1469 // ----------------------------------------------------------------------------
1470
1471 void wxWindowBase::SetValidator(const wxValidator& validator)
1472 {
1473 if ( m_windowValidator )
1474 delete m_windowValidator;
1475
1476 m_windowValidator = (wxValidator *)validator.Clone();
1477
1478 if ( m_windowValidator )
1479 m_windowValidator->SetWindow(this);
1480 }
1481 #endif // wxUSE_VALIDATORS
1482
1483 // ----------------------------------------------------------------------------
1484 // update region stuff
1485 // ----------------------------------------------------------------------------
1486
1487 wxRect wxWindowBase::GetUpdateClientRect() const
1488 {
1489 wxRegion rgnUpdate = GetUpdateRegion();
1490 rgnUpdate.Intersect(GetClientRect());
1491 wxRect rectUpdate = rgnUpdate.GetBox();
1492 wxPoint ptOrigin = GetClientAreaOrigin();
1493 rectUpdate.x -= ptOrigin.x;
1494 rectUpdate.y -= ptOrigin.y;
1495
1496 return rectUpdate;
1497 }
1498
1499 bool wxWindowBase::DoIsExposed(int x, int y) const
1500 {
1501 return m_updateRegion.Contains(x, y) != wxOutRegion;
1502 }
1503
1504 bool wxWindowBase::DoIsExposed(int x, int y, int w, int h) const
1505 {
1506 return m_updateRegion.Contains(x, y, w, h) != wxOutRegion;
1507 }
1508
1509 void wxWindowBase::ClearBackground()
1510 {
1511 // wxGTK uses its own version, no need to add never used code
1512 #ifndef __WXGTK__
1513 wxClientDC dc((wxWindow *)this);
1514 wxBrush brush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID);
1515 dc.SetBackground(brush);
1516 dc.Clear();
1517 #endif // __WXGTK__
1518 }
1519
1520 // ----------------------------------------------------------------------------
1521 // find child window by id or name
1522 // ----------------------------------------------------------------------------
1523
1524 wxWindow *wxWindowBase::FindWindow(long id) const
1525 {
1526 if ( id == m_windowId )
1527 return (wxWindow *)this;
1528
1529 wxWindowBase *res = NULL;
1530 wxWindowList::compatibility_iterator node;
1531 for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() )
1532 {
1533 wxWindowBase *child = node->GetData();
1534 res = child->FindWindow( id );
1535 }
1536
1537 return (wxWindow *)res;
1538 }
1539
1540 wxWindow *wxWindowBase::FindWindow(const wxString& name) const
1541 {
1542 if ( name == m_windowName )
1543 return (wxWindow *)this;
1544
1545 wxWindowBase *res = NULL;
1546 wxWindowList::compatibility_iterator node;
1547 for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() )
1548 {
1549 wxWindow *child = node->GetData();
1550 res = child->FindWindow(name);
1551 }
1552
1553 return (wxWindow *)res;
1554 }
1555
1556
1557 // find any window by id or name or label: If parent is non-NULL, look through
1558 // children for a label or title matching the specified string. If NULL, look
1559 // through all top-level windows.
1560 //
1561 // to avoid duplicating code we reuse the same helper function but with
1562 // different comparators
1563
1564 typedef bool (*wxFindWindowCmp)(const wxWindow *win,
1565 const wxString& label, long id);
1566
1567 static
1568 bool wxFindWindowCmpLabels(const wxWindow *win, const wxString& label,
1569 long WXUNUSED(id))
1570 {
1571 return win->GetLabel() == label;
1572 }
1573
1574 static
1575 bool wxFindWindowCmpNames(const wxWindow *win, const wxString& label,
1576 long WXUNUSED(id))
1577 {
1578 return win->GetName() == label;
1579 }
1580
1581 static
1582 bool wxFindWindowCmpIds(const wxWindow *win, const wxString& WXUNUSED(label),
1583 long id)
1584 {
1585 return win->GetId() == id;
1586 }
1587
1588 // recursive helper for the FindWindowByXXX() functions
1589 static
1590 wxWindow *wxFindWindowRecursively(const wxWindow *parent,
1591 const wxString& label,
1592 long id,
1593 wxFindWindowCmp cmp)
1594 {
1595 if ( parent )
1596 {
1597 // see if this is the one we're looking for
1598 if ( (*cmp)(parent, label, id) )
1599 return (wxWindow *)parent;
1600
1601 // It wasn't, so check all its children
1602 for ( wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst();
1603 node;
1604 node = node->GetNext() )
1605 {
1606 // recursively check each child
1607 wxWindow *win = (wxWindow *)node->GetData();
1608 wxWindow *retwin = wxFindWindowRecursively(win, label, id, cmp);
1609 if (retwin)
1610 return retwin;
1611 }
1612 }
1613
1614 // Not found
1615 return NULL;
1616 }
1617
1618 // helper for FindWindowByXXX()
1619 static
1620 wxWindow *wxFindWindowHelper(const wxWindow *parent,
1621 const wxString& label,
1622 long id,
1623 wxFindWindowCmp cmp)
1624 {
1625 if ( parent )
1626 {
1627 // just check parent and all its children
1628 return wxFindWindowRecursively(parent, label, id, cmp);
1629 }
1630
1631 // start at very top of wx's windows
1632 for ( wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
1633 node;
1634 node = node->GetNext() )
1635 {
1636 // recursively check each window & its children
1637 wxWindow *win = node->GetData();
1638 wxWindow *retwin = wxFindWindowRecursively(win, label, id, cmp);
1639 if (retwin)
1640 return retwin;
1641 }
1642
1643 return NULL;
1644 }
1645
1646 /* static */
1647 wxWindow *
1648 wxWindowBase::FindWindowByLabel(const wxString& title, const wxWindow *parent)
1649 {
1650 return wxFindWindowHelper(parent, title, 0, wxFindWindowCmpLabels);
1651 }
1652
1653 /* static */
1654 wxWindow *
1655 wxWindowBase::FindWindowByName(const wxString& title, const wxWindow *parent)
1656 {
1657 wxWindow *win = wxFindWindowHelper(parent, title, 0, wxFindWindowCmpNames);
1658
1659 if ( !win )
1660 {
1661 // fall back to the label
1662 win = FindWindowByLabel(title, parent);
1663 }
1664
1665 return win;
1666 }
1667
1668 /* static */
1669 wxWindow *
1670 wxWindowBase::FindWindowById( long id, const wxWindow* parent )
1671 {
1672 return wxFindWindowHelper(parent, wxEmptyString, id, wxFindWindowCmpIds);
1673 }
1674
1675 // ----------------------------------------------------------------------------
1676 // dialog oriented functions
1677 // ----------------------------------------------------------------------------
1678
1679 void wxWindowBase::MakeModal(bool modal)
1680 {
1681 // Disable all other windows
1682 if ( IsTopLevel() )
1683 {
1684 wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
1685 while (node)
1686 {
1687 wxWindow *win = node->GetData();
1688 if (win != this)
1689 win->Enable(!modal);
1690
1691 node = node->GetNext();
1692 }
1693 }
1694 }
1695
1696 bool wxWindowBase::Validate()
1697 {
1698 #if wxUSE_VALIDATORS
1699 bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0;
1700
1701 wxWindowList::compatibility_iterator node;
1702 for ( node = m_children.GetFirst(); node; node = node->GetNext() )
1703 {
1704 wxWindowBase *child = node->GetData();
1705 wxValidator *validator = child->GetValidator();
1706 if ( validator && !validator->Validate((wxWindow *)this) )
1707 {
1708 return false;
1709 }
1710
1711 if ( recurse && !child->Validate() )
1712 {
1713 return false;
1714 }
1715 }
1716 #endif // wxUSE_VALIDATORS
1717
1718 return true;
1719 }
1720
1721 bool wxWindowBase::TransferDataToWindow()
1722 {
1723 #if wxUSE_VALIDATORS
1724 bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0;
1725
1726 wxWindowList::compatibility_iterator node;
1727 for ( node = m_children.GetFirst(); node; node = node->GetNext() )
1728 {
1729 wxWindowBase *child = node->GetData();
1730 wxValidator *validator = child->GetValidator();
1731 if ( validator && !validator->TransferToWindow() )
1732 {
1733 wxLogWarning(_("Could not transfer data to window"));
1734 #if wxUSE_LOG
1735 wxLog::FlushActive();
1736 #endif // wxUSE_LOG
1737
1738 return false;
1739 }
1740
1741 if ( recurse )
1742 {
1743 if ( !child->TransferDataToWindow() )
1744 {
1745 // warning already given
1746 return false;
1747 }
1748 }
1749 }
1750 #endif // wxUSE_VALIDATORS
1751
1752 return true;
1753 }
1754
1755 bool wxWindowBase::TransferDataFromWindow()
1756 {
1757 #if wxUSE_VALIDATORS
1758 bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0;
1759
1760 wxWindowList::compatibility_iterator node;
1761 for ( node = m_children.GetFirst(); node; node = node->GetNext() )
1762 {
1763 wxWindow *child = node->GetData();
1764 wxValidator *validator = child->GetValidator();
1765 if ( validator && !validator->TransferFromWindow() )
1766 {
1767 // nop warning here because the application is supposed to give
1768 // one itself - we don't know here what might have gone wrongly
1769
1770 return false;
1771 }
1772
1773 if ( recurse )
1774 {
1775 if ( !child->TransferDataFromWindow() )
1776 {
1777 // warning already given
1778 return false;
1779 }
1780 }
1781 }
1782 #endif // wxUSE_VALIDATORS
1783
1784 return true;
1785 }
1786
1787 void wxWindowBase::InitDialog()
1788 {
1789 wxInitDialogEvent event(GetId());
1790 event.SetEventObject( this );
1791 GetEventHandler()->ProcessEvent(event);
1792 }
1793
1794 // ----------------------------------------------------------------------------
1795 // context-sensitive help support
1796 // ----------------------------------------------------------------------------
1797
1798 #if wxUSE_HELP
1799
1800 // associate this help text with this window
1801 void wxWindowBase::SetHelpText(const wxString& text)
1802 {
1803 wxHelpProvider *helpProvider = wxHelpProvider::Get();
1804 if ( helpProvider )
1805 {
1806 helpProvider->AddHelp(this, text);
1807 }
1808 }
1809
1810 #if WXWIN_COMPATIBILITY_2_8
1811 // associate this help text with all windows with the same id as this
1812 // one
1813 void wxWindowBase::SetHelpTextForId(const wxString& text)
1814 {
1815 wxHelpProvider *helpProvider = wxHelpProvider::Get();
1816 if ( helpProvider )
1817 {
1818 helpProvider->AddHelp(GetId(), text);
1819 }
1820 }
1821 #endif // WXWIN_COMPATIBILITY_2_8
1822
1823 // get the help string associated with this window (may be empty)
1824 // default implementation forwards calls to the help provider
1825 wxString
1826 wxWindowBase::GetHelpTextAtPoint(const wxPoint & WXUNUSED(pt),
1827 wxHelpEvent::Origin WXUNUSED(origin)) const
1828 {
1829 wxString text;
1830 wxHelpProvider *helpProvider = wxHelpProvider::Get();
1831 if ( helpProvider )
1832 {
1833 text = helpProvider->GetHelp(this);
1834 }
1835
1836 return text;
1837 }
1838
1839 // show help for this window
1840 void wxWindowBase::OnHelp(wxHelpEvent& event)
1841 {
1842 wxHelpProvider *helpProvider = wxHelpProvider::Get();
1843 if ( helpProvider )
1844 {
1845 wxPoint pos = event.GetPosition();
1846 const wxHelpEvent::Origin origin = event.GetOrigin();
1847 if ( origin == wxHelpEvent::Origin_Keyboard )
1848 {
1849 // if the help event was generated from keyboard it shouldn't
1850 // appear at the mouse position (which is still the only position
1851 // associated with help event) if the mouse is far away, although
1852 // we still do use the mouse position if it's over the window
1853 // because we suppose the user looks approximately at the mouse
1854 // already and so it would be more convenient than showing tooltip
1855 // at some arbitrary position which can be quite far from it
1856 const wxRect rectClient = GetClientRect();
1857 if ( !rectClient.Contains(ScreenToClient(pos)) )
1858 {
1859 // position help slightly under and to the right of this window
1860 pos = ClientToScreen(wxPoint(
1861 2*GetCharWidth(),
1862 rectClient.height + GetCharHeight()
1863 ));
1864 }
1865 }
1866
1867 if ( helpProvider->ShowHelpAtPoint(this, pos, origin) )
1868 {
1869 // skip the event.Skip() below
1870 return;
1871 }
1872 }
1873
1874 event.Skip();
1875 }
1876
1877 #endif // wxUSE_HELP
1878
1879 // ----------------------------------------------------------------------------
1880 // tooltips
1881 // ----------------------------------------------------------------------------
1882
1883 #if wxUSE_TOOLTIPS
1884
1885 void wxWindowBase::SetToolTip( const wxString &tip )
1886 {
1887 // don't create the new tooltip if we already have one
1888 if ( m_tooltip )
1889 {
1890 m_tooltip->SetTip( tip );
1891 }
1892 else
1893 {
1894 SetToolTip( new wxToolTip( tip ) );
1895 }
1896
1897 // setting empty tooltip text does not remove the tooltip any more - use
1898 // SetToolTip(NULL) for this
1899 }
1900
1901 void wxWindowBase::DoSetToolTip(wxToolTip *tooltip)
1902 {
1903 if ( m_tooltip != tooltip )
1904 {
1905 if ( m_tooltip )
1906 delete m_tooltip;
1907
1908 m_tooltip = tooltip;
1909 }
1910 }
1911
1912 #endif // wxUSE_TOOLTIPS
1913
1914 // ----------------------------------------------------------------------------
1915 // constraints and sizers
1916 // ----------------------------------------------------------------------------
1917
1918 #if wxUSE_CONSTRAINTS
1919
1920 void wxWindowBase::SetConstraints( wxLayoutConstraints *constraints )
1921 {
1922 if ( m_constraints )
1923 {
1924 UnsetConstraints(m_constraints);
1925 delete m_constraints;
1926 }
1927 m_constraints = constraints;
1928 if ( m_constraints )
1929 {
1930 // Make sure other windows know they're part of a 'meaningful relationship'
1931 if ( m_constraints->left.GetOtherWindow() && (m_constraints->left.GetOtherWindow() != this) )
1932 m_constraints->left.GetOtherWindow()->AddConstraintReference(this);
1933 if ( m_constraints->top.GetOtherWindow() && (m_constraints->top.GetOtherWindow() != this) )
1934 m_constraints->top.GetOtherWindow()->AddConstraintReference(this);
1935 if ( m_constraints->right.GetOtherWindow() && (m_constraints->right.GetOtherWindow() != this) )
1936 m_constraints->right.GetOtherWindow()->AddConstraintReference(this);
1937 if ( m_constraints->bottom.GetOtherWindow() && (m_constraints->bottom.GetOtherWindow() != this) )
1938 m_constraints->bottom.GetOtherWindow()->AddConstraintReference(this);
1939 if ( m_constraints->width.GetOtherWindow() && (m_constraints->width.GetOtherWindow() != this) )
1940 m_constraints->width.GetOtherWindow()->AddConstraintReference(this);
1941 if ( m_constraints->height.GetOtherWindow() && (m_constraints->height.GetOtherWindow() != this) )
1942 m_constraints->height.GetOtherWindow()->AddConstraintReference(this);
1943 if ( m_constraints->centreX.GetOtherWindow() && (m_constraints->centreX.GetOtherWindow() != this) )
1944 m_constraints->centreX.GetOtherWindow()->AddConstraintReference(this);
1945 if ( m_constraints->centreY.GetOtherWindow() && (m_constraints->centreY.GetOtherWindow() != this) )
1946 m_constraints->centreY.GetOtherWindow()->AddConstraintReference(this);
1947 }
1948 }
1949
1950 // This removes any dangling pointers to this window in other windows'
1951 // constraintsInvolvedIn lists.
1952 void wxWindowBase::UnsetConstraints(wxLayoutConstraints *c)
1953 {
1954 if ( c )
1955 {
1956 if ( c->left.GetOtherWindow() && (c->top.GetOtherWindow() != this) )
1957 c->left.GetOtherWindow()->RemoveConstraintReference(this);
1958 if ( c->top.GetOtherWindow() && (c->top.GetOtherWindow() != this) )
1959 c->top.GetOtherWindow()->RemoveConstraintReference(this);
1960 if ( c->right.GetOtherWindow() && (c->right.GetOtherWindow() != this) )
1961 c->right.GetOtherWindow()->RemoveConstraintReference(this);
1962 if ( c->bottom.GetOtherWindow() && (c->bottom.GetOtherWindow() != this) )
1963 c->bottom.GetOtherWindow()->RemoveConstraintReference(this);
1964 if ( c->width.GetOtherWindow() && (c->width.GetOtherWindow() != this) )
1965 c->width.GetOtherWindow()->RemoveConstraintReference(this);
1966 if ( c->height.GetOtherWindow() && (c->height.GetOtherWindow() != this) )
1967 c->height.GetOtherWindow()->RemoveConstraintReference(this);
1968 if ( c->centreX.GetOtherWindow() && (c->centreX.GetOtherWindow() != this) )
1969 c->centreX.GetOtherWindow()->RemoveConstraintReference(this);
1970 if ( c->centreY.GetOtherWindow() && (c->centreY.GetOtherWindow() != this) )
1971 c->centreY.GetOtherWindow()->RemoveConstraintReference(this);
1972 }
1973 }
1974
1975 // Back-pointer to other windows we're involved with, so if we delete this
1976 // window, we must delete any constraints we're involved with.
1977 void wxWindowBase::AddConstraintReference(wxWindowBase *otherWin)
1978 {
1979 if ( !m_constraintsInvolvedIn )
1980 m_constraintsInvolvedIn = new wxWindowList;
1981 if ( !m_constraintsInvolvedIn->Find((wxWindow *)otherWin) )
1982 m_constraintsInvolvedIn->Append((wxWindow *)otherWin);
1983 }
1984
1985 // REMOVE back-pointer to other windows we're involved with.
1986 void wxWindowBase::RemoveConstraintReference(wxWindowBase *otherWin)
1987 {
1988 if ( m_constraintsInvolvedIn )
1989 m_constraintsInvolvedIn->DeleteObject((wxWindow *)otherWin);
1990 }
1991
1992 // Reset any constraints that mention this window
1993 void wxWindowBase::DeleteRelatedConstraints()
1994 {
1995 if ( m_constraintsInvolvedIn )
1996 {
1997 wxWindowList::compatibility_iterator node = m_constraintsInvolvedIn->GetFirst();
1998 while (node)
1999 {
2000 wxWindow *win = node->GetData();
2001 wxLayoutConstraints *constr = win->GetConstraints();
2002
2003 // Reset any constraints involving this window
2004 if ( constr )
2005 {
2006 constr->left.ResetIfWin(this);
2007 constr->top.ResetIfWin(this);
2008 constr->right.ResetIfWin(this);
2009 constr->bottom.ResetIfWin(this);
2010 constr->width.ResetIfWin(this);
2011 constr->height.ResetIfWin(this);
2012 constr->centreX.ResetIfWin(this);
2013 constr->centreY.ResetIfWin(this);
2014 }
2015
2016 wxWindowList::compatibility_iterator next = node->GetNext();
2017 m_constraintsInvolvedIn->Erase(node);
2018 node = next;
2019 }
2020
2021 delete m_constraintsInvolvedIn;
2022 m_constraintsInvolvedIn = NULL;
2023 }
2024 }
2025
2026 #endif // wxUSE_CONSTRAINTS
2027
2028 void wxWindowBase::SetSizer(wxSizer *sizer, bool deleteOld)
2029 {
2030 if ( sizer == m_windowSizer)
2031 return;
2032
2033 if ( m_windowSizer )
2034 {
2035 m_windowSizer->SetContainingWindow(NULL);
2036
2037 if ( deleteOld )
2038 delete m_windowSizer;
2039 }
2040
2041 m_windowSizer = sizer;
2042 if ( m_windowSizer )
2043 {
2044 m_windowSizer->SetContainingWindow((wxWindow *)this);
2045 }
2046
2047 SetAutoLayout(m_windowSizer != NULL);
2048 }
2049
2050 void wxWindowBase::SetSizerAndFit(wxSizer *sizer, bool deleteOld)
2051 {
2052 SetSizer( sizer, deleteOld );
2053 sizer->SetSizeHints( (wxWindow*) this );
2054 }
2055
2056
2057 void wxWindowBase::SetContainingSizer(wxSizer* sizer)
2058 {
2059 // adding a window to a sizer twice is going to result in fatal and
2060 // hard to debug problems later because when deleting the second
2061 // associated wxSizerItem we're going to dereference a dangling
2062 // pointer; so try to detect this as early as possible
2063 wxASSERT_MSG( !sizer || m_containingSizer != sizer,
2064 _T("Adding a window to the same sizer twice?") );
2065
2066 m_containingSizer = sizer;
2067 }
2068
2069 #if wxUSE_CONSTRAINTS
2070
2071 void wxWindowBase::SatisfyConstraints()
2072 {
2073 wxLayoutConstraints *constr = GetConstraints();
2074 bool wasOk = constr && constr->AreSatisfied();
2075
2076 ResetConstraints(); // Mark all constraints as unevaluated
2077
2078 int noChanges = 1;
2079
2080 // if we're a top level panel (i.e. our parent is frame/dialog), our
2081 // own constraints will never be satisfied any more unless we do it
2082 // here
2083 if ( wasOk )
2084 {
2085 while ( noChanges > 0 )
2086 {
2087 LayoutPhase1(&noChanges);
2088 }
2089 }
2090
2091 LayoutPhase2(&noChanges);
2092 }
2093
2094 #endif // wxUSE_CONSTRAINTS
2095
2096 bool wxWindowBase::Layout()
2097 {
2098 // If there is a sizer, use it instead of the constraints
2099 if ( GetSizer() )
2100 {
2101 int w = 0, h = 0;
2102 GetVirtualSize(&w, &h);
2103 GetSizer()->SetDimension( 0, 0, w, h );
2104 }
2105 #if wxUSE_CONSTRAINTS
2106 else
2107 {
2108 SatisfyConstraints(); // Find the right constraints values
2109 SetConstraintSizes(); // Recursively set the real window sizes
2110 }
2111 #endif
2112
2113 return true;
2114 }
2115
2116 #if wxUSE_CONSTRAINTS
2117
2118 // first phase of the constraints evaluation: set our own constraints
2119 bool wxWindowBase::LayoutPhase1(int *noChanges)
2120 {
2121 wxLayoutConstraints *constr = GetConstraints();
2122
2123 return !constr || constr->SatisfyConstraints(this, noChanges);
2124 }
2125
2126 // second phase: set the constraints for our children
2127 bool wxWindowBase::LayoutPhase2(int *noChanges)
2128 {
2129 *noChanges = 0;
2130
2131 // Layout children
2132 DoPhase(1);
2133
2134 // Layout grand children
2135 DoPhase(2);
2136
2137 return true;
2138 }
2139
2140 // Do a phase of evaluating child constraints
2141 bool wxWindowBase::DoPhase(int phase)
2142 {
2143 // the list containing the children for which the constraints are already
2144 // set correctly
2145 wxWindowList succeeded;
2146
2147 // the max number of iterations we loop before concluding that we can't set
2148 // the constraints
2149 static const int maxIterations = 500;
2150
2151 for ( int noIterations = 0; noIterations < maxIterations; noIterations++ )
2152 {
2153 int noChanges = 0;
2154
2155 // loop over all children setting their constraints
2156 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
2157 node;
2158 node = node->GetNext() )
2159 {
2160 wxWindow *child = node->GetData();
2161 if ( child->IsTopLevel() )
2162 {
2163 // top level children are not inside our client area
2164 continue;
2165 }
2166
2167 if ( !child->GetConstraints() || succeeded.Find(child) )
2168 {
2169 // this one is either already ok or nothing we can do about it
2170 continue;
2171 }
2172
2173 int tempNoChanges = 0;
2174 bool success = phase == 1 ? child->LayoutPhase1(&tempNoChanges)
2175 : child->LayoutPhase2(&tempNoChanges);
2176 noChanges += tempNoChanges;
2177
2178 if ( success )
2179 {
2180 succeeded.Append(child);
2181 }
2182 }
2183
2184 if ( !noChanges )
2185 {
2186 // constraints are set
2187 break;
2188 }
2189 }
2190
2191 return true;
2192 }
2193
2194 void wxWindowBase::ResetConstraints()
2195 {
2196 wxLayoutConstraints *constr = GetConstraints();
2197 if ( constr )
2198 {
2199 constr->left.SetDone(false);
2200 constr->top.SetDone(false);
2201 constr->right.SetDone(false);
2202 constr->bottom.SetDone(false);
2203 constr->width.SetDone(false);
2204 constr->height.SetDone(false);
2205 constr->centreX.SetDone(false);
2206 constr->centreY.SetDone(false);
2207 }
2208
2209 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
2210 while (node)
2211 {
2212 wxWindow *win = node->GetData();
2213 if ( !win->IsTopLevel() )
2214 win->ResetConstraints();
2215 node = node->GetNext();
2216 }
2217 }
2218
2219 // Need to distinguish between setting the 'fake' size for windows and sizers,
2220 // and setting the real values.
2221 void wxWindowBase::SetConstraintSizes(bool recurse)
2222 {
2223 wxLayoutConstraints *constr = GetConstraints();
2224 if ( constr && constr->AreSatisfied() )
2225 {
2226 int x = constr->left.GetValue();
2227 int y = constr->top.GetValue();
2228 int w = constr->width.GetValue();
2229 int h = constr->height.GetValue();
2230
2231 if ( (constr->width.GetRelationship() != wxAsIs ) ||
2232 (constr->height.GetRelationship() != wxAsIs) )
2233 {
2234 SetSize(x, y, w, h);
2235 }
2236 else
2237 {
2238 // If we don't want to resize this window, just move it...
2239 Move(x, y);
2240 }
2241 }
2242 else if ( constr )
2243 {
2244 wxLogDebug(wxT("Constraints not satisfied for %s named '%s'."),
2245 GetClassInfo()->GetClassName(),
2246 GetName().c_str());
2247 }
2248
2249 if ( recurse )
2250 {
2251 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
2252 while (node)
2253 {
2254 wxWindow *win = node->GetData();
2255 if ( !win->IsTopLevel() && win->GetConstraints() )
2256 win->SetConstraintSizes();
2257 node = node->GetNext();
2258 }
2259 }
2260 }
2261
2262 // Only set the size/position of the constraint (if any)
2263 void wxWindowBase::SetSizeConstraint(int x, int y, int w, int h)
2264 {
2265 wxLayoutConstraints *constr = GetConstraints();
2266 if ( constr )
2267 {
2268 if ( x != wxDefaultCoord )
2269 {
2270 constr->left.SetValue(x);
2271 constr->left.SetDone(true);
2272 }
2273 if ( y != wxDefaultCoord )
2274 {
2275 constr->top.SetValue(y);
2276 constr->top.SetDone(true);
2277 }
2278 if ( w != wxDefaultCoord )
2279 {
2280 constr->width.SetValue(w);
2281 constr->width.SetDone(true);
2282 }
2283 if ( h != wxDefaultCoord )
2284 {
2285 constr->height.SetValue(h);
2286 constr->height.SetDone(true);
2287 }
2288 }
2289 }
2290
2291 void wxWindowBase::MoveConstraint(int x, int y)
2292 {
2293 wxLayoutConstraints *constr = GetConstraints();
2294 if ( constr )
2295 {
2296 if ( x != wxDefaultCoord )
2297 {
2298 constr->left.SetValue(x);
2299 constr->left.SetDone(true);
2300 }
2301 if ( y != wxDefaultCoord )
2302 {
2303 constr->top.SetValue(y);
2304 constr->top.SetDone(true);
2305 }
2306 }
2307 }
2308
2309 void wxWindowBase::GetSizeConstraint(int *w, int *h) const
2310 {
2311 wxLayoutConstraints *constr = GetConstraints();
2312 if ( constr )
2313 {
2314 *w = constr->width.GetValue();
2315 *h = constr->height.GetValue();
2316 }
2317 else
2318 GetSize(w, h);
2319 }
2320
2321 void wxWindowBase::GetClientSizeConstraint(int *w, int *h) const
2322 {
2323 wxLayoutConstraints *constr = GetConstraints();
2324 if ( constr )
2325 {
2326 *w = constr->width.GetValue();
2327 *h = constr->height.GetValue();
2328 }
2329 else
2330 GetClientSize(w, h);
2331 }
2332
2333 void wxWindowBase::GetPositionConstraint(int *x, int *y) const
2334 {
2335 wxLayoutConstraints *constr = GetConstraints();
2336 if ( constr )
2337 {
2338 *x = constr->left.GetValue();
2339 *y = constr->top.GetValue();
2340 }
2341 else
2342 GetPosition(x, y);
2343 }
2344
2345 #endif // wxUSE_CONSTRAINTS
2346
2347 void wxWindowBase::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) const
2348 {
2349 // don't do it for the dialogs/frames - they float independently of their
2350 // parent
2351 if ( !IsTopLevel() )
2352 {
2353 wxWindow *parent = GetParent();
2354 if ( !(sizeFlags & wxSIZE_NO_ADJUSTMENTS) && parent )
2355 {
2356 wxPoint pt(parent->GetClientAreaOrigin());
2357 x += pt.x;
2358 y += pt.y;
2359 }
2360 }
2361 }
2362
2363 // ----------------------------------------------------------------------------
2364 // Update UI processing
2365 // ----------------------------------------------------------------------------
2366
2367 void wxWindowBase::UpdateWindowUI(long flags)
2368 {
2369 wxUpdateUIEvent event(GetId());
2370 event.SetEventObject(this);
2371
2372 if ( GetEventHandler()->ProcessEvent(event) )
2373 {
2374 DoUpdateWindowUI(event);
2375 }
2376
2377 if (flags & wxUPDATE_UI_RECURSE)
2378 {
2379 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
2380 while (node)
2381 {
2382 wxWindow* child = (wxWindow*) node->GetData();
2383 child->UpdateWindowUI(flags);
2384 node = node->GetNext();
2385 }
2386 }
2387 }
2388
2389 // do the window-specific processing after processing the update event
2390 void wxWindowBase::DoUpdateWindowUI(wxUpdateUIEvent& event)
2391 {
2392 if ( event.GetSetEnabled() )
2393 Enable(event.GetEnabled());
2394
2395 if ( event.GetSetShown() )
2396 Show(event.GetShown());
2397 }
2398
2399 // ----------------------------------------------------------------------------
2400 // dialog units translations
2401 // ----------------------------------------------------------------------------
2402
2403 wxPoint wxWindowBase::ConvertPixelsToDialog(const wxPoint& pt)
2404 {
2405 int charWidth = GetCharWidth();
2406 int charHeight = GetCharHeight();
2407 wxPoint pt2 = wxDefaultPosition;
2408 if (pt.x != wxDefaultCoord)
2409 pt2.x = (int) ((pt.x * 4) / charWidth);
2410 if (pt.y != wxDefaultCoord)
2411 pt2.y = (int) ((pt.y * 8) / charHeight);
2412
2413 return pt2;
2414 }
2415
2416 wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt)
2417 {
2418 int charWidth = GetCharWidth();
2419 int charHeight = GetCharHeight();
2420 wxPoint pt2 = wxDefaultPosition;
2421 if (pt.x != wxDefaultCoord)
2422 pt2.x = (int) ((pt.x * charWidth) / 4);
2423 if (pt.y != wxDefaultCoord)
2424 pt2.y = (int) ((pt.y * charHeight) / 8);
2425
2426 return pt2;
2427 }
2428
2429 // ----------------------------------------------------------------------------
2430 // event handlers
2431 // ----------------------------------------------------------------------------
2432
2433 // propagate the colour change event to the subwindows
2434 void wxWindowBase::OnSysColourChanged(wxSysColourChangedEvent& event)
2435 {
2436 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
2437 while ( node )
2438 {
2439 // Only propagate to non-top-level windows
2440 wxWindow *win = node->GetData();
2441 if ( !win->IsTopLevel() )
2442 {
2443 wxSysColourChangedEvent event2;
2444 event.SetEventObject(win);
2445 win->GetEventHandler()->ProcessEvent(event2);
2446 }
2447
2448 node = node->GetNext();
2449 }
2450
2451 Refresh();
2452 }
2453
2454 // the default action is to populate dialog with data when it's created,
2455 // and nudge the UI into displaying itself correctly in case
2456 // we've turned the wxUpdateUIEvents frequency down low.
2457 void wxWindowBase::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) )
2458 {
2459 TransferDataToWindow();
2460
2461 // Update the UI at this point
2462 UpdateWindowUI(wxUPDATE_UI_RECURSE);
2463 }
2464
2465 // ----------------------------------------------------------------------------
2466 // menu-related functions
2467 // ----------------------------------------------------------------------------
2468
2469 #if wxUSE_MENUS
2470
2471 bool wxWindowBase::PopupMenu(wxMenu *menu, int x, int y)
2472 {
2473 wxCHECK_MSG( menu, false, "can't popup NULL menu" );
2474
2475 wxCurrentPopupMenu = menu;
2476 const bool rc = DoPopupMenu(menu, x, y);
2477 wxCurrentPopupMenu = NULL;
2478
2479 return rc;
2480 }
2481
2482 // this is used to pass the id of the selected item from the menu event handler
2483 // to the main function itself
2484 //
2485 // it's ok to use a global here as there can be at most one popup menu shown at
2486 // any time
2487 static int gs_popupMenuSelection = wxID_NONE;
2488
2489 void wxWindowBase::InternalOnPopupMenu(wxCommandEvent& event)
2490 {
2491 // store the id in a global variable where we'll retrieve it from later
2492 gs_popupMenuSelection = event.GetId();
2493 }
2494
2495 void wxWindowBase::InternalOnPopupMenuUpdate(wxUpdateUIEvent& WXUNUSED(event))
2496 {
2497 // nothing to do but do not skip it
2498 }
2499
2500 int
2501 wxWindowBase::DoGetPopupMenuSelectionFromUser(wxMenu& menu, int x, int y)
2502 {
2503 gs_popupMenuSelection = wxID_NONE;
2504
2505 Connect(wxEVT_COMMAND_MENU_SELECTED,
2506 wxCommandEventHandler(wxWindowBase::InternalOnPopupMenu),
2507 NULL,
2508 this);
2509
2510 // it is common to construct the menu passed to this function dynamically
2511 // using some fixed range of ids which could clash with the ids used
2512 // elsewhere in the program, which could result in some menu items being
2513 // unintentionally disabled or otherwise modified by update UI handlers
2514 // elsewhere in the program code and this is difficult to avoid in the
2515 // program itself, so instead we just temporarily suspend UI updating while
2516 // this menu is shown
2517 Connect(wxEVT_UPDATE_UI,
2518 wxUpdateUIEventHandler(wxWindowBase::InternalOnPopupMenuUpdate),
2519 NULL,
2520 this);
2521
2522 PopupMenu(&menu, x, y);
2523
2524 Disconnect(wxEVT_UPDATE_UI,
2525 wxUpdateUIEventHandler(wxWindowBase::InternalOnPopupMenuUpdate),
2526 NULL,
2527 this);
2528 Disconnect(wxEVT_COMMAND_MENU_SELECTED,
2529 wxCommandEventHandler(wxWindowBase::InternalOnPopupMenu),
2530 NULL,
2531 this);
2532
2533 return gs_popupMenuSelection;
2534 }
2535
2536 #endif // wxUSE_MENUS
2537
2538 // methods for drawing the sizers in a visible way
2539 #ifdef __WXDEBUG__
2540
2541 static void DrawSizers(wxWindowBase *win);
2542
2543 static void DrawBorder(wxWindowBase *win, const wxRect& rect, bool fill, const wxPen* pen)
2544 {
2545 wxClientDC dc((wxWindow *)win);
2546 dc.SetPen(*pen);
2547 dc.SetBrush(fill ? wxBrush(pen->GetColour(), wxBRUSHSTYLE_CROSSDIAG_HATCH) :
2548 *wxTRANSPARENT_BRUSH);
2549 dc.DrawRectangle(rect.Deflate(1, 1));
2550 }
2551
2552 static void DrawSizer(wxWindowBase *win, wxSizer *sizer)
2553 {
2554 const wxSizerItemList& items = sizer->GetChildren();
2555 for ( wxSizerItemList::const_iterator i = items.begin(),
2556 end = items.end();
2557 i != end;
2558 ++i )
2559 {
2560 wxSizerItem *item = *i;
2561 if ( item->IsSizer() )
2562 {
2563 DrawBorder(win, item->GetRect().Deflate(2), false, wxRED_PEN);
2564 DrawSizer(win, item->GetSizer());
2565 }
2566 else if ( item->IsSpacer() )
2567 {
2568 DrawBorder(win, item->GetRect().Deflate(2), true, wxBLUE_PEN);
2569 }
2570 else if ( item->IsWindow() )
2571 {
2572 DrawSizers(item->GetWindow());
2573 }
2574 else
2575 wxFAIL_MSG("inconsistent wxSizerItem status!");
2576 }
2577 }
2578
2579 static void DrawSizers(wxWindowBase *win)
2580 {
2581 DrawBorder(win, win->GetClientSize(), false, wxGREEN_PEN);
2582
2583 wxSizer *sizer = win->GetSizer();
2584 if ( sizer )
2585 {
2586 DrawSizer(win, sizer);
2587 }
2588 else // no sizer, still recurse into the children
2589 {
2590 const wxWindowList& children = win->GetChildren();
2591 for ( wxWindowList::const_iterator i = children.begin(),
2592 end = children.end();
2593 i != end;
2594 ++i )
2595 {
2596 DrawSizers(*i);
2597 }
2598
2599 // show all kind of sizes of this window; see the "window sizing" topic
2600 // overview for more info about the various differences:
2601 wxSize fullSz = win->GetSize();
2602 wxSize clientSz = win->GetClientSize();
2603 wxSize bestSz = win->GetBestSize();
2604 wxSize minSz = win->GetMinSize();
2605 wxSize maxSz = win->GetMaxSize();
2606 wxSize virtualSz = win->GetVirtualSize();
2607
2608 wxMessageOutputDebug dbgout;
2609 dbgout.Printf(
2610 "%-10s => fullsz=%4d;%-4d clientsz=%4d;%-4d bestsz=%4d;%-4d minsz=%4d;%-4d maxsz=%4d;%-4d virtualsz=%4d;%-4d\n",
2611 (const char*)win->GetName(),
2612 fullSz.x, fullSz.y,
2613 clientSz.x, clientSz.y,
2614 bestSz.x, bestSz.y,
2615 minSz.x, minSz.y,
2616 maxSz.x, maxSz.y,
2617 virtualSz.x, virtualSz.y);
2618 }
2619 }
2620
2621 #endif // __WXDEBUG__
2622
2623 // process special middle clicks
2624 void wxWindowBase::OnMiddleClick( wxMouseEvent& event )
2625 {
2626 if ( event.ControlDown() && event.AltDown() )
2627 {
2628 #ifdef __WXDEBUG__
2629 // Ctrl-Alt-Shift-mclick makes the sizers visible in debug builds
2630 if ( event.ShiftDown() )
2631 {
2632 DrawSizers(this);
2633 return;
2634 }
2635 #endif // __WXDEBUG__
2636 ::wxInfoMessageBox((wxWindow*)this);
2637 }
2638 else
2639 {
2640 event.Skip();
2641 }
2642 }
2643
2644 // ----------------------------------------------------------------------------
2645 // accessibility
2646 // ----------------------------------------------------------------------------
2647
2648 #if wxUSE_ACCESSIBILITY
2649 void wxWindowBase::SetAccessible(wxAccessible* accessible)
2650 {
2651 if (m_accessible && (accessible != m_accessible))
2652 delete m_accessible;
2653 m_accessible = accessible;
2654 if (m_accessible)
2655 m_accessible->SetWindow((wxWindow*) this);
2656 }
2657
2658 // Returns the accessible object, creating if necessary.
2659 wxAccessible* wxWindowBase::GetOrCreateAccessible()
2660 {
2661 if (!m_accessible)
2662 m_accessible = CreateAccessible();
2663 return m_accessible;
2664 }
2665
2666 // Override to create a specific accessible object.
2667 wxAccessible* wxWindowBase::CreateAccessible()
2668 {
2669 return new wxWindowAccessible((wxWindow*) this);
2670 }
2671
2672 #endif
2673
2674 // ----------------------------------------------------------------------------
2675 // list classes implementation
2676 // ----------------------------------------------------------------------------
2677
2678 #if wxUSE_STL
2679
2680 #include "wx/listimpl.cpp"
2681 WX_DEFINE_LIST(wxWindowList)
2682
2683 #else // !wxUSE_STL
2684
2685 void wxWindowListNode::DeleteData()
2686 {
2687 delete (wxWindow *)GetData();
2688 }
2689
2690 #endif // wxUSE_STL/!wxUSE_STL
2691
2692 // ----------------------------------------------------------------------------
2693 // borders
2694 // ----------------------------------------------------------------------------
2695
2696 wxBorder wxWindowBase::GetBorder(long flags) const
2697 {
2698 wxBorder border = (wxBorder)(flags & wxBORDER_MASK);
2699 if ( border == wxBORDER_DEFAULT )
2700 {
2701 border = GetDefaultBorder();
2702 }
2703 else if ( border == wxBORDER_THEME )
2704 {
2705 border = GetDefaultBorderForControl();
2706 }
2707
2708 return border;
2709 }
2710
2711 wxBorder wxWindowBase::GetDefaultBorder() const
2712 {
2713 return wxBORDER_NONE;
2714 }
2715
2716 // ----------------------------------------------------------------------------
2717 // hit testing
2718 // ----------------------------------------------------------------------------
2719
2720 wxHitTest wxWindowBase::DoHitTest(wxCoord x, wxCoord y) const
2721 {
2722 // here we just check if the point is inside the window or not
2723
2724 // check the top and left border first
2725 bool outside = x < 0 || y < 0;
2726 if ( !outside )
2727 {
2728 // check the right and bottom borders too
2729 wxSize size = GetSize();
2730 outside = x >= size.x || y >= size.y;
2731 }
2732
2733 return outside ? wxHT_WINDOW_OUTSIDE : wxHT_WINDOW_INSIDE;
2734 }
2735
2736 // ----------------------------------------------------------------------------
2737 // mouse capture
2738 // ----------------------------------------------------------------------------
2739
2740 struct WXDLLEXPORT wxWindowNext
2741 {
2742 wxWindow *win;
2743 wxWindowNext *next;
2744 } *wxWindowBase::ms_winCaptureNext = NULL;
2745 wxWindow *wxWindowBase::ms_winCaptureCurrent = NULL;
2746 bool wxWindowBase::ms_winCaptureChanging = false;
2747
2748 void wxWindowBase::CaptureMouse()
2749 {
2750 wxLogTrace(_T("mousecapture"), _T("CaptureMouse(%p)"), static_cast<void*>(this));
2751
2752 wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive CaptureMouse call?") );
2753
2754 ms_winCaptureChanging = true;
2755
2756 wxWindow *winOld = GetCapture();
2757 if ( winOld )
2758 {
2759 ((wxWindowBase*) winOld)->DoReleaseMouse();
2760
2761 // save it on stack
2762 wxWindowNext *item = new wxWindowNext;
2763 item->win = winOld;
2764 item->next = ms_winCaptureNext;
2765 ms_winCaptureNext = item;
2766 }
2767 //else: no mouse capture to save
2768
2769 DoCaptureMouse();
2770 ms_winCaptureCurrent = (wxWindow*)this;
2771
2772 ms_winCaptureChanging = false;
2773 }
2774
2775 void wxWindowBase::ReleaseMouse()
2776 {
2777 wxLogTrace(_T("mousecapture"), _T("ReleaseMouse(%p)"), static_cast<void*>(this));
2778
2779 wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive ReleaseMouse call?") );
2780
2781 wxASSERT_MSG( GetCapture() == this,
2782 "attempt to release mouse, but this window hasn't captured it" );
2783 wxASSERT_MSG( ms_winCaptureCurrent == this,
2784 "attempt to release mouse, but this window hasn't captured it" );
2785
2786 ms_winCaptureChanging = true;
2787
2788 DoReleaseMouse();
2789 ms_winCaptureCurrent = NULL;
2790
2791 if ( ms_winCaptureNext )
2792 {
2793 ((wxWindowBase*)ms_winCaptureNext->win)->DoCaptureMouse();
2794 ms_winCaptureCurrent = ms_winCaptureNext->win;
2795
2796 wxWindowNext *item = ms_winCaptureNext;
2797 ms_winCaptureNext = item->next;
2798 delete item;
2799 }
2800 //else: stack is empty, no previous capture
2801
2802 ms_winCaptureChanging = false;
2803
2804 wxLogTrace(_T("mousecapture"),
2805 (const wxChar *) _T("After ReleaseMouse() mouse is captured by %p"),
2806 static_cast<void*>(GetCapture()));
2807 }
2808
2809 static void DoNotifyWindowAboutCaptureLost(wxWindow *win)
2810 {
2811 wxMouseCaptureLostEvent event(win->GetId());
2812 event.SetEventObject(win);
2813 if ( !win->GetEventHandler()->ProcessEvent(event) )
2814 {
2815 // windows must handle this event, otherwise the app wouldn't behave
2816 // correctly if it loses capture unexpectedly; see the discussion here:
2817 // http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863
2818 // http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/82376
2819 wxFAIL_MSG( _T("window that captured the mouse didn't process wxEVT_MOUSE_CAPTURE_LOST") );
2820 }
2821 }
2822
2823 /* static */
2824 void wxWindowBase::NotifyCaptureLost()
2825 {
2826 // don't do anything if capture lost was expected, i.e. resulted from
2827 // a wx call to ReleaseMouse or CaptureMouse:
2828 if ( ms_winCaptureChanging )
2829 return;
2830
2831 // if the capture was lost unexpectedly, notify every window that has
2832 // capture (on stack or current) about it and clear the stack:
2833
2834 if ( ms_winCaptureCurrent )
2835 {
2836 DoNotifyWindowAboutCaptureLost(ms_winCaptureCurrent);
2837 ms_winCaptureCurrent = NULL;
2838 }
2839
2840 while ( ms_winCaptureNext )
2841 {
2842 wxWindowNext *item = ms_winCaptureNext;
2843 ms_winCaptureNext = item->next;
2844
2845 DoNotifyWindowAboutCaptureLost(item->win);
2846
2847 delete item;
2848 }
2849 }
2850
2851 #if wxUSE_HOTKEY
2852
2853 bool
2854 wxWindowBase::RegisterHotKey(int WXUNUSED(hotkeyId),
2855 int WXUNUSED(modifiers),
2856 int WXUNUSED(keycode))
2857 {
2858 // not implemented
2859 return false;
2860 }
2861
2862 bool wxWindowBase::UnregisterHotKey(int WXUNUSED(hotkeyId))
2863 {
2864 // not implemented
2865 return false;
2866 }
2867
2868 #endif // wxUSE_HOTKEY
2869
2870 // ----------------------------------------------------------------------------
2871 // event processing
2872 // ----------------------------------------------------------------------------
2873
2874 bool wxWindowBase::TryValidator(wxEvent& wxVALIDATOR_PARAM(event))
2875 {
2876 #if wxUSE_VALIDATORS
2877 // Can only use the validator of the window which
2878 // is receiving the event
2879 if ( event.GetEventObject() == this )
2880 {
2881 wxValidator * const validator = GetValidator();
2882 if ( validator && validator->ProcessEventHere(event) )
2883 {
2884 return true;
2885 }
2886 }
2887 #endif // wxUSE_VALIDATORS
2888
2889 return false;
2890 }
2891
2892 bool wxWindowBase::TryParent(wxEvent& event)
2893 {
2894 // carry on up the parent-child hierarchy if the propagation count hasn't
2895 // reached zero yet
2896 if ( event.ShouldPropagate() )
2897 {
2898 // honour the requests to stop propagation at this window: this is
2899 // used by the dialogs, for example, to prevent processing the events
2900 // from the dialog controls in the parent frame which rarely, if ever,
2901 // makes sense
2902 if ( !(GetExtraStyle() & wxWS_EX_BLOCK_EVENTS) )
2903 {
2904 wxWindow *parent = GetParent();
2905 if ( parent && !parent->IsBeingDeleted() )
2906 {
2907 wxPropagateOnce propagateOnce(event);
2908
2909 return parent->GetEventHandler()->ProcessEvent(event);
2910 }
2911 }
2912 }
2913
2914 return wxEvtHandler::TryParent(event);
2915 }
2916
2917 // ----------------------------------------------------------------------------
2918 // window relationships
2919 // ----------------------------------------------------------------------------
2920
2921 wxWindow *wxWindowBase::DoGetSibling(WindowOrder order) const
2922 {
2923 wxCHECK_MSG( GetParent(), NULL,
2924 _T("GetPrev/NextSibling() don't work for TLWs!") );
2925
2926 wxWindowList& siblings = GetParent()->GetChildren();
2927 wxWindowList::compatibility_iterator i = siblings.Find((wxWindow *)this);
2928 wxCHECK_MSG( i, NULL, _T("window not a child of its parent?") );
2929
2930 if ( order == OrderBefore )
2931 i = i->GetPrevious();
2932 else // OrderAfter
2933 i = i->GetNext();
2934
2935 return i ? i->GetData() : NULL;
2936 }
2937
2938 // ----------------------------------------------------------------------------
2939 // keyboard navigation
2940 // ----------------------------------------------------------------------------
2941
2942 // Navigates in the specified direction inside this window
2943 bool wxWindowBase::DoNavigateIn(int flags)
2944 {
2945 #ifdef wxHAS_NATIVE_TAB_TRAVERSAL
2946 // native code doesn't process our wxNavigationKeyEvents anyhow
2947 wxUnusedVar(flags);
2948 return false;
2949 #else // !wxHAS_NATIVE_TAB_TRAVERSAL
2950 wxNavigationKeyEvent eventNav;
2951 wxWindow *focused = FindFocus();
2952 eventNav.SetCurrentFocus(focused);
2953 eventNav.SetEventObject(focused);
2954 eventNav.SetFlags(flags);
2955 return GetEventHandler()->ProcessEvent(eventNav);
2956 #endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL
2957 }
2958
2959 bool wxWindowBase::HandleAsNavigationKey(const wxKeyEvent& event)
2960 {
2961 if ( event.GetKeyCode() != WXK_TAB )
2962 return false;
2963
2964 int flags = wxNavigationKeyEvent::FromTab;
2965
2966 if ( event.ShiftDown() )
2967 flags |= wxNavigationKeyEvent::IsBackward;
2968 else
2969 flags |= wxNavigationKeyEvent::IsForward;
2970
2971 if ( event.ControlDown() )
2972 flags |= wxNavigationKeyEvent::WinChange;
2973
2974 Navigate(flags);
2975 return true;
2976 }
2977
2978 void wxWindowBase::DoMoveInTabOrder(wxWindow *win, WindowOrder move)
2979 {
2980 // check that we're not a top level window
2981 wxCHECK_RET( GetParent(),
2982 _T("MoveBefore/AfterInTabOrder() don't work for TLWs!") );
2983
2984 // detect the special case when we have nothing to do anyhow and when the
2985 // code below wouldn't work
2986 if ( win == this )
2987 return;
2988
2989 // find the target window in the siblings list
2990 wxWindowList& siblings = GetParent()->GetChildren();
2991 wxWindowList::compatibility_iterator i = siblings.Find(win);
2992 wxCHECK_RET( i, _T("MoveBefore/AfterInTabOrder(): win is not a sibling") );
2993
2994 // unfortunately, when wxUSE_STL == 1 DetachNode() is not implemented so we
2995 // can't just move the node around
2996 wxWindow *self = (wxWindow *)this;
2997 siblings.DeleteObject(self);
2998 if ( move == OrderAfter )
2999 {
3000 i = i->GetNext();
3001 }
3002
3003 if ( i )
3004 {
3005 siblings.Insert(i, self);
3006 }
3007 else // OrderAfter and win was the last sibling
3008 {
3009 siblings.Append(self);
3010 }
3011 }
3012
3013 // ----------------------------------------------------------------------------
3014 // focus handling
3015 // ----------------------------------------------------------------------------
3016
3017 /*static*/ wxWindow* wxWindowBase::FindFocus()
3018 {
3019 wxWindowBase *win = DoFindFocus();
3020 return win ? win->GetMainWindowOfCompositeControl() : NULL;
3021 }
3022
3023 bool wxWindowBase::HasFocus() const
3024 {
3025 wxWindowBase *win = DoFindFocus();
3026 return win == this ||
3027 win == wxConstCast(this, wxWindowBase)->GetMainWindowOfCompositeControl();
3028 }
3029
3030 // ----------------------------------------------------------------------------
3031 // drag and drop
3032 // ----------------------------------------------------------------------------
3033
3034 #if wxUSE_DRAG_AND_DROP && !defined(__WXMSW__)
3035
3036 namespace
3037 {
3038
3039 class DragAcceptFilesTarget : public wxFileDropTarget
3040 {
3041 public:
3042 DragAcceptFilesTarget(wxWindowBase *win) : m_win(win) {}
3043
3044 virtual bool OnDropFiles(wxCoord x, wxCoord y,
3045 const wxArrayString& filenames)
3046 {
3047 wxDropFilesEvent event(wxEVT_DROP_FILES,
3048 filenames.size(),
3049 wxCArrayString(filenames).Release());
3050 event.SetEventObject(m_win);
3051 event.m_pos.x = x;
3052 event.m_pos.y = y;
3053
3054 return m_win->HandleWindowEvent(event);
3055 }
3056
3057 private:
3058 wxWindowBase * const m_win;
3059
3060 DECLARE_NO_COPY_CLASS(DragAcceptFilesTarget)
3061 };
3062
3063
3064 } // anonymous namespace
3065
3066 // Generic version of DragAcceptFiles(). It works by installing a simple
3067 // wxFileDropTarget-to-EVT_DROP_FILES adaptor and therefore cannot be used
3068 // together with explicit SetDropTarget() calls.
3069 void wxWindowBase::DragAcceptFiles(bool accept)
3070 {
3071 if ( accept )
3072 {
3073 wxASSERT_MSG( !GetDropTarget(),
3074 "cannot use DragAcceptFiles() and SetDropTarget() together" );
3075 SetDropTarget(new DragAcceptFilesTarget(this));
3076 }
3077 else
3078 {
3079 SetDropTarget(NULL);
3080 }
3081 }
3082
3083 #endif // wxUSE_DRAG_AND_DROP && !defined(__WXMSW__)
3084
3085 // ----------------------------------------------------------------------------
3086 // global functions
3087 // ----------------------------------------------------------------------------
3088
3089 wxWindow* wxGetTopLevelParent(wxWindow *win)
3090 {
3091 while ( win && !win->IsTopLevel() )
3092 win = win->GetParent();
3093
3094 return win;
3095 }
3096
3097 #if wxUSE_ACCESSIBILITY
3098 // ----------------------------------------------------------------------------
3099 // accessible object for windows
3100 // ----------------------------------------------------------------------------
3101
3102 // Can return either a child object, or an integer
3103 // representing the child element, starting from 1.
3104 wxAccStatus wxWindowAccessible::HitTest(const wxPoint& WXUNUSED(pt), int* WXUNUSED(childId), wxAccessible** WXUNUSED(childObject))
3105 {
3106 wxASSERT( GetWindow() != NULL );
3107 if (!GetWindow())
3108 return wxACC_FAIL;
3109
3110 return wxACC_NOT_IMPLEMENTED;
3111 }
3112
3113 // Returns the rectangle for this object (id = 0) or a child element (id > 0).
3114 wxAccStatus wxWindowAccessible::GetLocation(wxRect& rect, int elementId)
3115 {
3116 wxASSERT( GetWindow() != NULL );
3117 if (!GetWindow())
3118 return wxACC_FAIL;
3119
3120 wxWindow* win = NULL;
3121 if (elementId == 0)
3122 {
3123 win = GetWindow();
3124 }
3125 else
3126 {
3127 if (elementId <= (int) GetWindow()->GetChildren().GetCount())
3128 {
3129 win = GetWindow()->GetChildren().Item(elementId-1)->GetData();
3130 }
3131 else
3132 return wxACC_FAIL;
3133 }
3134 if (win)
3135 {
3136 rect = win->GetRect();
3137 if (win->GetParent() && !win->IsKindOf(CLASSINFO(wxTopLevelWindow)))
3138 rect.SetPosition(win->GetParent()->ClientToScreen(rect.GetPosition()));
3139 return wxACC_OK;
3140 }
3141
3142 return wxACC_NOT_IMPLEMENTED;
3143 }
3144
3145 // Navigates from fromId to toId/toObject.
3146 wxAccStatus wxWindowAccessible::Navigate(wxNavDir navDir, int fromId,
3147 int* WXUNUSED(toId), wxAccessible** toObject)
3148 {
3149 wxASSERT( GetWindow() != NULL );
3150 if (!GetWindow())
3151 return wxACC_FAIL;
3152
3153 switch (navDir)
3154 {
3155 case wxNAVDIR_FIRSTCHILD:
3156 {
3157 if (GetWindow()->GetChildren().GetCount() == 0)
3158 return wxACC_FALSE;
3159 wxWindow* childWindow = (wxWindow*) GetWindow()->GetChildren().GetFirst()->GetData();
3160 *toObject = childWindow->GetOrCreateAccessible();
3161
3162 return wxACC_OK;
3163 }
3164 case wxNAVDIR_LASTCHILD:
3165 {
3166 if (GetWindow()->GetChildren().GetCount() == 0)
3167 return wxACC_FALSE;
3168 wxWindow* childWindow = (wxWindow*) GetWindow()->GetChildren().GetLast()->GetData();
3169 *toObject = childWindow->GetOrCreateAccessible();
3170
3171 return wxACC_OK;
3172 }
3173 case wxNAVDIR_RIGHT:
3174 case wxNAVDIR_DOWN:
3175 case wxNAVDIR_NEXT:
3176 {
3177 wxWindowList::compatibility_iterator node =
3178 wxWindowList::compatibility_iterator();
3179 if (fromId == 0)
3180 {
3181 // Can't navigate to sibling of this window
3182 // if we're a top-level window.
3183 if (!GetWindow()->GetParent())
3184 return wxACC_NOT_IMPLEMENTED;
3185
3186 node = GetWindow()->GetParent()->GetChildren().Find(GetWindow());
3187 }
3188 else
3189 {
3190 if (fromId <= (int) GetWindow()->GetChildren().GetCount())
3191 node = GetWindow()->GetChildren().Item(fromId-1);
3192 }
3193
3194 if (node && node->GetNext())
3195 {
3196 wxWindow* nextWindow = node->GetNext()->GetData();
3197 *toObject = nextWindow->GetOrCreateAccessible();
3198 return wxACC_OK;
3199 }
3200 else
3201 return wxACC_FALSE;
3202 }
3203 case wxNAVDIR_LEFT:
3204 case wxNAVDIR_UP:
3205 case wxNAVDIR_PREVIOUS:
3206 {
3207 wxWindowList::compatibility_iterator node =
3208 wxWindowList::compatibility_iterator();
3209 if (fromId == 0)
3210 {
3211 // Can't navigate to sibling of this window
3212 // if we're a top-level window.
3213 if (!GetWindow()->GetParent())
3214 return wxACC_NOT_IMPLEMENTED;
3215
3216 node = GetWindow()->GetParent()->GetChildren().Find(GetWindow());
3217 }
3218 else
3219 {
3220 if (fromId <= (int) GetWindow()->GetChildren().GetCount())
3221 node = GetWindow()->GetChildren().Item(fromId-1);
3222 }
3223
3224 if (node && node->GetPrevious())
3225 {
3226 wxWindow* previousWindow = node->GetPrevious()->GetData();
3227 *toObject = previousWindow->GetOrCreateAccessible();
3228 return wxACC_OK;
3229 }
3230 else
3231 return wxACC_FALSE;
3232 }
3233 }
3234
3235 return wxACC_NOT_IMPLEMENTED;
3236 }
3237
3238 // Gets the name of the specified object.
3239 wxAccStatus wxWindowAccessible::GetName(int childId, wxString* name)
3240 {
3241 wxASSERT( GetWindow() != NULL );
3242 if (!GetWindow())
3243 return wxACC_FAIL;
3244
3245 wxString title;
3246
3247 // If a child, leave wxWidgets to call the function on the actual
3248 // child object.
3249 if (childId > 0)
3250 return wxACC_NOT_IMPLEMENTED;
3251
3252 // This will eventually be replaced by specialised
3253 // accessible classes, one for each kind of wxWidgets
3254 // control or window.
3255 #if wxUSE_BUTTON
3256 if (GetWindow()->IsKindOf(CLASSINFO(wxButton)))
3257 title = ((wxButton*) GetWindow())->GetLabel();
3258 else
3259 #endif
3260 title = GetWindow()->GetName();
3261
3262 if (!title.empty())
3263 {
3264 *name = title;
3265 return wxACC_OK;
3266 }
3267 else
3268 return wxACC_NOT_IMPLEMENTED;
3269 }
3270
3271 // Gets the number of children.
3272 wxAccStatus wxWindowAccessible::GetChildCount(int* childId)
3273 {
3274 wxASSERT( GetWindow() != NULL );
3275 if (!GetWindow())
3276 return wxACC_FAIL;
3277
3278 *childId = (int) GetWindow()->GetChildren().GetCount();
3279 return wxACC_OK;
3280 }
3281
3282 // Gets the specified child (starting from 1).
3283 // If *child is NULL and return value is wxACC_OK,
3284 // this means that the child is a simple element and
3285 // not an accessible object.
3286 wxAccStatus wxWindowAccessible::GetChild(int childId, wxAccessible** child)
3287 {
3288 wxASSERT( GetWindow() != NULL );
3289 if (!GetWindow())
3290 return wxACC_FAIL;
3291
3292 if (childId == 0)
3293 {
3294 *child = this;
3295 return wxACC_OK;
3296 }
3297
3298 if (childId > (int) GetWindow()->GetChildren().GetCount())
3299 return wxACC_FAIL;
3300
3301 wxWindow* childWindow = GetWindow()->GetChildren().Item(childId-1)->GetData();
3302 *child = childWindow->GetOrCreateAccessible();
3303 if (*child)
3304 return wxACC_OK;
3305 else
3306 return wxACC_FAIL;
3307 }
3308
3309 // Gets the parent, or NULL.
3310 wxAccStatus wxWindowAccessible::GetParent(wxAccessible** parent)
3311 {
3312 wxASSERT( GetWindow() != NULL );
3313 if (!GetWindow())
3314 return wxACC_FAIL;
3315
3316 wxWindow* parentWindow = GetWindow()->GetParent();
3317 if (!parentWindow)
3318 {
3319 *parent = NULL;
3320 return wxACC_OK;
3321 }
3322 else
3323 {
3324 *parent = parentWindow->GetOrCreateAccessible();
3325 if (*parent)
3326 return wxACC_OK;
3327 else
3328 return wxACC_FAIL;
3329 }
3330 }
3331
3332 // Performs the default action. childId is 0 (the action for this object)
3333 // or > 0 (the action for a child).
3334 // Return wxACC_NOT_SUPPORTED if there is no default action for this
3335 // window (e.g. an edit control).
3336 wxAccStatus wxWindowAccessible::DoDefaultAction(int WXUNUSED(childId))
3337 {
3338 wxASSERT( GetWindow() != NULL );
3339 if (!GetWindow())
3340 return wxACC_FAIL;
3341
3342 return wxACC_NOT_IMPLEMENTED;
3343 }
3344
3345 // Gets the default action for this object (0) or > 0 (the action for a child).
3346 // Return wxACC_OK even if there is no action. actionName is the action, or the empty
3347 // string if there is no action.
3348 // The retrieved string describes the action that is performed on an object,
3349 // not what the object does as a result. For example, a toolbar button that prints
3350 // a document has a default action of "Press" rather than "Prints the current document."
3351 wxAccStatus wxWindowAccessible::GetDefaultAction(int WXUNUSED(childId), wxString* WXUNUSED(actionName))
3352 {
3353 wxASSERT( GetWindow() != NULL );
3354 if (!GetWindow())
3355 return wxACC_FAIL;
3356
3357 return wxACC_NOT_IMPLEMENTED;
3358 }
3359
3360 // Returns the description for this object or a child.
3361 wxAccStatus wxWindowAccessible::GetDescription(int WXUNUSED(childId), wxString* description)
3362 {
3363 wxASSERT( GetWindow() != NULL );
3364 if (!GetWindow())
3365 return wxACC_FAIL;
3366
3367 wxString ht(GetWindow()->GetHelpTextAtPoint(wxDefaultPosition, wxHelpEvent::Origin_Keyboard));
3368 if (!ht.empty())
3369 {
3370 *description = ht;
3371 return wxACC_OK;
3372 }
3373 return wxACC_NOT_IMPLEMENTED;
3374 }
3375
3376 // Returns help text for this object or a child, similar to tooltip text.
3377 wxAccStatus wxWindowAccessible::GetHelpText(int WXUNUSED(childId), wxString* helpText)
3378 {
3379 wxASSERT( GetWindow() != NULL );
3380 if (!GetWindow())
3381 return wxACC_FAIL;
3382
3383 wxString ht(GetWindow()->GetHelpTextAtPoint(wxDefaultPosition, wxHelpEvent::Origin_Keyboard));
3384 if (!ht.empty())
3385 {
3386 *helpText = ht;
3387 return wxACC_OK;
3388 }
3389 return wxACC_NOT_IMPLEMENTED;
3390 }
3391
3392 // Returns the keyboard shortcut for this object or child.
3393 // Return e.g. ALT+K
3394 wxAccStatus wxWindowAccessible::GetKeyboardShortcut(int WXUNUSED(childId), wxString* WXUNUSED(shortcut))
3395 {
3396 wxASSERT( GetWindow() != NULL );
3397 if (!GetWindow())
3398 return wxACC_FAIL;
3399
3400 return wxACC_NOT_IMPLEMENTED;
3401 }
3402
3403 // Returns a role constant.
3404 wxAccStatus wxWindowAccessible::GetRole(int childId, wxAccRole* role)
3405 {
3406 wxASSERT( GetWindow() != NULL );
3407 if (!GetWindow())
3408 return wxACC_FAIL;
3409
3410 // If a child, leave wxWidgets to call the function on the actual
3411 // child object.
3412 if (childId > 0)
3413 return wxACC_NOT_IMPLEMENTED;
3414
3415 if (GetWindow()->IsKindOf(CLASSINFO(wxControl)))
3416 return wxACC_NOT_IMPLEMENTED;
3417 #if wxUSE_STATUSBAR
3418 if (GetWindow()->IsKindOf(CLASSINFO(wxStatusBar)))
3419 return wxACC_NOT_IMPLEMENTED;
3420 #endif
3421 #if wxUSE_TOOLBAR
3422 if (GetWindow()->IsKindOf(CLASSINFO(wxToolBar)))
3423 return wxACC_NOT_IMPLEMENTED;
3424 #endif
3425
3426 //*role = wxROLE_SYSTEM_CLIENT;
3427 *role = wxROLE_SYSTEM_CLIENT;
3428 return wxACC_OK;
3429
3430 #if 0
3431 return wxACC_NOT_IMPLEMENTED;
3432 #endif
3433 }
3434
3435 // Returns a state constant.
3436 wxAccStatus wxWindowAccessible::GetState(int childId, long* state)
3437 {
3438 wxASSERT( GetWindow() != NULL );
3439 if (!GetWindow())
3440 return wxACC_FAIL;
3441
3442 // If a child, leave wxWidgets to call the function on the actual
3443 // child object.
3444 if (childId > 0)
3445 return wxACC_NOT_IMPLEMENTED;
3446
3447 if (GetWindow()->IsKindOf(CLASSINFO(wxControl)))
3448 return wxACC_NOT_IMPLEMENTED;
3449
3450 #if wxUSE_STATUSBAR
3451 if (GetWindow()->IsKindOf(CLASSINFO(wxStatusBar)))
3452 return wxACC_NOT_IMPLEMENTED;
3453 #endif
3454 #if wxUSE_TOOLBAR
3455 if (GetWindow()->IsKindOf(CLASSINFO(wxToolBar)))
3456 return wxACC_NOT_IMPLEMENTED;
3457 #endif
3458
3459 *state = 0;
3460 return wxACC_OK;
3461
3462 #if 0
3463 return wxACC_NOT_IMPLEMENTED;
3464 #endif
3465 }
3466
3467 // Returns a localized string representing the value for the object
3468 // or child.
3469 wxAccStatus wxWindowAccessible::GetValue(int WXUNUSED(childId), wxString* WXUNUSED(strValue))
3470 {
3471 wxASSERT( GetWindow() != NULL );
3472 if (!GetWindow())
3473 return wxACC_FAIL;
3474
3475 return wxACC_NOT_IMPLEMENTED;
3476 }
3477
3478 // Selects the object or child.
3479 wxAccStatus wxWindowAccessible::Select(int WXUNUSED(childId), wxAccSelectionFlags WXUNUSED(selectFlags))
3480 {
3481 wxASSERT( GetWindow() != NULL );
3482 if (!GetWindow())
3483 return wxACC_FAIL;
3484
3485 return wxACC_NOT_IMPLEMENTED;
3486 }
3487
3488 // Gets the window with the keyboard focus.
3489 // If childId is 0 and child is NULL, no object in
3490 // this subhierarchy has the focus.
3491 // If this object has the focus, child should be 'this'.
3492 wxAccStatus wxWindowAccessible::GetFocus(int* WXUNUSED(childId), wxAccessible** WXUNUSED(child))
3493 {
3494 wxASSERT( GetWindow() != NULL );
3495 if (!GetWindow())
3496 return wxACC_FAIL;
3497
3498 return wxACC_NOT_IMPLEMENTED;
3499 }
3500
3501 #if wxUSE_VARIANT
3502 // Gets a variant representing the selected children
3503 // of this object.
3504 // Acceptable values:
3505 // - a null variant (IsNull() returns true)
3506 // - a list variant (GetType() == wxT("list")
3507 // - an integer representing the selected child element,
3508 // or 0 if this object is selected (GetType() == wxT("long")
3509 // - a "void*" pointer to a wxAccessible child object
3510 wxAccStatus wxWindowAccessible::GetSelections(wxVariant* WXUNUSED(selections))
3511 {
3512 wxASSERT( GetWindow() != NULL );
3513 if (!GetWindow())
3514 return wxACC_FAIL;
3515
3516 return wxACC_NOT_IMPLEMENTED;
3517 }
3518 #endif // wxUSE_VARIANT
3519
3520 #endif // wxUSE_ACCESSIBILITY
3521
3522 // ----------------------------------------------------------------------------
3523 // RTL support
3524 // ----------------------------------------------------------------------------
3525
3526 wxCoord
3527 wxWindowBase::AdjustForLayoutDirection(wxCoord x,
3528 wxCoord width,
3529 wxCoord widthTotal) const
3530 {
3531 if ( GetLayoutDirection() == wxLayout_RightToLeft )
3532 {
3533 x = widthTotal - x - width;
3534 }
3535
3536 return x;
3537 }
3538
3539