- bFound = WIN(node)->AcceptsFocus();
- }
-#if 0 // to restore when it will really work (now it's triggered all the time)
- else {
- // just to be sure it's the right one
- wxASSERT( WIN(node)->AcceptsFocus() );
- }
-#endif // 0
-
- // find the next child which accepts focus
- bool bParentWantsIt = TRUE;
- while ( !bFound ) {
- node = bForward ? node->Next() : node->Previous();
- if ( node == NULL ) {
- if ( !bParentWantsIt ) {
- // we've already been here which means that we've done a whole
- // cycle without success - get out from the infinite loop
- return FALSE;
- }
-
- // ask parent if he doesn't want to advance focus to the next panel
- if ( GetParent() != NULL ) {
- wxNavigationKeyEvent event;
- event.SetDirection(bForward);
- event.SetWindowChange(FALSE);
- event.SetCurrentFocus(this);
-
- if ( GetParent()->ProcessEvent(event) )
- return TRUE;
- }
-
- // a sentinel to avoid infinite loops
- bParentWantsIt = FALSE;
-
- // wrap around
- node = bForward ? children->First() : children->Last();
+ // where are we going?
+ bool forward = event.GetDirection();
+
+ // the node of the children list from which we should start looking for the
+ // next acceptable child
+ wxWindowList::Node *node, *start_node;
+
+ // the event is propagated downwards if the event emitter was our parent
+ bool goingDown = event.GetEventObject() == GetParent();
+
+ // we should start from the first/last control and not from the one which
+ // had focus the last time if we're propagating the event downwards because
+ // for our parent we look like a single control
+ if ( goingDown )
+ {
+ // just to be sure it's not used (normally this is not necessary, but
+ // doesn't hurt neither)
+ m_winLastFocused = (wxWindow *)NULL;
+
+ // start from first or last depending on where we're going
+ node = forward ? children.GetFirst() : children.GetLast();
+
+ // we want to cycle over all nodes
+ start_node = (wxWindowList::Node *)NULL;
+ }
+ else
+ {
+ // try to find the child which has the focus currently
+
+ // the event emitter might have done this for us
+ wxWindow *winFocus = event.GetCurrentFocus();
+
+ // but if not, we might know where the focus was ourselves
+ if (!winFocus)
+ winFocus = m_winLastFocused;
+
+ // if still no luck, do it the hard way
+ if (!winFocus)
+ winFocus = wxWindow::FindFocus();
+
+ if ( winFocus )
+ {
+ // ok, we found the focus - now is it our child?
+ start_node = children.Find( winFocus );
+ }
+ else
+ {
+ start_node = (wxWindowList::Node *)NULL;
+ }
+
+ if ( !start_node && m_winLastFocused )
+ {
+ // window which has focus isn't our child, fall back to the one
+ // which had the focus the last time
+ start_node = children.Find( m_winLastFocused );
+ }
+
+ // if we still didn't find anything, we should start with the first one
+ if ( !start_node )
+ {
+ start_node = children.GetFirst();
+ }
+
+ // and the first child which we can try setting focus to is the next or
+ // the previous one
+ node = forward ? start_node->GetNext() : start_node->GetPrevious();
+ }
+
+ // we want to cycle over all elements passing by NULL
+ while ( node != start_node )
+ {
+ // Have we come to the last or first item on the panel?
+ if ( !node )
+ {
+ if ( !goingDown )
+ {
+ // Check if our (may be grand) parent is another panel: if this
+ // is the case, they will know what to do with this navigation
+ // key and so give them the chance to process it instead of
+ // looping inside this panel (normally, the focus will go to
+ // the next/previous item after this panel in the parent
+ // panel).
+ wxWindow *focussed_child_of_parent = this;
+ for ( wxWindow *parent = GetParent();
+ parent;
+ parent = parent->GetParent() )
+ {
+ // we don't want to tab into a different dialog or frame
+ if ( focussed_child_of_parent->IsTopLevel() )
+ break;
+
+ event.SetCurrentFocus( focussed_child_of_parent );
+ if (parent->GetEventHandler()->ProcessEvent( event ))
+ return;
+
+ focussed_child_of_parent = parent;
+ }
+ }
+ //else: as the focus came from our parent, we definitely don't want
+ // to send it back to it!
+
+ // no, we are not inside another panel so process this ourself
+ node = forward ? children.GetFirst() : children.GetLast();
+
+ continue;
+ }
+
+ wxWindow *child = node->GetData();
+
+ if ( child->AcceptsFocus() )
+ {
+ m_winLastFocused = child; // should be redundant, but it is not
+
+ // if we're setting the focus to a child panel we should prevent it
+ // from giving it to the child which had the focus the last time
+ // and instead give it to the first/last child depending from which
+ // direction we're coming
+ wxPanel *subpanel = wxDynamicCast(child, wxPanel);
+ if ( subpanel )
+ {
+ // trick the panel into thinking that it got the navigation
+ // event - instead of duplicating all the code here
+ //
+ // make sure that we do trick it by setting all the parameters
+ // correctly (consistently with the code in this very function
+ // above) and that it starts from the very beginning/end by
+ // using SetLastFocus(NULL)
+ subpanel->SetLastFocus((wxWindow *)NULL);
+ }
+
+ event.SetEventObject(this);
+ if ( !child->GetEventHandler()->ProcessEvent(event) )
+ {
+ // everything is simple: just give focus to it
+ child->SetFocus();
+ }
+ //else: the child manages its focus itself
+
+ event.Skip( FALSE );
+ return;
+ }
+
+ node = forward ? node->GetNext() : node->GetPrevious();