Added DoGetClientBestSize() and use it for a couple of controls in wxMSW.
[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 #include "wx/platinfo.h"
76
77 // Windows List
78 WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows;
79
80 // globals
81 #if wxUSE_MENUS
82 wxMenu *wxCurrentPopupMenu = NULL;
83 #endif // wxUSE_MENUS
84
85 // ----------------------------------------------------------------------------
86 // static data
87 // ----------------------------------------------------------------------------
88
89
90 IMPLEMENT_ABSTRACT_CLASS(wxWindowBase, wxEvtHandler)
91
92 // ----------------------------------------------------------------------------
93 // event table
94 // ----------------------------------------------------------------------------
95
96 BEGIN_EVENT_TABLE(wxWindowBase, wxEvtHandler)
97 EVT_SYS_COLOUR_CHANGED(wxWindowBase::OnSysColourChanged)
98 EVT_INIT_DIALOG(wxWindowBase::OnInitDialog)
99 EVT_MIDDLE_DOWN(wxWindowBase::OnMiddleClick)
100
101 #if wxUSE_HELP
102 EVT_HELP(wxID_ANY, wxWindowBase::OnHelp)
103 #endif // wxUSE_HELP
104
105 EVT_SIZE(wxWindowBase::InternalOnSize)
106 END_EVENT_TABLE()
107
108 // ============================================================================
109 // implementation of the common functionality of the wxWindow class
110 // ============================================================================
111
112 // ----------------------------------------------------------------------------
113 // initialization
114 // ----------------------------------------------------------------------------
115
116 // the default initialization
117 wxWindowBase::wxWindowBase()
118 {
119 // no window yet, no parent nor children
120 m_parent = NULL;
121 m_windowId = wxID_ANY;
122
123 // no constraints on the minimal window size
124 m_minWidth =
125 m_maxWidth = wxDefaultCoord;
126 m_minHeight =
127 m_maxHeight = wxDefaultCoord;
128
129 // invalidiated cache value
130 m_bestSizeCache = wxDefaultSize;
131
132 // window are created enabled and visible by default
133 m_isShown =
134 m_isEnabled = true;
135
136 // the default event handler is just this window
137 m_eventHandler = this;
138
139 #if wxUSE_VALIDATORS
140 // no validator
141 m_windowValidator = NULL;
142 #endif // wxUSE_VALIDATORS
143
144 // the colours/fonts are default for now, so leave m_font,
145 // m_backgroundColour and m_foregroundColour uninitialized and set those
146 m_hasBgCol =
147 m_hasFgCol =
148 m_hasFont = false;
149 m_inheritBgCol =
150 m_inheritFgCol =
151 m_inheritFont = false;
152
153 // no style bits
154 m_exStyle =
155 m_windowStyle = 0;
156
157 m_backgroundStyle = wxBG_STYLE_ERASE;
158
159 #if wxUSE_CONSTRAINTS
160 // no constraints whatsoever
161 m_constraints = NULL;
162 m_constraintsInvolvedIn = NULL;
163 #endif // wxUSE_CONSTRAINTS
164
165 m_windowSizer = NULL;
166 m_containingSizer = NULL;
167 m_autoLayout = false;
168
169 #if wxUSE_DRAG_AND_DROP
170 m_dropTarget = NULL;
171 #endif // wxUSE_DRAG_AND_DROP
172
173 #if wxUSE_TOOLTIPS
174 m_tooltip = NULL;
175 #endif // wxUSE_TOOLTIPS
176
177 #if wxUSE_CARET
178 m_caret = NULL;
179 #endif // wxUSE_CARET
180
181 #if wxUSE_PALETTE
182 m_hasCustomPalette = false;
183 #endif // wxUSE_PALETTE
184
185 #if wxUSE_ACCESSIBILITY
186 m_accessible = NULL;
187 #endif
188
189 m_virtualSize = wxDefaultSize;
190
191 m_scrollHelper = NULL;
192
193 m_windowVariant = wxWINDOW_VARIANT_NORMAL;
194 #if wxUSE_SYSTEM_OPTIONS
195 if ( wxSystemOptions::HasOption(wxWINDOW_DEFAULT_VARIANT) )
196 {
197 m_windowVariant = (wxWindowVariant) wxSystemOptions::GetOptionInt( wxWINDOW_DEFAULT_VARIANT ) ;
198 }
199 #endif
200
201 // Whether we're using the current theme for this window (wxGTK only for now)
202 m_themeEnabled = false;
203
204 // This is set to true by SendDestroyEvent() which should be called by the
205 // most derived class to ensure that the destruction event is sent as soon
206 // as possible to allow its handlers to still see the undestroyed window
207 m_isBeingDeleted = false;
208
209 m_freezeCount = 0;
210 }
211
212 // common part of window creation process
213 bool wxWindowBase::CreateBase(wxWindowBase *parent,
214 wxWindowID id,
215 const wxPoint& WXUNUSED(pos),
216 const wxSize& WXUNUSED(size),
217 long style,
218 const wxValidator& wxVALIDATOR_PARAM(validator),
219 const wxString& name)
220 {
221 // ids are limited to 16 bits under MSW so if you care about portability,
222 // it's not a good idea to use ids out of this range (and negative ids are
223 // reserved for wxWidgets own usage)
224 wxASSERT_MSG( id == wxID_ANY || (id >= 0 && id < 32767) ||
225 (id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST),
226 _T("invalid id value") );
227
228 // generate a new id if the user doesn't care about it
229 if ( id == wxID_ANY )
230 {
231 m_windowId = NewControlId();
232 }
233 else // valid id specified
234 {
235 m_windowId = id;
236 }
237
238 // don't use SetWindowStyleFlag() here, this function should only be called
239 // to change the flag after creation as it tries to reflect the changes in
240 // flags by updating the window dynamically and we don't need this here
241 m_windowStyle = style;
242
243 SetName(name);
244 SetParent(parent);
245
246 #if wxUSE_VALIDATORS
247 SetValidator(validator);
248 #endif // wxUSE_VALIDATORS
249
250 // if the parent window has wxWS_EX_VALIDATE_RECURSIVELY set, we want to
251 // have it too - like this it's possible to set it only in the top level
252 // dialog/frame and all children will inherit it by defult
253 if ( parent && (parent->GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) )
254 {
255 SetExtraStyle(GetExtraStyle() | wxWS_EX_VALIDATE_RECURSIVELY);
256 }
257
258 return true;
259 }
260
261 bool wxWindowBase::ToggleWindowStyle(int flag)
262 {
263 wxASSERT_MSG( flag, _T("flags with 0 value can't be toggled") );
264
265 bool rc;
266 long style = GetWindowStyleFlag();
267 if ( style & flag )
268 {
269 style &= ~flag;
270 rc = false;
271 }
272 else // currently off
273 {
274 style |= flag;
275 rc = true;
276 }
277
278 SetWindowStyleFlag(style);
279
280 return rc;
281 }
282
283 // ----------------------------------------------------------------------------
284 // destruction
285 // ----------------------------------------------------------------------------
286
287 // common clean up
288 wxWindowBase::~wxWindowBase()
289 {
290 wxASSERT_MSG( GetCapture() != this, wxT("attempt to destroy window with mouse capture") );
291
292 // FIXME if these 2 cases result from programming errors in the user code
293 // we should probably assert here instead of silently fixing them
294
295 // Just in case the window has been Closed, but we're then deleting
296 // immediately: don't leave dangling pointers.
297 wxPendingDelete.DeleteObject(this);
298
299 // Just in case we've loaded a top-level window via LoadNativeDialog but
300 // we weren't a dialog class
301 wxTopLevelWindows.DeleteObject((wxWindow*)this);
302
303 #if wxUSE_MENUS
304 // The associated popup menu can still be alive, disassociate from it in
305 // this case
306 if ( wxCurrentPopupMenu && wxCurrentPopupMenu->GetInvokingWindow() == this )
307 wxCurrentPopupMenu->SetInvokingWindow(NULL);
308 #endif // wxUSE_MENUS
309
310 wxASSERT_MSG( GetChildren().GetCount() == 0, wxT("children not destroyed") );
311
312 // notify the parent about this window destruction
313 if ( m_parent )
314 m_parent->RemoveChild(this);
315
316 #if wxUSE_CARET
317 delete m_caret;
318 #endif // wxUSE_CARET
319
320 #if wxUSE_VALIDATORS
321 delete m_windowValidator;
322 #endif // wxUSE_VALIDATORS
323
324 #if wxUSE_CONSTRAINTS
325 // Have to delete constraints/sizer FIRST otherwise sizers may try to look
326 // at deleted windows as they delete themselves.
327 DeleteRelatedConstraints();
328
329 if ( m_constraints )
330 {
331 // This removes any dangling pointers to this window in other windows'
332 // constraintsInvolvedIn lists.
333 UnsetConstraints(m_constraints);
334 delete m_constraints;
335 m_constraints = NULL;
336 }
337 #endif // wxUSE_CONSTRAINTS
338
339 if ( m_containingSizer )
340 m_containingSizer->Detach( (wxWindow*)this );
341
342 delete m_windowSizer;
343
344 #if wxUSE_DRAG_AND_DROP
345 delete m_dropTarget;
346 #endif // wxUSE_DRAG_AND_DROP
347
348 #if wxUSE_TOOLTIPS
349 delete m_tooltip;
350 #endif // wxUSE_TOOLTIPS
351
352 #if wxUSE_ACCESSIBILITY
353 delete m_accessible;
354 #endif
355
356 #if wxUSE_HELP
357 // NB: this has to be called unconditionally, because we don't know
358 // whether this window has associated help text or not
359 wxHelpProvider *helpProvider = wxHelpProvider::Get();
360 if ( helpProvider )
361 helpProvider->RemoveHelp(this);
362 #endif
363 }
364
365 bool wxWindowBase::IsBeingDeleted() const
366 {
367 return m_isBeingDeleted ||
368 (!IsTopLevel() && m_parent && m_parent->IsBeingDeleted());
369 }
370
371 void wxWindowBase::SendDestroyEvent()
372 {
373 if ( m_isBeingDeleted )
374 {
375 // we could have been already called from a more derived class dtor,
376 // e.g. ~wxTLW calls us and so does ~wxWindow and the latter call
377 // should be simply ignored
378 return;
379 }
380
381 m_isBeingDeleted = true;
382
383 wxWindowDestroyEvent event;
384 event.SetEventObject(this);
385 event.SetId(GetId());
386 GetEventHandler()->ProcessEvent(event);
387 }
388
389 bool wxWindowBase::Destroy()
390 {
391 SendDestroyEvent();
392
393 delete this;
394
395 return true;
396 }
397
398 bool wxWindowBase::Close(bool force)
399 {
400 wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId);
401 event.SetEventObject(this);
402 event.SetCanVeto(!force);
403
404 // return false if window wasn't closed because the application vetoed the
405 // close event
406 return HandleWindowEvent(event) && !event.GetVeto();
407 }
408
409 bool wxWindowBase::DestroyChildren()
410 {
411 wxWindowList::compatibility_iterator node;
412 for ( ;; )
413 {
414 // we iterate until the list becomes empty
415 node = GetChildren().GetFirst();
416 if ( !node )
417 break;
418
419 wxWindow *child = node->GetData();
420
421 // note that we really want to delete it immediately so don't call the
422 // possible overridden Destroy() version which might not delete the
423 // child immediately resulting in problems with our (top level) child
424 // outliving its parent
425 child->wxWindowBase::Destroy();
426
427 wxASSERT_MSG( !GetChildren().Find(child),
428 wxT("child didn't remove itself using RemoveChild()") );
429 }
430
431 return true;
432 }
433
434 // ----------------------------------------------------------------------------
435 // size/position related methods
436 // ----------------------------------------------------------------------------
437
438 // centre the window with respect to its parent in either (or both) directions
439 void wxWindowBase::DoCentre(int dir)
440 {
441 wxCHECK_RET( !(dir & wxCENTRE_ON_SCREEN) && GetParent(),
442 _T("this method only implements centering child windows") );
443
444 SetSize(GetRect().CentreIn(GetParent()->GetClientSize(), dir));
445 }
446
447 // fits the window around the children
448 void wxWindowBase::Fit()
449 {
450 if ( !GetChildren().empty() )
451 {
452 SetSize(GetBestSize());
453 }
454 //else: do nothing if we have no children
455 }
456
457 // fits virtual size (ie. scrolled area etc.) around children
458 void wxWindowBase::FitInside()
459 {
460 if ( GetChildren().GetCount() > 0 )
461 {
462 SetVirtualSize( GetBestVirtualSize() );
463 }
464 }
465
466 // On Mac, scrollbars are explicitly children.
467 #if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__)
468 static bool wxHasRealChildren(const wxWindowBase* win)
469 {
470 int realChildCount = 0;
471
472 for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
473 node;
474 node = node->GetNext() )
475 {
476 wxWindow *win = node->GetData();
477 if ( !win->IsTopLevel() && win->IsShown() && !win->IsKindOf(CLASSINFO(wxScrollBar)))
478 realChildCount ++;
479 }
480 return (realChildCount > 0);
481 }
482 #endif
483
484 void wxWindowBase::InvalidateBestSize()
485 {
486 m_bestSizeCache = wxDefaultSize;
487
488 // parent's best size calculation may depend on its children's
489 // as long as child window we are in is not top level window itself
490 // (because the TLW size is never resized automatically)
491 // so let's invalidate it as well to be safe:
492 if (m_parent && !IsTopLevel())
493 m_parent->InvalidateBestSize();
494 }
495
496 // return the size best suited for the current window
497 wxSize wxWindowBase::DoGetBestSize() const
498 {
499 wxSize best;
500
501 if ( m_windowSizer )
502 {
503 best = m_windowSizer->GetMinSize();
504 }
505 #if wxUSE_CONSTRAINTS
506 else if ( m_constraints )
507 {
508 wxConstCast(this, wxWindowBase)->SatisfyConstraints();
509
510 // our minimal acceptable size is such that all our windows fit inside
511 int maxX = 0,
512 maxY = 0;
513
514 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
515 node;
516 node = node->GetNext() )
517 {
518 wxLayoutConstraints *c = node->GetData()->GetConstraints();
519 if ( !c )
520 {
521 // it's not normal that we have an unconstrained child, but
522 // what can we do about it?
523 continue;
524 }
525
526 int x = c->right.GetValue(),
527 y = c->bottom.GetValue();
528
529 if ( x > maxX )
530 maxX = x;
531
532 if ( y > maxY )
533 maxY = y;
534
535 // TODO: we must calculate the overlaps somehow, otherwise we
536 // will never return a size bigger than the current one :-(
537 }
538
539 best = wxSize(maxX, maxY);
540 }
541 #endif // wxUSE_CONSTRAINTS
542 else if ( !GetChildren().empty()
543 #if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__)
544 && wxHasRealChildren(this)
545 #endif
546 )
547 {
548 // our minimal acceptable size is such that all our visible child
549 // windows fit inside
550 int maxX = 0,
551 maxY = 0;
552
553 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
554 node;
555 node = node->GetNext() )
556 {
557 wxWindow *win = node->GetData();
558 if ( win->IsTopLevel()
559 || !win->IsShown()
560 #if wxUSE_STATUSBAR
561 || wxDynamicCast(win, wxStatusBar)
562 #endif // wxUSE_STATUSBAR
563 )
564 {
565 // dialogs and frames lie in different top level windows -
566 // don't deal with them here; as for the status bars, they
567 // don't lie in the client area at all
568 continue;
569 }
570
571 int wx, wy, ww, wh;
572 win->GetPosition(&wx, &wy);
573
574 // if the window hadn't been positioned yet, assume that it is in
575 // the origin
576 if ( wx == wxDefaultCoord )
577 wx = 0;
578 if ( wy == wxDefaultCoord )
579 wy = 0;
580
581 win->GetSize(&ww, &wh);
582 if ( wx + ww > maxX )
583 maxX = wx + ww;
584 if ( wy + wh > maxY )
585 maxY = wy + wh;
586 }
587
588 best = wxSize(maxX, maxY);
589 }
590 else // ! has children
591 {
592 // for a generic window there is no natural best size so, if the
593 // minimal size is not set, use the current size but take care to
594 // remember it as minimal size for the next time because our best size
595 // should be constant: otherwise we could get into a situation when the
596 // window is initially at some size, then expanded to a larger size and
597 // then, when the containing window is shrunk back (because our initial
598 // best size had been used for computing the parent min size), we can't
599 // be shrunk back any more because our best size is now bigger
600 wxSize size = GetMinSize();
601 if ( !size.IsFullySpecified() )
602 {
603 size.SetDefaults(GetSize());
604 wxConstCast(this, wxWindowBase)->SetMinSize(size);
605 }
606
607 // return as-is, unadjusted by the client size difference.
608 return size;
609 }
610
611 // Add any difference between size and client size
612 wxSize diff = GetSize() - GetClientSize();
613 best.x += wxMax(0, diff.x);
614 best.y += wxMax(0, diff.y);
615
616 return best;
617 }
618
619 // helper of GetWindowBorderSize(): as many ports don't implement support for
620 // wxSYS_BORDER/EDGE_X/Y metrics in their wxSystemSettings, use hard coded
621 // fallbacks in this case
622 static int wxGetMetricOrDefault(wxSystemMetric what, const wxWindowBase* win)
623 {
624 int rc = wxSystemSettings::GetMetric(
625 what, static_cast<wxWindow*>(const_cast<wxWindowBase*>(win)));
626 if ( rc == -1 )
627 {
628 switch ( what )
629 {
630 case wxSYS_BORDER_X:
631 case wxSYS_BORDER_Y:
632 // 2D border is by default 1 pixel wide
633 rc = 1;
634 break;
635
636 case wxSYS_EDGE_X:
637 case wxSYS_EDGE_Y:
638 // 3D borders are by default 2 pixels
639 rc = 2;
640 break;
641
642 default:
643 wxFAIL_MSG( _T("unexpected wxGetMetricOrDefault() argument") );
644 rc = 0;
645 }
646 }
647
648 return rc;
649 }
650
651 wxSize wxWindowBase::GetWindowBorderSize() const
652 {
653 wxSize size;
654
655 switch ( GetBorder() )
656 {
657 case wxBORDER_NONE:
658 // nothing to do, size is already (0, 0)
659 break;
660
661 case wxBORDER_SIMPLE:
662 case wxBORDER_STATIC:
663 size.x = wxGetMetricOrDefault(wxSYS_BORDER_X, this);
664 size.y = wxGetMetricOrDefault(wxSYS_BORDER_Y, this);
665 break;
666
667 case wxBORDER_SUNKEN:
668 case wxBORDER_RAISED:
669 size.x = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_X, this),
670 wxGetMetricOrDefault(wxSYS_BORDER_X, this));
671 size.y = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_Y, this),
672 wxGetMetricOrDefault(wxSYS_BORDER_Y, this));
673 break;
674
675 case wxBORDER_DOUBLE:
676 size.x = wxGetMetricOrDefault(wxSYS_EDGE_X, this) +
677 wxGetMetricOrDefault(wxSYS_BORDER_X, this);
678 size.y = wxGetMetricOrDefault(wxSYS_EDGE_Y, this) +
679 wxGetMetricOrDefault(wxSYS_BORDER_Y, this);
680 break;
681
682 default:
683 wxFAIL_MSG(_T("Unknown border style."));
684 break;
685 }
686
687 // we have borders on both sides
688 return size*2;
689 }
690
691 wxSize wxWindowBase::GetEffectiveMinSize() const
692 {
693 // merge the best size with the min size, giving priority to the min size
694 wxSize min = GetMinSize();
695
696 if (min.x == wxDefaultCoord || min.y == wxDefaultCoord)
697 {
698 wxSize best = GetBestSize();
699 if (min.x == wxDefaultCoord) min.x = best.x;
700 if (min.y == wxDefaultCoord) min.y = best.y;
701 }
702
703 return min;
704 }
705
706 wxSize wxWindowBase::GetBestSize() const
707 {
708 if ( !m_windowSizer && m_bestSizeCache.IsFullySpecified() )
709 return m_bestSizeCache;
710
711 // call DoGetBestClientSize() first, if a derived class overrides it wants
712 // it to be used
713 wxSize size = DoGetBestClientSize();
714 if ( size != wxDefaultSize )
715 {
716 size += DoGetBorderSize();
717
718 CacheBestSize(size);
719 return size;
720 }
721
722 return DoGetBestSize();
723 }
724
725 void wxWindowBase::SetMinSize(const wxSize& minSize)
726 {
727 m_minWidth = minSize.x;
728 m_minHeight = minSize.y;
729 }
730
731 void wxWindowBase::SetMaxSize(const wxSize& maxSize)
732 {
733 m_maxWidth = maxSize.x;
734 m_maxHeight = maxSize.y;
735 }
736
737 void wxWindowBase::SetInitialSize(const wxSize& size)
738 {
739 // Set the min size to the size passed in. This will usually either be
740 // wxDefaultSize or the size passed to this window's ctor/Create function.
741 SetMinSize(size);
742
743 // Merge the size with the best size if needed
744 wxSize best = GetEffectiveMinSize();
745
746 // If the current size doesn't match then change it
747 if (GetSize() != best)
748 SetSize(best);
749 }
750
751
752 // by default the origin is not shifted
753 wxPoint wxWindowBase::GetClientAreaOrigin() const
754 {
755 return wxPoint(0,0);
756 }
757
758 wxSize wxWindowBase::ClientToWindowSize(const wxSize& size) const
759 {
760 const wxSize diff(GetSize() - GetClientSize());
761
762 return wxSize(size.x == -1 ? -1 : size.x + diff.x,
763 size.y == -1 ? -1 : size.y + diff.y);
764 }
765
766 wxSize wxWindowBase::WindowToClientSize(const wxSize& size) const
767 {
768 const wxSize diff(GetSize() - GetClientSize());
769
770 return wxSize(size.x == -1 ? -1 : size.x - diff.x,
771 size.y == -1 ? -1 : size.y - diff.y);
772 }
773
774 void wxWindowBase::SetWindowVariant( wxWindowVariant variant )
775 {
776 if ( m_windowVariant != variant )
777 {
778 m_windowVariant = variant;
779
780 DoSetWindowVariant(variant);
781 }
782 }
783
784 void wxWindowBase::DoSetWindowVariant( wxWindowVariant variant )
785 {
786 // adjust the font height to correspond to our new variant (notice that
787 // we're only called if something really changed)
788 wxFont font = GetFont();
789 int size = font.GetPointSize();
790 switch ( variant )
791 {
792 case wxWINDOW_VARIANT_NORMAL:
793 break;
794
795 case wxWINDOW_VARIANT_SMALL:
796 size *= 3;
797 size /= 4;
798 break;
799
800 case wxWINDOW_VARIANT_MINI:
801 size *= 2;
802 size /= 3;
803 break;
804
805 case wxWINDOW_VARIANT_LARGE:
806 size *= 5;
807 size /= 4;
808 break;
809
810 default:
811 wxFAIL_MSG(_T("unexpected window variant"));
812 break;
813 }
814
815 font.SetPointSize(size);
816 SetFont(font);
817 }
818
819 void wxWindowBase::DoSetSizeHints( int minW, int minH,
820 int maxW, int maxH,
821 int WXUNUSED(incW), int WXUNUSED(incH) )
822 {
823 wxCHECK_RET( (minW == wxDefaultCoord || maxW == wxDefaultCoord || minW <= maxW) &&
824 (minH == wxDefaultCoord || maxH == wxDefaultCoord || minH <= maxH),
825 _T("min width/height must be less than max width/height!") );
826
827 m_minWidth = minW;
828 m_maxWidth = maxW;
829 m_minHeight = minH;
830 m_maxHeight = maxH;
831 }
832
833
834 #if WXWIN_COMPATIBILITY_2_8
835 void wxWindowBase::SetVirtualSizeHints(int WXUNUSED(minW), int WXUNUSED(minH),
836 int WXUNUSED(maxW), int WXUNUSED(maxH))
837 {
838 }
839
840 void wxWindowBase::SetVirtualSizeHints(const wxSize& WXUNUSED(minsize),
841 const wxSize& WXUNUSED(maxsize))
842 {
843 }
844 #endif // WXWIN_COMPATIBILITY_2_8
845
846 void wxWindowBase::DoSetVirtualSize( int x, int y )
847 {
848 m_virtualSize = wxSize(x, y);
849 }
850
851 wxSize wxWindowBase::DoGetVirtualSize() const
852 {
853 // we should use the entire client area so if it is greater than our
854 // virtual size, expand it to fit (otherwise if the window is big enough we
855 // wouldn't be using parts of it)
856 wxSize size = GetClientSize();
857 if ( m_virtualSize.x > size.x )
858 size.x = m_virtualSize.x;
859
860 if ( m_virtualSize.y >= size.y )
861 size.y = m_virtualSize.y;
862
863 return size;
864 }
865
866 void wxWindowBase::DoGetScreenPosition(int *x, int *y) const
867 {
868 // screen position is the same as (0, 0) in client coords for non TLWs (and
869 // TLWs override this method)
870 if ( x )
871 *x = 0;
872 if ( y )
873 *y = 0;
874
875 ClientToScreen(x, y);
876 }
877
878 void wxWindowBase::SendSizeEvent(int flags)
879 {
880 wxSizeEvent event(GetSize(), GetId());
881 event.SetEventObject(this);
882 if ( flags & wxSEND_EVENT_POST )
883 wxPostEvent(this, event);
884 else
885 HandleWindowEvent(event);
886 }
887
888 void wxWindowBase::SendSizeEventToParent(int flags)
889 {
890 wxWindow * const parent = GetParent();
891 if ( parent && !parent->IsBeingDeleted() )
892 parent->SendSizeEvent(flags);
893 }
894
895 // ----------------------------------------------------------------------------
896 // show/hide/enable/disable the window
897 // ----------------------------------------------------------------------------
898
899 bool wxWindowBase::Show(bool show)
900 {
901 if ( show != m_isShown )
902 {
903 m_isShown = show;
904
905 return true;
906 }
907 else
908 {
909 return false;
910 }
911 }
912
913 bool wxWindowBase::IsEnabled() const
914 {
915 return IsThisEnabled() && (IsTopLevel() || !GetParent() || GetParent()->IsEnabled());
916 }
917
918 void wxWindowBase::NotifyWindowOnEnableChange(bool enabled)
919 {
920 #ifndef wxHAS_NATIVE_ENABLED_MANAGEMENT
921 DoEnable(enabled);
922 #endif // !defined(wxHAS_NATIVE_ENABLED_MANAGEMENT)
923
924 OnEnabled(enabled);
925
926 // If we are top-level then the logic doesn't apply - otherwise
927 // showing a modal dialog would result in total greying out (and ungreying
928 // out later) of everything which would be really ugly
929 if ( IsTopLevel() )
930 return;
931
932 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
933 node;
934 node = node->GetNext() )
935 {
936 wxWindowBase * const child = node->GetData();
937 if ( !child->IsTopLevel() && child->IsThisEnabled() )
938 child->NotifyWindowOnEnableChange(enabled);
939 }
940 }
941
942 bool wxWindowBase::Enable(bool enable)
943 {
944 if ( enable == IsThisEnabled() )
945 return false;
946
947 m_isEnabled = enable;
948
949 #ifdef wxHAS_NATIVE_ENABLED_MANAGEMENT
950 DoEnable(enable);
951 #else // !defined(wxHAS_NATIVE_ENABLED_MANAGEMENT)
952 wxWindowBase * const parent = GetParent();
953 if( !IsTopLevel() && parent && !parent->IsEnabled() )
954 {
955 return true;
956 }
957 #endif // !defined(wxHAS_NATIVE_ENABLED_MANAGEMENT)
958
959 NotifyWindowOnEnableChange(enable);
960
961 return true;
962 }
963
964 bool wxWindowBase::IsShownOnScreen() const
965 {
966 // A window is shown on screen if it itself is shown and so are all its
967 // parents. But if a window is toplevel one, then its always visible on
968 // screen if IsShown() returns true, even if it has a hidden parent.
969 return IsShown() &&
970 (IsTopLevel() || GetParent() == NULL || GetParent()->IsShownOnScreen());
971 }
972
973 // ----------------------------------------------------------------------------
974 // RTTI
975 // ----------------------------------------------------------------------------
976
977 bool wxWindowBase::IsTopLevel() const
978 {
979 return false;
980 }
981
982 // ----------------------------------------------------------------------------
983 // Freeze/Thaw
984 // ----------------------------------------------------------------------------
985
986 void wxWindowBase::Freeze()
987 {
988 if ( !m_freezeCount++ )
989 {
990 // physically freeze this window:
991 DoFreeze();
992
993 // and recursively freeze all children:
994 for ( wxWindowList::iterator i = GetChildren().begin();
995 i != GetChildren().end(); ++i )
996 {
997 wxWindow *child = *i;
998 if ( child->IsTopLevel() )
999 continue;
1000
1001 child->Freeze();
1002 }
1003 }
1004 }
1005
1006 void wxWindowBase::Thaw()
1007 {
1008 wxASSERT_MSG( m_freezeCount, "Thaw() without matching Freeze()" );
1009
1010 if ( !--m_freezeCount )
1011 {
1012 // recursively thaw all children:
1013 for ( wxWindowList::iterator i = GetChildren().begin();
1014 i != GetChildren().end(); ++i )
1015 {
1016 wxWindow *child = *i;
1017 if ( child->IsTopLevel() )
1018 continue;
1019
1020 child->Thaw();
1021 }
1022
1023 // physically thaw this window:
1024 DoThaw();
1025 }
1026 }
1027
1028 // ----------------------------------------------------------------------------
1029 // reparenting the window
1030 // ----------------------------------------------------------------------------
1031
1032 void wxWindowBase::AddChild(wxWindowBase *child)
1033 {
1034 wxCHECK_RET( child, wxT("can't add a NULL child") );
1035
1036 // this should never happen and it will lead to a crash later if it does
1037 // because RemoveChild() will remove only one node from the children list
1038 // and the other(s) one(s) will be left with dangling pointers in them
1039 wxASSERT_MSG( !GetChildren().Find((wxWindow*)child), _T("AddChild() called twice") );
1040
1041 GetChildren().Append((wxWindow*)child);
1042 child->SetParent(this);
1043
1044 // adding a child while frozen will assert when thawed, so freeze it as if
1045 // it had been already present when we were frozen
1046 if ( IsFrozen() && !child->IsTopLevel() )
1047 child->Freeze();
1048 }
1049
1050 void wxWindowBase::RemoveChild(wxWindowBase *child)
1051 {
1052 wxCHECK_RET( child, wxT("can't remove a NULL child") );
1053
1054 // removing a child while frozen may result in permanently frozen window
1055 // if used e.g. from Reparent(), so thaw it
1056 //
1057 // NB: IsTopLevel() doesn't return true any more when a TLW child is being
1058 // removed from its ~wxWindowBase, so check for IsBeingDeleted() too
1059 if ( IsFrozen() && !child->IsBeingDeleted() && !child->IsTopLevel() )
1060 child->Thaw();
1061
1062 GetChildren().DeleteObject((wxWindow *)child);
1063 child->SetParent(NULL);
1064 }
1065
1066 bool wxWindowBase::Reparent(wxWindowBase *newParent)
1067 {
1068 wxWindow *oldParent = GetParent();
1069 if ( newParent == oldParent )
1070 {
1071 // nothing done
1072 return false;
1073 }
1074
1075 const bool oldEnabledState = IsEnabled();
1076
1077 // unlink this window from the existing parent.
1078 if ( oldParent )
1079 {
1080 oldParent->RemoveChild(this);
1081 }
1082 else
1083 {
1084 wxTopLevelWindows.DeleteObject((wxWindow *)this);
1085 }
1086
1087 // add it to the new one
1088 if ( newParent )
1089 {
1090 newParent->AddChild(this);
1091 }
1092 else
1093 {
1094 wxTopLevelWindows.Append((wxWindow *)this);
1095 }
1096
1097 // We need to notify window (and its subwindows) if by changing the parent
1098 // we also change our enabled/disabled status.
1099 const bool newEnabledState = IsEnabled();
1100 if ( newEnabledState != oldEnabledState )
1101 {
1102 NotifyWindowOnEnableChange(newEnabledState);
1103 }
1104
1105 return true;
1106 }
1107
1108 // ----------------------------------------------------------------------------
1109 // event handler stuff
1110 // ----------------------------------------------------------------------------
1111
1112 void wxWindowBase::SetEventHandler(wxEvtHandler *handler)
1113 {
1114 wxCHECK_RET(handler != NULL, "SetEventHandler(NULL) called");
1115
1116 m_eventHandler = handler;
1117 }
1118
1119 void wxWindowBase::SetNextHandler(wxEvtHandler *WXUNUSED(handler))
1120 {
1121 // disable wxEvtHandler chain mechanism for wxWindows:
1122 // wxWindow uses its own stack mechanism which doesn't mix well with wxEvtHandler's one
1123
1124 wxFAIL_MSG("wxWindow cannot be part of a wxEvtHandler chain");
1125 }
1126 void wxWindowBase::SetPreviousHandler(wxEvtHandler *WXUNUSED(handler))
1127 {
1128 // we can't simply wxFAIL here as in SetNextHandler: in fact the last
1129 // handler of our stack when is destroyed will be Unlink()ed and thus
1130 // will call this function to update the pointer of this window...
1131
1132 //wxFAIL_MSG("wxWindow cannot be part of a wxEvtHandler chain");
1133 }
1134
1135 void wxWindowBase::PushEventHandler(wxEvtHandler *handlerToPush)
1136 {
1137 wxCHECK_RET( handlerToPush != NULL, "PushEventHandler(NULL) called" );
1138
1139 // the new handler is going to be part of the wxWindow stack of event handlers:
1140 // it can't be part also of an event handler double-linked chain:
1141 wxASSERT_MSG(handlerToPush->IsUnlinked(),
1142 "The handler being pushed in the wxWindow stack shouldn't be part of "
1143 "a wxEvtHandler chain; call Unlink() on it first");
1144
1145 wxEvtHandler *handlerOld = GetEventHandler();
1146 wxCHECK_RET( handlerOld, "an old event handler is NULL?" );
1147
1148 // now use wxEvtHandler double-linked list to implement a stack:
1149 handlerToPush->SetNextHandler(handlerOld);
1150
1151 if (handlerOld != this)
1152 handlerOld->SetPreviousHandler(handlerToPush);
1153
1154 SetEventHandler(handlerToPush);
1155
1156 #if wxDEBUG_LEVEL
1157 // final checks of the operations done above:
1158 wxASSERT_MSG( handlerToPush->GetPreviousHandler() == NULL,
1159 "the first handler of the wxWindow stack should "
1160 "have no previous handlers set" );
1161 wxASSERT_MSG( handlerToPush->GetNextHandler() != NULL,
1162 "the first handler of the wxWindow stack should "
1163 "have non-NULL next handler" );
1164
1165 wxEvtHandler* pLast = handlerToPush;
1166 while ( pLast && pLast != this )
1167 pLast = pLast->GetNextHandler();
1168 wxASSERT_MSG( pLast->GetNextHandler() == NULL,
1169 "the last handler of the wxWindow stack should "
1170 "have this window as next handler" );
1171 #endif // wxDEBUG_LEVEL
1172 }
1173
1174 wxEvtHandler *wxWindowBase::PopEventHandler(bool deleteHandler)
1175 {
1176 // we need to pop the wxWindow stack, i.e. we need to remove the first handler
1177
1178 wxEvtHandler *firstHandler = GetEventHandler();
1179 wxCHECK_MSG( firstHandler != NULL, NULL, "wxWindow cannot have a NULL event handler" );
1180 wxCHECK_MSG( firstHandler != this, NULL, "cannot pop the wxWindow itself" );
1181 wxCHECK_MSG( firstHandler->GetPreviousHandler() == NULL, NULL,
1182 "the first handler of the wxWindow stack should have no previous handlers set" );
1183
1184 wxEvtHandler *secondHandler = firstHandler->GetNextHandler();
1185 wxCHECK_MSG( secondHandler != NULL, NULL,
1186 "the first handler of the wxWindow stack should have non-NULL next handler" );
1187
1188 firstHandler->SetNextHandler(NULL);
1189 secondHandler->SetPreviousHandler(NULL);
1190
1191 // now firstHandler is completely unlinked; set secondHandler as the new window event handler
1192 SetEventHandler(secondHandler);
1193
1194 if ( deleteHandler )
1195 {
1196 delete firstHandler;
1197 firstHandler = NULL;
1198 }
1199
1200 return firstHandler;
1201 }
1202
1203 bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handlerToRemove)
1204 {
1205 wxCHECK_MSG( handlerToRemove != NULL, false, "RemoveEventHandler(NULL) called" );
1206 wxCHECK_MSG( handlerToRemove != this, false, "Cannot remove the window itself" );
1207
1208 if (handlerToRemove == GetEventHandler())
1209 {
1210 // removing the first event handler is equivalent to "popping" the stack
1211 PopEventHandler(false);
1212 return true;
1213 }
1214
1215 // NOTE: the wxWindow event handler list is always terminated with "this" handler
1216 wxEvtHandler *handlerCur = GetEventHandler()->GetNextHandler();
1217 while ( handlerCur != this )
1218 {
1219 wxEvtHandler *handlerNext = handlerCur->GetNextHandler();
1220
1221 if ( handlerCur == handlerToRemove )
1222 {
1223 handlerCur->Unlink();
1224
1225 wxASSERT_MSG( handlerCur != GetEventHandler(),
1226 "the case Remove == Pop should was already handled" );
1227 return true;
1228 }
1229
1230 handlerCur = handlerNext;
1231 }
1232
1233 wxFAIL_MSG( _T("where has the event handler gone?") );
1234
1235 return false;
1236 }
1237
1238 bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
1239 {
1240 // SafelyProcessEvent() will handle exceptions nicely
1241 return GetEventHandler()->SafelyProcessEvent(event);
1242 }
1243
1244 // ----------------------------------------------------------------------------
1245 // colours, fonts &c
1246 // ----------------------------------------------------------------------------
1247
1248 void wxWindowBase::InheritAttributes()
1249 {
1250 const wxWindowBase * const parent = GetParent();
1251 if ( !parent )
1252 return;
1253
1254 // we only inherit attributes which had been explicitly set for the parent
1255 // which ensures that this only happens if the user really wants it and
1256 // not by default which wouldn't make any sense in modern GUIs where the
1257 // controls don't all use the same fonts (nor colours)
1258 if ( parent->m_inheritFont && !m_hasFont )
1259 SetFont(parent->GetFont());
1260
1261 // in addition, there is a possibility to explicitly forbid inheriting
1262 // colours at each class level by overriding ShouldInheritColours()
1263 if ( ShouldInheritColours() )
1264 {
1265 if ( parent->m_inheritFgCol && !m_hasFgCol )
1266 SetForegroundColour(parent->GetForegroundColour());
1267
1268 // inheriting (solid) background colour is wrong as it totally breaks
1269 // any kind of themed backgrounds
1270 //
1271 // instead, the controls should use the same background as their parent
1272 // (ideally by not drawing it at all)
1273 #if 0
1274 if ( parent->m_inheritBgCol && !m_hasBgCol )
1275 SetBackgroundColour(parent->GetBackgroundColour());
1276 #endif // 0
1277 }
1278 }
1279
1280 /* static */ wxVisualAttributes
1281 wxWindowBase::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
1282 {
1283 // it is important to return valid values for all attributes from here,
1284 // GetXXX() below rely on this
1285 wxVisualAttributes attrs;
1286 attrs.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
1287 attrs.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
1288
1289 // On Smartphone/PocketPC, wxSYS_COLOUR_WINDOW is a better reflection of
1290 // the usual background colour than wxSYS_COLOUR_BTNFACE.
1291 // It's a pity that wxSYS_COLOUR_WINDOW isn't always a suitable background
1292 // colour on other platforms.
1293
1294 #if defined(__WXWINCE__) && (defined(__SMARTPHONE__) || defined(__POCKETPC__))
1295 attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
1296 #else
1297 attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
1298 #endif
1299 return attrs;
1300 }
1301
1302 wxColour wxWindowBase::GetBackgroundColour() const
1303 {
1304 if ( !m_backgroundColour.IsOk() )
1305 {
1306 wxASSERT_MSG( !m_hasBgCol, _T("we have invalid explicit bg colour?") );
1307
1308 // get our default background colour
1309 wxColour colBg = GetDefaultAttributes().colBg;
1310
1311 // we must return some valid colour to avoid redoing this every time
1312 // and also to avoid surprizing the applications written for older
1313 // wxWidgets versions where GetBackgroundColour() always returned
1314 // something -- so give them something even if it doesn't make sense
1315 // for this window (e.g. it has a themed background)
1316 if ( !colBg.Ok() )
1317 colBg = GetClassDefaultAttributes().colBg;
1318
1319 return colBg;
1320 }
1321 else
1322 return m_backgroundColour;
1323 }
1324
1325 wxColour wxWindowBase::GetForegroundColour() const
1326 {
1327 // logic is the same as above
1328 if ( !m_hasFgCol && !m_foregroundColour.Ok() )
1329 {
1330 wxColour colFg = GetDefaultAttributes().colFg;
1331
1332 if ( !colFg.IsOk() )
1333 colFg = GetClassDefaultAttributes().colFg;
1334
1335 return colFg;
1336 }
1337 else
1338 return m_foregroundColour;
1339 }
1340
1341 bool wxWindowBase::SetBackgroundColour( const wxColour &colour )
1342 {
1343 if ( colour == m_backgroundColour )
1344 return false;
1345
1346 m_hasBgCol = colour.IsOk();
1347
1348 m_inheritBgCol = m_hasBgCol;
1349 m_backgroundColour = colour;
1350 SetThemeEnabled( !m_hasBgCol && !m_foregroundColour.Ok() );
1351 return true;
1352 }
1353
1354 bool wxWindowBase::SetForegroundColour( const wxColour &colour )
1355 {
1356 if (colour == m_foregroundColour )
1357 return false;
1358
1359 m_hasFgCol = colour.IsOk();
1360 m_inheritFgCol = m_hasFgCol;
1361 m_foregroundColour = colour;
1362 SetThemeEnabled( !m_hasFgCol && !m_backgroundColour.Ok() );
1363 return true;
1364 }
1365
1366 bool wxWindowBase::SetCursor(const wxCursor& cursor)
1367 {
1368 // setting an invalid cursor is ok, it means that we don't have any special
1369 // cursor
1370 if ( m_cursor.IsSameAs(cursor) )
1371 {
1372 // no change
1373 return false;
1374 }
1375
1376 m_cursor = cursor;
1377
1378 return true;
1379 }
1380
1381 wxFont wxWindowBase::GetFont() const
1382 {
1383 // logic is the same as in GetBackgroundColour()
1384 if ( !m_font.IsOk() )
1385 {
1386 wxASSERT_MSG( !m_hasFont, _T("we have invalid explicit font?") );
1387
1388 wxFont font = GetDefaultAttributes().font;
1389 if ( !font.IsOk() )
1390 font = GetClassDefaultAttributes().font;
1391
1392 return font;
1393 }
1394 else
1395 return m_font;
1396 }
1397
1398 bool wxWindowBase::SetFont(const wxFont& font)
1399 {
1400 if ( font == m_font )
1401 {
1402 // no change
1403 return false;
1404 }
1405
1406 m_font = font;
1407 m_hasFont = font.IsOk();
1408 m_inheritFont = m_hasFont;
1409
1410 InvalidateBestSize();
1411
1412 return true;
1413 }
1414
1415 #if wxUSE_PALETTE
1416
1417 void wxWindowBase::SetPalette(const wxPalette& pal)
1418 {
1419 m_hasCustomPalette = true;
1420 m_palette = pal;
1421
1422 // VZ: can anyone explain me what do we do here?
1423 wxWindowDC d((wxWindow *) this);
1424 d.SetPalette(pal);
1425 }
1426
1427 wxWindow *wxWindowBase::GetAncestorWithCustomPalette() const
1428 {
1429 wxWindow *win = (wxWindow *)this;
1430 while ( win && !win->HasCustomPalette() )
1431 {
1432 win = win->GetParent();
1433 }
1434
1435 return win;
1436 }
1437
1438 #endif // wxUSE_PALETTE
1439
1440 #if wxUSE_CARET
1441 void wxWindowBase::SetCaret(wxCaret *caret)
1442 {
1443 if ( m_caret )
1444 {
1445 delete m_caret;
1446 }
1447
1448 m_caret = caret;
1449
1450 if ( m_caret )
1451 {
1452 wxASSERT_MSG( m_caret->GetWindow() == this,
1453 wxT("caret should be created associated to this window") );
1454 }
1455 }
1456 #endif // wxUSE_CARET
1457
1458 #if wxUSE_VALIDATORS
1459 // ----------------------------------------------------------------------------
1460 // validators
1461 // ----------------------------------------------------------------------------
1462
1463 void wxWindowBase::SetValidator(const wxValidator& validator)
1464 {
1465 if ( m_windowValidator )
1466 delete m_windowValidator;
1467
1468 m_windowValidator = (wxValidator *)validator.Clone();
1469
1470 if ( m_windowValidator )
1471 m_windowValidator->SetWindow(this);
1472 }
1473 #endif // wxUSE_VALIDATORS
1474
1475 // ----------------------------------------------------------------------------
1476 // update region stuff
1477 // ----------------------------------------------------------------------------
1478
1479 wxRect wxWindowBase::GetUpdateClientRect() const
1480 {
1481 wxRegion rgnUpdate = GetUpdateRegion();
1482 rgnUpdate.Intersect(GetClientRect());
1483 wxRect rectUpdate = rgnUpdate.GetBox();
1484 wxPoint ptOrigin = GetClientAreaOrigin();
1485 rectUpdate.x -= ptOrigin.x;
1486 rectUpdate.y -= ptOrigin.y;
1487
1488 return rectUpdate;
1489 }
1490
1491 bool wxWindowBase::DoIsExposed(int x, int y) const
1492 {
1493 return m_updateRegion.Contains(x, y) != wxOutRegion;
1494 }
1495
1496 bool wxWindowBase::DoIsExposed(int x, int y, int w, int h) const
1497 {
1498 return m_updateRegion.Contains(x, y, w, h) != wxOutRegion;
1499 }
1500
1501 void wxWindowBase::ClearBackground()
1502 {
1503 // wxGTK uses its own version, no need to add never used code
1504 #ifndef __WXGTK__
1505 wxClientDC dc((wxWindow *)this);
1506 wxBrush brush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID);
1507 dc.SetBackground(brush);
1508 dc.Clear();
1509 #endif // __WXGTK__
1510 }
1511
1512 // ----------------------------------------------------------------------------
1513 // find child window by id or name
1514 // ----------------------------------------------------------------------------
1515
1516 wxWindow *wxWindowBase::FindWindow(long id) const
1517 {
1518 if ( id == m_windowId )
1519 return (wxWindow *)this;
1520
1521 wxWindowBase *res = NULL;
1522 wxWindowList::compatibility_iterator node;
1523 for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() )
1524 {
1525 wxWindowBase *child = node->GetData();
1526 res = child->FindWindow( id );
1527 }
1528
1529 return (wxWindow *)res;
1530 }
1531
1532 wxWindow *wxWindowBase::FindWindow(const wxString& name) const
1533 {
1534 if ( name == m_windowName )
1535 return (wxWindow *)this;
1536
1537 wxWindowBase *res = NULL;
1538 wxWindowList::compatibility_iterator node;
1539 for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() )
1540 {
1541 wxWindow *child = node->GetData();
1542 res = child->FindWindow(name);
1543 }
1544
1545 return (wxWindow *)res;
1546 }
1547
1548
1549 // find any window by id or name or label: If parent is non-NULL, look through
1550 // children for a label or title matching the specified string. If NULL, look
1551 // through all top-level windows.
1552 //
1553 // to avoid duplicating code we reuse the same helper function but with
1554 // different comparators
1555
1556 typedef bool (*wxFindWindowCmp)(const wxWindow *win,
1557 const wxString& label, long id);
1558
1559 static
1560 bool wxFindWindowCmpLabels(const wxWindow *win, const wxString& label,
1561 long WXUNUSED(id))
1562 {
1563 return win->GetLabel() == label;
1564 }
1565
1566 static
1567 bool wxFindWindowCmpNames(const wxWindow *win, const wxString& label,
1568 long WXUNUSED(id))
1569 {
1570 return win->GetName() == label;
1571 }
1572
1573 static
1574 bool wxFindWindowCmpIds(const wxWindow *win, const wxString& WXUNUSED(label),
1575 long id)
1576 {
1577 return win->GetId() == id;
1578 }
1579
1580 // recursive helper for the FindWindowByXXX() functions
1581 static
1582 wxWindow *wxFindWindowRecursively(const wxWindow *parent,
1583 const wxString& label,
1584 long id,
1585 wxFindWindowCmp cmp)
1586 {
1587 if ( parent )
1588 {
1589 // see if this is the one we're looking for
1590 if ( (*cmp)(parent, label, id) )
1591 return (wxWindow *)parent;
1592
1593 // It wasn't, so check all its children
1594 for ( wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst();
1595 node;
1596 node = node->GetNext() )
1597 {
1598 // recursively check each child
1599 wxWindow *win = (wxWindow *)node->GetData();
1600 wxWindow *retwin = wxFindWindowRecursively(win, label, id, cmp);
1601 if (retwin)
1602 return retwin;
1603 }
1604 }
1605
1606 // Not found
1607 return NULL;
1608 }
1609
1610 // helper for FindWindowByXXX()
1611 static
1612 wxWindow *wxFindWindowHelper(const wxWindow *parent,
1613 const wxString& label,
1614 long id,
1615 wxFindWindowCmp cmp)
1616 {
1617 if ( parent )
1618 {
1619 // just check parent and all its children
1620 return wxFindWindowRecursively(parent, label, id, cmp);
1621 }
1622
1623 // start at very top of wx's windows
1624 for ( wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
1625 node;
1626 node = node->GetNext() )
1627 {
1628 // recursively check each window & its children
1629 wxWindow *win = node->GetData();
1630 wxWindow *retwin = wxFindWindowRecursively(win, label, id, cmp);
1631 if (retwin)
1632 return retwin;
1633 }
1634
1635 return NULL;
1636 }
1637
1638 /* static */
1639 wxWindow *
1640 wxWindowBase::FindWindowByLabel(const wxString& title, const wxWindow *parent)
1641 {
1642 return wxFindWindowHelper(parent, title, 0, wxFindWindowCmpLabels);
1643 }
1644
1645 /* static */
1646 wxWindow *
1647 wxWindowBase::FindWindowByName(const wxString& title, const wxWindow *parent)
1648 {
1649 wxWindow *win = wxFindWindowHelper(parent, title, 0, wxFindWindowCmpNames);
1650
1651 if ( !win )
1652 {
1653 // fall back to the label
1654 win = FindWindowByLabel(title, parent);
1655 }
1656
1657 return win;
1658 }
1659
1660 /* static */
1661 wxWindow *
1662 wxWindowBase::FindWindowById( long id, const wxWindow* parent )
1663 {
1664 return wxFindWindowHelper(parent, wxEmptyString, id, wxFindWindowCmpIds);
1665 }
1666
1667 // ----------------------------------------------------------------------------
1668 // dialog oriented functions
1669 // ----------------------------------------------------------------------------
1670
1671 void wxWindowBase::MakeModal(bool modal)
1672 {
1673 // Disable all other windows
1674 if ( IsTopLevel() )
1675 {
1676 wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
1677 while (node)
1678 {
1679 wxWindow *win = node->GetData();
1680 if (win != this)
1681 win->Enable(!modal);
1682
1683 node = node->GetNext();
1684 }
1685 }
1686 }
1687
1688 bool wxWindowBase::Validate()
1689 {
1690 #if wxUSE_VALIDATORS
1691 bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0;
1692
1693 wxWindowList::compatibility_iterator node;
1694 for ( node = m_children.GetFirst(); node; node = node->GetNext() )
1695 {
1696 wxWindowBase *child = node->GetData();
1697 wxValidator *validator = child->GetValidator();
1698 if ( validator && !validator->Validate((wxWindow *)this) )
1699 {
1700 return false;
1701 }
1702
1703 if ( recurse && !child->Validate() )
1704 {
1705 return false;
1706 }
1707 }
1708 #endif // wxUSE_VALIDATORS
1709
1710 return true;
1711 }
1712
1713 bool wxWindowBase::TransferDataToWindow()
1714 {
1715 #if wxUSE_VALIDATORS
1716 bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0;
1717
1718 wxWindowList::compatibility_iterator node;
1719 for ( node = m_children.GetFirst(); node; node = node->GetNext() )
1720 {
1721 wxWindowBase *child = node->GetData();
1722 wxValidator *validator = child->GetValidator();
1723 if ( validator && !validator->TransferToWindow() )
1724 {
1725 wxLogWarning(_("Could not transfer data to window"));
1726 #if wxUSE_LOG
1727 wxLog::FlushActive();
1728 #endif // wxUSE_LOG
1729
1730 return false;
1731 }
1732
1733 if ( recurse )
1734 {
1735 if ( !child->TransferDataToWindow() )
1736 {
1737 // warning already given
1738 return false;
1739 }
1740 }
1741 }
1742 #endif // wxUSE_VALIDATORS
1743
1744 return true;
1745 }
1746
1747 bool wxWindowBase::TransferDataFromWindow()
1748 {
1749 #if wxUSE_VALIDATORS
1750 bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0;
1751
1752 wxWindowList::compatibility_iterator node;
1753 for ( node = m_children.GetFirst(); node; node = node->GetNext() )
1754 {
1755 wxWindow *child = node->GetData();
1756 wxValidator *validator = child->GetValidator();
1757 if ( validator && !validator->TransferFromWindow() )
1758 {
1759 // nop warning here because the application is supposed to give
1760 // one itself - we don't know here what might have gone wrongly
1761
1762 return false;
1763 }
1764
1765 if ( recurse )
1766 {
1767 if ( !child->TransferDataFromWindow() )
1768 {
1769 // warning already given
1770 return false;
1771 }
1772 }
1773 }
1774 #endif // wxUSE_VALIDATORS
1775
1776 return true;
1777 }
1778
1779 void wxWindowBase::InitDialog()
1780 {
1781 wxInitDialogEvent event(GetId());
1782 event.SetEventObject( this );
1783 GetEventHandler()->ProcessEvent(event);
1784 }
1785
1786 // ----------------------------------------------------------------------------
1787 // context-sensitive help support
1788 // ----------------------------------------------------------------------------
1789
1790 #if wxUSE_HELP
1791
1792 // associate this help text with this window
1793 void wxWindowBase::SetHelpText(const wxString& text)
1794 {
1795 wxHelpProvider *helpProvider = wxHelpProvider::Get();
1796 if ( helpProvider )
1797 {
1798 helpProvider->AddHelp(this, text);
1799 }
1800 }
1801
1802 #if WXWIN_COMPATIBILITY_2_8
1803 // associate this help text with all windows with the same id as this
1804 // one
1805 void wxWindowBase::SetHelpTextForId(const wxString& text)
1806 {
1807 wxHelpProvider *helpProvider = wxHelpProvider::Get();
1808 if ( helpProvider )
1809 {
1810 helpProvider->AddHelp(GetId(), text);
1811 }
1812 }
1813 #endif // WXWIN_COMPATIBILITY_2_8
1814
1815 // get the help string associated with this window (may be empty)
1816 // default implementation forwards calls to the help provider
1817 wxString
1818 wxWindowBase::GetHelpTextAtPoint(const wxPoint & WXUNUSED(pt),
1819 wxHelpEvent::Origin WXUNUSED(origin)) const
1820 {
1821 wxString text;
1822 wxHelpProvider *helpProvider = wxHelpProvider::Get();
1823 if ( helpProvider )
1824 {
1825 text = helpProvider->GetHelp(this);
1826 }
1827
1828 return text;
1829 }
1830
1831 // show help for this window
1832 void wxWindowBase::OnHelp(wxHelpEvent& event)
1833 {
1834 wxHelpProvider *helpProvider = wxHelpProvider::Get();
1835 if ( helpProvider )
1836 {
1837 wxPoint pos = event.GetPosition();
1838 const wxHelpEvent::Origin origin = event.GetOrigin();
1839 if ( origin == wxHelpEvent::Origin_Keyboard )
1840 {
1841 // if the help event was generated from keyboard it shouldn't
1842 // appear at the mouse position (which is still the only position
1843 // associated with help event) if the mouse is far away, although
1844 // we still do use the mouse position if it's over the window
1845 // because we suppose the user looks approximately at the mouse
1846 // already and so it would be more convenient than showing tooltip
1847 // at some arbitrary position which can be quite far from it
1848 const wxRect rectClient = GetClientRect();
1849 if ( !rectClient.Contains(ScreenToClient(pos)) )
1850 {
1851 // position help slightly under and to the right of this window
1852 pos = ClientToScreen(wxPoint(
1853 2*GetCharWidth(),
1854 rectClient.height + GetCharHeight()
1855 ));
1856 }
1857 }
1858
1859 if ( helpProvider->ShowHelpAtPoint(this, pos, origin) )
1860 {
1861 // skip the event.Skip() below
1862 return;
1863 }
1864 }
1865
1866 event.Skip();
1867 }
1868
1869 #endif // wxUSE_HELP
1870
1871 // ----------------------------------------------------------------------------
1872 // tooltips
1873 // ----------------------------------------------------------------------------
1874
1875 #if wxUSE_TOOLTIPS
1876
1877 void wxWindowBase::SetToolTip( const wxString &tip )
1878 {
1879 // don't create the new tooltip if we already have one
1880 if ( m_tooltip )
1881 {
1882 m_tooltip->SetTip( tip );
1883 }
1884 else
1885 {
1886 SetToolTip( new wxToolTip( tip ) );
1887 }
1888
1889 // setting empty tooltip text does not remove the tooltip any more - use
1890 // SetToolTip(NULL) for this
1891 }
1892
1893 void wxWindowBase::DoSetToolTip(wxToolTip *tooltip)
1894 {
1895 if ( m_tooltip != tooltip )
1896 {
1897 if ( m_tooltip )
1898 delete m_tooltip;
1899
1900 m_tooltip = tooltip;
1901 }
1902 }
1903
1904 #endif // wxUSE_TOOLTIPS
1905
1906 // ----------------------------------------------------------------------------
1907 // constraints and sizers
1908 // ----------------------------------------------------------------------------
1909
1910 #if wxUSE_CONSTRAINTS
1911
1912 void wxWindowBase::SetConstraints( wxLayoutConstraints *constraints )
1913 {
1914 if ( m_constraints )
1915 {
1916 UnsetConstraints(m_constraints);
1917 delete m_constraints;
1918 }
1919 m_constraints = constraints;
1920 if ( m_constraints )
1921 {
1922 // Make sure other windows know they're part of a 'meaningful relationship'
1923 if ( m_constraints->left.GetOtherWindow() && (m_constraints->left.GetOtherWindow() != this) )
1924 m_constraints->left.GetOtherWindow()->AddConstraintReference(this);
1925 if ( m_constraints->top.GetOtherWindow() && (m_constraints->top.GetOtherWindow() != this) )
1926 m_constraints->top.GetOtherWindow()->AddConstraintReference(this);
1927 if ( m_constraints->right.GetOtherWindow() && (m_constraints->right.GetOtherWindow() != this) )
1928 m_constraints->right.GetOtherWindow()->AddConstraintReference(this);
1929 if ( m_constraints->bottom.GetOtherWindow() && (m_constraints->bottom.GetOtherWindow() != this) )
1930 m_constraints->bottom.GetOtherWindow()->AddConstraintReference(this);
1931 if ( m_constraints->width.GetOtherWindow() && (m_constraints->width.GetOtherWindow() != this) )
1932 m_constraints->width.GetOtherWindow()->AddConstraintReference(this);
1933 if ( m_constraints->height.GetOtherWindow() && (m_constraints->height.GetOtherWindow() != this) )
1934 m_constraints->height.GetOtherWindow()->AddConstraintReference(this);
1935 if ( m_constraints->centreX.GetOtherWindow() && (m_constraints->centreX.GetOtherWindow() != this) )
1936 m_constraints->centreX.GetOtherWindow()->AddConstraintReference(this);
1937 if ( m_constraints->centreY.GetOtherWindow() && (m_constraints->centreY.GetOtherWindow() != this) )
1938 m_constraints->centreY.GetOtherWindow()->AddConstraintReference(this);
1939 }
1940 }
1941
1942 // This removes any dangling pointers to this window in other windows'
1943 // constraintsInvolvedIn lists.
1944 void wxWindowBase::UnsetConstraints(wxLayoutConstraints *c)
1945 {
1946 if ( c )
1947 {
1948 if ( c->left.GetOtherWindow() && (c->top.GetOtherWindow() != this) )
1949 c->left.GetOtherWindow()->RemoveConstraintReference(this);
1950 if ( c->top.GetOtherWindow() && (c->top.GetOtherWindow() != this) )
1951 c->top.GetOtherWindow()->RemoveConstraintReference(this);
1952 if ( c->right.GetOtherWindow() && (c->right.GetOtherWindow() != this) )
1953 c->right.GetOtherWindow()->RemoveConstraintReference(this);
1954 if ( c->bottom.GetOtherWindow() && (c->bottom.GetOtherWindow() != this) )
1955 c->bottom.GetOtherWindow()->RemoveConstraintReference(this);
1956 if ( c->width.GetOtherWindow() && (c->width.GetOtherWindow() != this) )
1957 c->width.GetOtherWindow()->RemoveConstraintReference(this);
1958 if ( c->height.GetOtherWindow() && (c->height.GetOtherWindow() != this) )
1959 c->height.GetOtherWindow()->RemoveConstraintReference(this);
1960 if ( c->centreX.GetOtherWindow() && (c->centreX.GetOtherWindow() != this) )
1961 c->centreX.GetOtherWindow()->RemoveConstraintReference(this);
1962 if ( c->centreY.GetOtherWindow() && (c->centreY.GetOtherWindow() != this) )
1963 c->centreY.GetOtherWindow()->RemoveConstraintReference(this);
1964 }
1965 }
1966
1967 // Back-pointer to other windows we're involved with, so if we delete this
1968 // window, we must delete any constraints we're involved with.
1969 void wxWindowBase::AddConstraintReference(wxWindowBase *otherWin)
1970 {
1971 if ( !m_constraintsInvolvedIn )
1972 m_constraintsInvolvedIn = new wxWindowList;
1973 if ( !m_constraintsInvolvedIn->Find((wxWindow *)otherWin) )
1974 m_constraintsInvolvedIn->Append((wxWindow *)otherWin);
1975 }
1976
1977 // REMOVE back-pointer to other windows we're involved with.
1978 void wxWindowBase::RemoveConstraintReference(wxWindowBase *otherWin)
1979 {
1980 if ( m_constraintsInvolvedIn )
1981 m_constraintsInvolvedIn->DeleteObject((wxWindow *)otherWin);
1982 }
1983
1984 // Reset any constraints that mention this window
1985 void wxWindowBase::DeleteRelatedConstraints()
1986 {
1987 if ( m_constraintsInvolvedIn )
1988 {
1989 wxWindowList::compatibility_iterator node = m_constraintsInvolvedIn->GetFirst();
1990 while (node)
1991 {
1992 wxWindow *win = node->GetData();
1993 wxLayoutConstraints *constr = win->GetConstraints();
1994
1995 // Reset any constraints involving this window
1996 if ( constr )
1997 {
1998 constr->left.ResetIfWin(this);
1999 constr->top.ResetIfWin(this);
2000 constr->right.ResetIfWin(this);
2001 constr->bottom.ResetIfWin(this);
2002 constr->width.ResetIfWin(this);
2003 constr->height.ResetIfWin(this);
2004 constr->centreX.ResetIfWin(this);
2005 constr->centreY.ResetIfWin(this);
2006 }
2007
2008 wxWindowList::compatibility_iterator next = node->GetNext();
2009 m_constraintsInvolvedIn->Erase(node);
2010 node = next;
2011 }
2012
2013 delete m_constraintsInvolvedIn;
2014 m_constraintsInvolvedIn = NULL;
2015 }
2016 }
2017
2018 #endif // wxUSE_CONSTRAINTS
2019
2020 void wxWindowBase::SetSizer(wxSizer *sizer, bool deleteOld)
2021 {
2022 if ( sizer == m_windowSizer)
2023 return;
2024
2025 if ( m_windowSizer )
2026 {
2027 m_windowSizer->SetContainingWindow(NULL);
2028
2029 if ( deleteOld )
2030 delete m_windowSizer;
2031 }
2032
2033 m_windowSizer = sizer;
2034 if ( m_windowSizer )
2035 {
2036 m_windowSizer->SetContainingWindow((wxWindow *)this);
2037 }
2038
2039 SetAutoLayout(m_windowSizer != NULL);
2040 }
2041
2042 void wxWindowBase::SetSizerAndFit(wxSizer *sizer, bool deleteOld)
2043 {
2044 SetSizer( sizer, deleteOld );
2045 sizer->SetSizeHints( (wxWindow*) this );
2046 }
2047
2048
2049 void wxWindowBase::SetContainingSizer(wxSizer* sizer)
2050 {
2051 // adding a window to a sizer twice is going to result in fatal and
2052 // hard to debug problems later because when deleting the second
2053 // associated wxSizerItem we're going to dereference a dangling
2054 // pointer; so try to detect this as early as possible
2055 wxASSERT_MSG( !sizer || m_containingSizer != sizer,
2056 _T("Adding a window to the same sizer twice?") );
2057
2058 m_containingSizer = sizer;
2059 }
2060
2061 #if wxUSE_CONSTRAINTS
2062
2063 void wxWindowBase::SatisfyConstraints()
2064 {
2065 wxLayoutConstraints *constr = GetConstraints();
2066 bool wasOk = constr && constr->AreSatisfied();
2067
2068 ResetConstraints(); // Mark all constraints as unevaluated
2069
2070 int noChanges = 1;
2071
2072 // if we're a top level panel (i.e. our parent is frame/dialog), our
2073 // own constraints will never be satisfied any more unless we do it
2074 // here
2075 if ( wasOk )
2076 {
2077 while ( noChanges > 0 )
2078 {
2079 LayoutPhase1(&noChanges);
2080 }
2081 }
2082
2083 LayoutPhase2(&noChanges);
2084 }
2085
2086 #endif // wxUSE_CONSTRAINTS
2087
2088 bool wxWindowBase::Layout()
2089 {
2090 // If there is a sizer, use it instead of the constraints
2091 if ( GetSizer() )
2092 {
2093 int w = 0, h = 0;
2094 GetVirtualSize(&w, &h);
2095 GetSizer()->SetDimension( 0, 0, w, h );
2096 }
2097 #if wxUSE_CONSTRAINTS
2098 else
2099 {
2100 SatisfyConstraints(); // Find the right constraints values
2101 SetConstraintSizes(); // Recursively set the real window sizes
2102 }
2103 #endif
2104
2105 return true;
2106 }
2107
2108 void wxWindowBase::InternalOnSize(wxSizeEvent& event)
2109 {
2110 if ( GetAutoLayout() )
2111 Layout();
2112
2113 event.Skip();
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 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::TryBefore(wxEvent& 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 wxEvtHandler::TryBefore(event);
2890 }
2891
2892 bool wxWindowBase::TryAfter(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::TryAfter(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 wxDECLARE_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