]> git.saurik.com Git - wxWidgets.git/blame - src/common/containr.cpp
Misc validity fixes to samples/xrc/rc/*.xrc.
[wxWidgets.git] / src / common / containr.cpp
CommitLineData
456bc6d9
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/common/containr.cpp
3// Purpose: implementation of wxControlContainer
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 06.08.01
456bc6d9 7// Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
526954c5 8// Licence: wxWindows licence
456bc6d9
VZ
9///////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
456bc6d9
VZ
19// For compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
de160b06
VZ
26#ifndef WX_PRECOMP
27 #include "wx/containr.h"
28#endif
29
456bc6d9 30#ifndef WX_PRECOMP
6285be72
VZ
31 #include "wx/log.h"
32 #include "wx/event.h"
33 #include "wx/window.h"
851dee09 34 #include "wx/scrolbar.h"
b0b5881a 35 #include "wx/radiobut.h"
456bc6d9
VZ
36#endif //WX_PRECOMP
37
9f542367 38// trace mask for focus messages
9a83f860 39#define TRACE_FOCUS wxT("focus")
9f542367 40
456bc6d9
VZ
41// ============================================================================
42// implementation
43// ============================================================================
44
80332672
VZ
45// ----------------------------------------------------------------------------
46// wxControlContainerBase
47// ----------------------------------------------------------------------------
48
2c750dae
VZ
49void wxControlContainerBase::UpdateParentCanFocus()
50{
51 // In the ports where it does something non trivial, the parent window
52 // should only be focusable if it doesn't have any focusable children
53 // (e.g. native focus handling in wxGTK totally breaks down otherwise).
54 m_winParent->SetCanFocus(m_acceptsFocusSelf && !m_acceptsFocusChildren);
55}
56
e68b7b36 57bool wxControlContainerBase::UpdateCanFocusChildren()
456bc6d9 58{
e68b7b36
VZ
59 const bool acceptsFocusChildren = HasAnyFocusableChildren();
60 if ( acceptsFocusChildren != m_acceptsFocusChildren )
61 {
62 m_acceptsFocusChildren = acceptsFocusChildren;
80332672 63
2c750dae 64 UpdateParentCanFocus();
e68b7b36 65 }
80332672 66
e68b7b36 67 return m_acceptsFocusChildren;
456bc6d9
VZ
68}
69
edc09871 70bool wxControlContainerBase::HasAnyFocusableChildren() const
3251b834 71{
edc09871
VZ
72 const wxWindowList& children = m_winParent->GetChildren();
73 for ( wxWindowList::const_iterator i = children.begin(),
74 end = children.end();
75 i != end;
76 ++i )
de160b06 77 {
edc09871 78 const wxWindow * const child = *i;
3251b834 79
049908c5 80 if ( !m_winParent->IsClientAreaChild(child) )
de160b06 81 continue;
80332672 82
dee22e31
VZ
83 // Here we check whether the child can accept the focus at all, as we
84 // want to try focusing it later even if it can't accept it right now.
85 if ( child->AcceptsFocusRecursively() )
86 return true;
87 }
88
89 return false;
90}
91
92bool wxControlContainerBase::HasAnyChildrenAcceptingFocus() const
93{
94 const wxWindowList& children = m_winParent->GetChildren();
95 for ( wxWindowList::const_iterator i = children.begin(),
96 end = children.end();
97 i != end;
98 ++i )
99 {
100 const wxWindow * const child = *i;
101
102 if ( !m_winParent->IsClientAreaChild(child) )
103 continue;
104
105 // Here we check if the child accepts focus right now as we need to
106 // know if we can give the focus to it or not.
de160b06 107 if ( child->CanAcceptFocus() )
edc09871 108 return true;
de160b06 109 }
c9d59ee7 110
edc09871 111 return false;
80332672
VZ
112}
113
c7bfb76a
JS
114bool wxControlContainerBase::DoSetFocus()
115{
9a83f860 116 wxLogTrace(TRACE_FOCUS, wxT("SetFocus on wxPanel 0x%p."),
c7bfb76a
JS
117 m_winParent->GetHandle());
118
119 if (m_inSetFocus)
120 return true;
121
122 // when the panel gets the focus we move the focus to either the last
123 // window that had the focus or the first one that can get it unless the
124 // focus had been already set to some other child
125
126 wxWindow *win = wxWindow::FindFocus();
127 while ( win )
128 {
129 if ( win == m_winParent )
130 {
131 // our child already has focus, don't take it away from it
132 return true;
133 }
134
135 if ( win->IsTopLevel() )
136 {
137 // don't look beyond the first top level parent - useless and
138 // unnecessary
139 break;
140 }
141
142 win = win->GetParent();
143 }
144
145 // protect against infinite recursion:
146 m_inSetFocus = true;
147
148 bool ret = SetFocusToChild();
149
150 m_inSetFocus = false;
151
152 return ret;
153}
154
1b7c3d90
VZ
155bool wxControlContainerBase::AcceptsFocus() const
156{
157 return m_acceptsFocusSelf && m_winParent->CanBeFocused();
158}
159
c7bfb76a
JS
160bool wxControlContainerBase::SetFocusToChild()
161{
162 return wxSetFocusToChild(m_winParent, &m_winLastFocused);
163}
164
80332672 165#ifndef wxHAS_NATIVE_TAB_TRAVERSAL
3251b834 166
80332672
VZ
167// ----------------------------------------------------------------------------
168// generic wxControlContainer
169// ----------------------------------------------------------------------------
170
171wxControlContainer::wxControlContainer()
172{
173 m_winLastFocused = NULL;
3251b834
VZ
174}
175
456bc6d9
VZ
176void wxControlContainer::SetLastFocus(wxWindow *win)
177{
6aeb6f2a
VZ
178 // the panel itself should never get the focus at all but if it does happen
179 // temporarily (as it seems to do under wxGTK), at the very least don't
180 // forget our previous m_winLastFocused
c25b5d1f 181 if ( win != m_winParent )
456bc6d9 182 {
c25b5d1f
VZ
183 // if we're setting the focus
184 if ( win )
83c865f5 185 {
c25b5d1f
VZ
186 // find the last _immediate_ child which got focus
187 wxWindow *winParent = win;
188 while ( winParent != m_winParent )
189 {
190 win = winParent;
191 winParent = win->GetParent();
83c865f5 192
c25b5d1f
VZ
193 // Yes, this can happen, though in a totally pathological case.
194 // like when detaching a menubar from a frame with a child
195 // which has pushed itself as an event handler for the menubar.
196 // (under wxGTK)
6f8239de 197
c25b5d1f 198 wxASSERT_MSG( winParent,
9a83f860 199 wxT("Setting last focus for a window that is not our child?") );
c25b5d1f 200 }
6f8239de 201 }
456bc6d9 202
c25b5d1f 203 m_winLastFocused = win;
6aeb6f2a 204
c25b5d1f
VZ
205 if ( win )
206 {
9a83f860 207 wxLogTrace(TRACE_FOCUS, wxT("Set last focus to %s(%s)"),
c25b5d1f
VZ
208 win->GetClassInfo()->GetClassName(),
209 win->GetLabel().c_str());
210 }
211 else
212 {
9a83f860 213 wxLogTrace(TRACE_FOCUS, wxT("No more last focus"));
c25b5d1f 214 }
6aeb6f2a 215 }
456bc6d9
VZ
216}
217
7ff1b620 218// --------------------------------------------------------------------
b49f58fe 219// The following four functions are used to find other radio buttons
7ff1b620
VZ
220// within the same group. Used by wxSetFocusToChild on wxMSW
221// --------------------------------------------------------------------
222
4164a04a 223#if wxUSE_RADIOBTN
7ff1b620
VZ
224
225wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn)
226{
227 if ( btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) )
228 return NULL;
229
230 const wxWindowList& siblings = btn->GetParent()->GetChildren();
231 wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn);
9a83f860 232 wxCHECK_MSG( nodeThis, NULL, wxT("radio button not a child of its parent?") );
7ff1b620
VZ
233
234 // Iterate over all previous siblings until we find the next radio button
235 wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious();
236 wxRadioButton *prevBtn = 0;
237 while (nodeBefore)
238 {
239 prevBtn = wxDynamicCast(nodeBefore->GetData(), wxRadioButton);
240 if (prevBtn)
241 break;
242
243 nodeBefore = nodeBefore->GetPrevious();
244 }
b49f58fe 245
7ff1b620
VZ
246 if (!prevBtn || prevBtn->HasFlag(wxRB_SINGLE))
247 {
248 // no more buttons in group
249 return NULL;
250 }
3d3afaec
JS
251
252 return prevBtn;
7ff1b620
VZ
253}
254
255wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn)
256{
257 if (btn->HasFlag(wxRB_SINGLE))
258 return NULL;
259
260 const wxWindowList& siblings = btn->GetParent()->GetChildren();
261 wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn);
9a83f860 262 wxCHECK_MSG( nodeThis, NULL, wxT("radio button not a child of its parent?") );
7ff1b620
VZ
263
264 // Iterate over all previous siblings until we find the next radio button
265 wxWindowList::compatibility_iterator nodeNext = nodeThis->GetNext();
266 wxRadioButton *nextBtn = 0;
267 while (nodeNext)
268 {
269 nextBtn = wxDynamicCast(nodeNext->GetData(), wxRadioButton);
270 if (nextBtn)
271 break;
272
273 nodeNext = nodeNext->GetNext();
274 }
275
276 if ( !nextBtn || nextBtn->HasFlag(wxRB_GROUP) || nextBtn->HasFlag(wxRB_SINGLE) )
277 {
278 // no more buttons or the first button of the next group
279 return NULL;
280 }
3d3afaec
JS
281
282 return nextBtn;
7ff1b620
VZ
283}
284
285wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn)
286{
287 while (true)
288 {
289 wxRadioButton* prevBtn = wxGetPreviousButtonInGroup(btn);
290 if (!prevBtn)
291 return btn;
b49f58fe 292
7ff1b620
VZ
293 btn = prevBtn;
294 }
295}
296
3d3afaec
JS
297wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn)
298{
299 while (true)
300 {
301 wxRadioButton* nextBtn = wxGetNextButtonInGroup(btn);
302 if (!nextBtn)
303 return btn;
304
305 btn = nextBtn;
306 }
307}
308
7ff1b620
VZ
309wxRadioButton* wxGetSelectedButtonInGroup(wxRadioButton *btn)
310{
311 // Find currently selected button
312 if (btn->GetValue())
313 return btn;
314
315 if (btn->HasFlag(wxRB_SINGLE))
316 return NULL;
317
318 wxRadioButton *selBtn;
319
320 // First check all previous buttons
321 for (selBtn = wxGetPreviousButtonInGroup(btn); selBtn; selBtn = wxGetPreviousButtonInGroup(selBtn))
322 if (selBtn->GetValue())
323 return selBtn;
324
325 // Now all following buttons
326 for (selBtn = wxGetNextButtonInGroup(btn); selBtn; selBtn = wxGetNextButtonInGroup(selBtn))
327 if (selBtn->GetValue())
328 return selBtn;
329
330 return NULL;
331}
332
b49f58fe 333#endif // __WXMSW__
7ff1b620 334
456bc6d9
VZ
335// ----------------------------------------------------------------------------
336// Keyboard handling - this is the place where the TAB traversal logic is
337// implemented. As this code is common to all ports, this ensures consistent
338// behaviour even if we don't specify how exactly the wxNavigationKeyEvent are
339// generated and this is done in platform specific code which also ensures that
340// we can follow the given platform standards.
341// ----------------------------------------------------------------------------
342
343void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event )
344{
391b1695
VZ
345 // for a TLW we shouldn't involve the parent window, it has nothing to do
346 // with keyboard navigation inside this TLW
347 wxWindow *parent = m_winParent->IsTopLevel() ? NULL
348 : m_winParent->GetParent();
456bc6d9
VZ
349
350 // the event is propagated downwards if the event emitter was our parent
351 bool goingDown = event.GetEventObject() == parent;
352
353 const wxWindowList& children = m_winParent->GetChildren();
354
f2426531
VZ
355 // if we have exactly one notebook-like child window (actually it could be
356 // any window that returns true from its HasMultiplePages()), then
357 // [Shift-]Ctrl-Tab and Ctrl-PageUp/Down keys should iterate over its pages
358 // even if the focus is outside of the control because this is how the
359 // standard MSW properties dialogs behave and we do it under other platforms
360 // as well because it seems like a good idea -- but we can always put this
361 // block inside "#ifdef __WXMSW__" if it's not suitable there
362 if ( event.IsWindowChange() && !goingDown )
363 {
364 // check if we have a unique notebook-like child
365 wxWindow *bookctrl = NULL;
366 for ( wxWindowList::const_iterator i = children.begin(),
367 end = children.end();
368 i != end;
369 ++i )
370 {
371 wxWindow * const window = *i;
372 if ( window->HasMultiplePages() )
373 {
374 if ( bookctrl )
375 {
376 // this is the second book-like control already so don't do
377 // anything as we don't know which one should have its page
378 // changed
379 bookctrl = NULL;
380 break;
381 }
382
383 bookctrl = window;
384 }
385 }
386
5f28de16
VZ
387 if ( bookctrl )
388 {
389 // make sure that we don't bubble up the event again from the book
390 // control resulting in infinite recursion
391 wxNavigationKeyEvent eventCopy(event);
392 eventCopy.SetEventObject(m_winParent);
393 if ( bookctrl->GetEventHandler()->ProcessEvent(eventCopy) )
394 return;
395 }
f2426531
VZ
396 }
397
456bc6d9
VZ
398 // there is not much to do if we don't have children and we're not
399 // interested in "notebook page change" events here
400 if ( !children.GetCount() || event.IsWindowChange() )
401 {
402 // let the parent process it unless it already comes from our parent
403 // of we don't have any
404 if ( goingDown ||
405 !parent || !parent->GetEventHandler()->ProcessEvent(event) )
406 {
407 event.Skip();
408 }
409
410 return;
411 }
412
413 // where are we going?
edc0a395 414 const bool forward = event.GetDirection();
456bc6d9
VZ
415
416 // the node of the children list from which we should start looking for the
417 // next acceptable child
222ed1d6 418 wxWindowList::compatibility_iterator node, start_node;
456bc6d9
VZ
419
420 // we should start from the first/last control and not from the one which
421 // had focus the last time if we're propagating the event downwards because
422 // for our parent we look like a single control
423 if ( goingDown )
424 {
425 // just to be sure it's not used (normally this is not necessary, but
426 // doesn't hurt neither)
d3b9f782 427 m_winLastFocused = NULL;
456bc6d9
VZ
428
429 // start from first or last depending on where we're going
430 node = forward ? children.GetFirst() : children.GetLast();
456bc6d9 431 }
edc0a395 432 else // going up
456bc6d9
VZ
433 {
434 // try to find the child which has the focus currently
435
436 // the event emitter might have done this for us
437 wxWindow *winFocus = event.GetCurrentFocus();
438
439 // but if not, we might know where the focus was ourselves
440 if (!winFocus)
441 winFocus = m_winLastFocused;
442
443 // if still no luck, do it the hard way
444 if (!winFocus)
445 winFocus = wxWindow::FindFocus();
446
447 if ( winFocus )
448 {
a8ff046b 449#if defined(__WXMSW__) && wxUSE_RADIOBTN
b49f58fe 450 // If we are in a radio button group, start from the first item in the
7ff1b620
VZ
451 // group
452 if ( event.IsFromTab() && wxIsKindOf(winFocus, wxRadioButton ) )
453 winFocus = wxGetFirstButtonInGroup((wxRadioButton*)winFocus);
a8ff046b 454#endif // __WXMSW__
456bc6d9
VZ
455 // ok, we found the focus - now is it our child?
456 start_node = children.Find( winFocus );
457 }
456bc6d9
VZ
458
459 if ( !start_node && m_winLastFocused )
460 {
461 // window which has focus isn't our child, fall back to the one
462 // which had the focus the last time
463 start_node = children.Find( m_winLastFocused );
464 }
465
466 // if we still didn't find anything, we should start with the first one
467 if ( !start_node )
468 {
469 start_node = children.GetFirst();
470 }
471
472 // and the first child which we can try setting focus to is the next or
473 // the previous one
474 node = forward ? start_node->GetNext() : start_node->GetPrevious();
475 }
476
477 // we want to cycle over all elements passing by NULL
edc0a395 478 for ( ;; )
456bc6d9 479 {
edc0a395 480 // don't go into infinite loop
aa78d22e 481 if ( start_node && node && node == start_node )
edc0a395
VZ
482 break;
483
456bc6d9
VZ
484 // Have we come to the last or first item on the panel?
485 if ( !node )
486 {
e547f7a7
VZ
487 if ( !start_node )
488 {
489 // exit now as otherwise we'd loop forever
490 break;
491 }
492
456bc6d9
VZ
493 if ( !goingDown )
494 {
edc0a395 495 // Check if our (maybe grand) parent is another panel: if this
456bc6d9
VZ
496 // is the case, they will know what to do with this navigation
497 // key and so give them the chance to process it instead of
498 // looping inside this panel (normally, the focus will go to
499 // the next/previous item after this panel in the parent
500 // panel).
2a0777a8 501 wxWindow *focusedParent = m_winParent;
456bc6d9
VZ
502 while ( parent )
503 {
6e92c299
VZ
504 // We don't want to tab into a different dialog or frame or
505 // even an MDI child frame, so test for this explicitly
506 // (and in particular don't just use IsTopLevel() which
507 // would return false in the latter case).
508 if ( focusedParent->IsTopNavigationDomain() )
456bc6d9
VZ
509 break;
510
2a0777a8 511 event.SetCurrentFocus( focusedParent );
456bc6d9
VZ
512 if ( parent->GetEventHandler()->ProcessEvent( event ) )
513 return;
514
2a0777a8 515 focusedParent = parent;
456bc6d9
VZ
516
517 parent = parent->GetParent();
518 }
519 }
520 //else: as the focus came from our parent, we definitely don't want
521 // to send it back to it!
522
523 // no, we are not inside another panel so process this ourself
524 node = forward ? children.GetFirst() : children.GetLast();
525
526 continue;
527 }
528
529 wxWindow *child = node->GetData();
530
e49d331c
VZ
531 // don't TAB to another TLW
532 if ( child->IsTopLevel() )
533 {
534 node = forward ? node->GetNext() : node->GetPrevious();
535
536 continue;
537 }
538
a8ff046b 539#if defined(__WXMSW__) && wxUSE_RADIOBTN
3d3afaec 540 if ( event.IsFromTab() )
7ff1b620 541 {
3d3afaec 542 if ( wxIsKindOf(child, wxRadioButton) )
7ff1b620 543 {
3d3afaec
JS
544 // only radio buttons with either wxRB_GROUP or wxRB_SINGLE
545 // can be tabbed to
546 if ( child->HasFlag(wxRB_GROUP) )
7ff1b620 547 {
3d3afaec
JS
548 // need to tab into the active button within a group
549 wxRadioButton *rb = wxGetSelectedButtonInGroup((wxRadioButton*)child);
550 if ( rb )
551 child = rb;
552 }
553 else if ( !child->HasFlag(wxRB_SINGLE) )
554 {
555 node = forward ? node->GetNext() : node->GetPrevious();
556 continue;
7ff1b620
VZ
557 }
558 }
559 }
3d3afaec
JS
560 else if ( m_winLastFocused &&
561 wxIsKindOf(m_winLastFocused, wxRadioButton) &&
562 !m_winLastFocused->HasFlag(wxRB_SINGLE) )
7ff1b620 563 {
506f9e92 564 wxRadioButton * const
5c33522f 565 lastBtn = static_cast<wxRadioButton *>(m_winLastFocused);
506f9e92 566
3d3afaec
JS
567 // cursor keys don't navigate out of a radio button group so
568 // find the correct radio button to focus
569 if ( forward )
7ff1b620 570 {
506f9e92 571 child = wxGetNextButtonInGroup(lastBtn);
3d3afaec
JS
572 if ( !child )
573 {
574 // no next button in group, set it to the first button
506f9e92 575 child = wxGetFirstButtonInGroup(lastBtn);
3d3afaec
JS
576 }
577 }
578 else
579 {
506f9e92 580 child = wxGetPreviousButtonInGroup(lastBtn);
3d3afaec
JS
581 if ( !child )
582 {
583 // no previous button in group, set it to the last button
506f9e92 584 child = wxGetLastButtonInGroup(lastBtn);
3d3afaec
JS
585 }
586 }
587
588 if ( child == m_winLastFocused )
589 {
590 // must be a group consisting of only one button therefore
591 // no need to send a navigation event
592 event.Skip(false);
593 return;
7ff1b620
VZ
594 }
595 }
3d3afaec 596#endif // __WXMSW__
c932709d 597
21bf81db 598 if ( child->CanAcceptFocusFromKeyboard() )
456bc6d9
VZ
599 {
600 // if we're setting the focus to a child panel we should prevent it
601 // from giving it to the child which had the focus the last time
602 // and instead give it to the first/last child depending from which
603 // direction we're coming
604 event.SetEventObject(m_winParent);
944e8709 605
aef35d0e
VZ
606 // disable propagation for this call as otherwise the event might
607 // bounce back to us.
608 wxPropagationDisabler disableProp(event);
456bc6d9
VZ
609 if ( !child->GetEventHandler()->ProcessEvent(event) )
610 {
2b5f62a0
VZ
611 // set it first in case SetFocusFromKbd() results in focus
612 // change too
613 m_winLastFocused = child;
614
456bc6d9 615 // everything is simple: just give focus to it
5463c0a4 616 child->SetFocusFromKbd();
456bc6d9
VZ
617 }
618 //else: the child manages its focus itself
619
c9d59ee7 620 event.Skip( false );
456bc6d9
VZ
621
622 return;
623 }
624
625 node = forward ? node->GetNext() : node->GetPrevious();
626 }
627
628 // we cycled through all of our children and none of them wanted to accept
629 // focus
630 event.Skip();
631}
632
633void wxControlContainer::HandleOnWindowDestroy(wxWindowBase *child)
634{
635 if ( child == m_winLastFocused )
636 m_winLastFocused = NULL;
456bc6d9
VZ
637}
638
639// ----------------------------------------------------------------------------
640// focus handling
641// ----------------------------------------------------------------------------
642
456bc6d9
VZ
643void wxControlContainer::HandleOnFocus(wxFocusEvent& event)
644{
9a83f860 645 wxLogTrace(TRACE_FOCUS, wxT("OnFocus on wxPanel 0x%p, name: %s"),
9f542367 646 m_winParent->GetHandle(),
456bc6d9
VZ
647 m_winParent->GetName().c_str() );
648
2b5f62a0 649 DoSetFocus();
456bc6d9
VZ
650
651 event.Skip();
652}
653
c7bfb76a
JS
654
655#else
656 // wxHAS_NATIVE_TAB_TRAVERSAL
657
456bc6d9
VZ
658bool wxControlContainer::SetFocusToChild()
659{
c7bfb76a 660 return wxSetFocusToChild(m_winParent, NULL);
456bc6d9
VZ
661}
662
c7bfb76a
JS
663
664#endif // !wxHAS_NATIVE_TAB_TRAVERSAL
665
456bc6d9
VZ
666// ----------------------------------------------------------------------------
667// SetFocusToChild(): this function is used by wxPanel but also by wxFrame in
668// wxMSW, this is why it is outside of wxControlContainer class
669// ----------------------------------------------------------------------------
670
671bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused)
672{
9a83f860 673 wxCHECK_MSG( win, false, wxT("wxSetFocusToChild(): invalid window") );
c7bfb76a 674 // wxCHECK_MSG( childLastFocused, false,
9a83f860 675 // wxT("wxSetFocusToChild(): NULL child poonter") );
456bc6d9 676
c7bfb76a 677 if ( childLastFocused && *childLastFocused )
456bc6d9 678 {
c25b5d1f
VZ
679 // It might happen that the window got reparented
680 if ( (*childLastFocused)->GetParent() == win )
456bc6d9 681 {
6ca243fc
VZ
682 // And it also could have become hidden in the meanwhile
683 // We want to focus on the deepest widget visible
684 wxWindow *deepestVisibleWindow = NULL;
685
686 while ( *childLastFocused )
26647ae4 687 {
6ca243fc
VZ
688 if ( (*childLastFocused)->IsShown() )
689 {
690 if ( !deepestVisibleWindow )
691 deepestVisibleWindow = *childLastFocused;
692 }
693 else
694 deepestVisibleWindow = NULL;
695
26647ae4 696 *childLastFocused = (*childLastFocused)->GetParent();
26647ae4 697 }
456bc6d9 698
6ca243fc 699 if ( deepestVisibleWindow )
26647ae4 700 {
6ca243fc
VZ
701 *childLastFocused = deepestVisibleWindow;
702
26647ae4
VZ
703 wxLogTrace(TRACE_FOCUS,
704 wxT("SetFocusToChild() => last child (0x%p)."),
705 (*childLastFocused)->GetHandle());
706
707 // not SetFocusFromKbd(): we're restoring focus back to the old
708 // window and not setting it as the result of a kbd action
709 (*childLastFocused)->SetFocus();
710 return true;
711 }
456bc6d9
VZ
712 }
713 else
714 {
715 // it doesn't count as such any more
d3b9f782 716 *childLastFocused = NULL;
456bc6d9
VZ
717 }
718 }
719
720 // set the focus to the first child who wants it
222ed1d6 721 wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
456bc6d9
VZ
722 while ( node )
723 {
724 wxWindow *child = node->GetData();
afd7bf26 725 node = node->GetNext();
456bc6d9 726
049908c5
VS
727 // skip special windows:
728 if ( !win->IsClientAreaChild(child) )
afd7bf26 729 continue;
049908c5 730
de160b06 731 if ( child->CanAcceptFocusFromKeyboard() && !child->IsTopLevel() )
456bc6d9 732 {
a8ff046b 733#if defined(__WXMSW__) && wxUSE_RADIOBTN
b49f58fe 734 // If a radiobutton is the first focusable child, search for the
7ff1b620
VZ
735 // selected radiobutton in the same group
736 wxRadioButton* btn = wxDynamicCast(child, wxRadioButton);
737 if (btn)
738 {
739 wxRadioButton* selected = wxGetSelectedButtonInGroup(btn);
740 if (selected)
741 child = selected;
742 }
a8ff046b 743#endif // __WXMSW__
7ff1b620 744
9f542367 745 wxLogTrace(TRACE_FOCUS,
9a83f860 746 wxT("SetFocusToChild() => first child (0x%p)."),
9f542367 747 child->GetHandle());
456bc6d9 748
c7bfb76a
JS
749 if (childLastFocused)
750 *childLastFocused = child;
5463c0a4 751 child->SetFocusFromKbd();
c9d59ee7 752 return true;
456bc6d9 753 }
456bc6d9
VZ
754 }
755
c9d59ee7 756 return false;
456bc6d9 757}
de160b06 758