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