]>
git.saurik.com Git - wxWidgets.git/blob - src/common/containr.cpp
   1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/common/containr.cpp 
   3 // Purpose:     implementation of wxControlContainer 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 
   9 // License:     wxWindows license 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  21     #pragma implementation "containr.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  34     #include "wx/window.h" 
  37 #include "wx/containr.h" 
  39 // ============================================================================ 
  41 // ============================================================================ 
  43 wxControlContainer::wxControlContainer(wxWindow 
*winParent
) 
  45     m_winParent 
= winParent
; 
  51 void wxControlContainer::SetLastFocus(wxWindow 
*win
) 
  53     // find the last _immediate_ child which got focus 
  54     while ( win 
&& win 
!= m_winParent 
) 
  56         win 
= win
->GetParent(); 
  59     wxASSERT_MSG( win
, _T("attempt to set last focus to not a child?") ); 
  61     m_winLastFocused 
= win
; 
  64 // ---------------------------------------------------------------------------- 
  65 // Keyboard handling - this is the place where the TAB traversal logic is 
  66 // implemented. As this code is common to all ports, this ensures consistent 
  67 // behaviour even if we don't specify how exactly the wxNavigationKeyEvent are 
  68 // generated and this is done in platform specific code which also ensures that 
  69 // we can follow the given platform standards. 
  70 // ---------------------------------------------------------------------------- 
  72 void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent
& event 
) 
  74     wxWindow 
*parent 
= m_winParent
->GetParent(); 
  76     // the event is propagated downwards if the event emitter was our parent 
  77     bool goingDown 
= event
.GetEventObject() == parent
; 
  79     const wxWindowList
& children 
= m_winParent
->GetChildren(); 
  81     // there is not much to do if we don't have children and we're not 
  82     // interested in "notebook page change" events here 
  83     if ( !children
.GetCount() || event
.IsWindowChange() ) 
  85         // let the parent process it unless it already comes from our parent 
  86         // of we don't have any 
  88              !parent 
|| !parent
->GetEventHandler()->ProcessEvent(event
) ) 
  96     // where are we going? 
  97     bool forward 
= event
.GetDirection(); 
  99     // the node of the children list from which we should start looking for the 
 100     // next acceptable child 
 101     wxWindowList::Node 
*node
, *start_node
; 
 103     // we should start from the first/last control and not from the one which 
 104     // had focus the last time if we're propagating the event downwards because 
 105     // for our parent we look like a single control 
 108         // just to be sure it's not used (normally this is not necessary, but 
 109         // doesn't hurt neither) 
 110         m_winLastFocused 
= (wxWindow 
*)NULL
; 
 112         // start from first or last depending on where we're going 
 113         node 
= forward 
? children
.GetFirst() : children
.GetLast(); 
 115         // we want to cycle over all nodes 
 116         start_node 
= (wxWindowList::Node 
*)NULL
; 
 120         // try to find the child which has the focus currently 
 122         // the event emitter might have done this for us 
 123         wxWindow 
*winFocus 
= event
.GetCurrentFocus(); 
 125         // but if not, we might know where the focus was ourselves 
 127             winFocus 
= m_winLastFocused
; 
 129         // if still no luck, do it the hard way 
 131             winFocus 
= wxWindow::FindFocus(); 
 135             // ok, we found the focus - now is it our child? 
 136             start_node 
= children
.Find( winFocus 
); 
 140             start_node 
= (wxWindowList::Node 
*)NULL
; 
 143         if ( !start_node 
&& m_winLastFocused 
) 
 145             // window which has focus isn't our child, fall back to the one 
 146             // which had the focus the last time 
 147             start_node 
= children
.Find( m_winLastFocused 
); 
 150         // if we still didn't find anything, we should start with the first one 
 153             start_node 
= children
.GetFirst(); 
 156         // and the first child which we can try setting focus to is the next or 
 158         node 
= forward 
? start_node
->GetNext() : start_node
->GetPrevious(); 
 161     // we want to cycle over all elements passing by NULL 
 162     while ( node 
!= start_node 
) 
 164         // Have we come to the last or first item on the panel? 
 169                 // Check if our (may be grand) parent is another panel: if this 
 170                 // is the case, they will know what to do with this navigation 
 171                 // key and so give them the chance to process it instead of 
 172                 // looping inside this panel (normally, the focus will go to 
 173                 // the next/previous item after this panel in the parent 
 175                 wxWindow 
*focussed_child_of_parent 
= m_winParent
; 
 178                     // we don't want to tab into a different dialog or frame 
 179                     if ( focussed_child_of_parent
->IsTopLevel() ) 
 182                     event
.SetCurrentFocus( focussed_child_of_parent 
); 
 183                     if ( parent
->GetEventHandler()->ProcessEvent( event 
) ) 
 186                     focussed_child_of_parent 
= parent
; 
 188                     parent 
= parent
->GetParent(); 
 191             //else: as the focus came from our parent, we definitely don't want 
 192             //      to send it back to it! 
 194             // no, we are not inside another panel so process this ourself 
 195             node 
= forward 
? children
.GetFirst() : children
.GetLast(); 
 200         wxWindow 
*child 
= node
->GetData(); 
 202         if ( child
->AcceptsFocusFromKeyboard() ) 
 204             // if we're setting the focus to a child panel we should prevent it 
 205             // from giving it to the child which had the focus the last time 
 206             // and instead give it to the first/last child depending from which 
 207             // direction we're coming 
 208             event
.SetEventObject(m_winParent
); 
 209             if ( !child
->GetEventHandler()->ProcessEvent(event
) ) 
 211                 // everything is simple: just give focus to it 
 214                 m_winLastFocused 
= child
; 
 216             //else: the child manages its focus itself 
 223         node 
= forward 
? node
->GetNext() : node
->GetPrevious(); 
 226     // we cycled through all of our children and none of them wanted to accept 
 231 void wxControlContainer::HandleOnWindowDestroy(wxWindowBase 
*child
) 
 233     if ( child 
== m_winLastFocused 
) 
 234         m_winLastFocused 
= NULL
; 
 236     if ( child 
== m_winDefault 
) 
 240 // ---------------------------------------------------------------------------- 
 242 // ---------------------------------------------------------------------------- 
 244 bool wxControlContainer::DoSetFocus() 
 246     wxLogTrace(_T("focus"), _T("SetFocus on wxPanel 0x%08x."), 
 247                m_winParent
->GetHandle()); 
 249     // If the panel gets the focus *by way of getting it set directly* 
 250     // we move the focus to the first window that can get it. 
 252     // VZ: no, we set the focus to the last window too. I don't understand why 
 253     //     should we make this distinction: if an app wants to set focus to 
 254     //     some precise control, it may always do it directly, but if we don't 
 255     //     use m_winLastFocused here, the focus won't be set correctly after a 
 256     //     notebook page change nor after frame activation under MSW (it calls 
 259     // RR: yes, when I the tab key to navigate in a panel with some controls and 
 260     //     a notebook and the focus jumps to the notebook (typically coming from 
 261     //     a button at the top) the notebook should focus the first child in the 
 262     //     current notebook page, not the last one which would otherwise get the 
 263     //     focus if you used the tab key to navigate from the current notebook 
 264     //     page to button at the bottom. See every page in the controls sample. 
 266     // VZ: ok, but this still doesn't (at least I don't see how it can) take 
 267     //     care of first/last child problem: i.e. if Shift-TAB is pressed in a 
 268     //     situation like above, the focus should be given to the last child, 
 269     //     not the first one (and not to the last focused one neither) - I 
 270     //     think my addition to OnNavigationKey() above takes care of it. 
 271     //     Keeping #ifdef __WXGTK__ for now, but please try removing it and see 
 274     // RR: Removed for now. Let's see what happens.. 
 276     return SetFocusToChild(); 
 279 void wxControlContainer::HandleOnFocus(wxFocusEvent
& event
) 
 281     wxLogTrace(_T("focus"), _T("OnFocus on wxPanel 0x%08x, name: %s"), 
 282                m_winParent
->GetHandle(), 
 283                m_winParent
->GetName().c_str() ); 
 285     // If we panel got the focus *by way of getting clicked on* 
 286     // we move the focus to either the last window that had the 
 287     // focus or the first one that can get it. 
 288     (void)SetFocusToChild(); 
 293 bool wxControlContainer::SetFocusToChild() 
 295     return wxSetFocusToChild(m_winParent
, &m_winLastFocused
); 
 298 // ---------------------------------------------------------------------------- 
 299 // SetFocusToChild(): this function is used by wxPanel but also by wxFrame in 
 300 // wxMSW, this is why it is outside of wxControlContainer class 
 301 // ---------------------------------------------------------------------------- 
 303 bool wxSetFocusToChild(wxWindow 
*win
, wxWindow 
**childLastFocused
) 
 305     wxCHECK_MSG( win
, FALSE
, _T("wxSetFocusToChild(): invalid window") ); 
 307     if ( *childLastFocused 
) 
 309         // It might happen that the window got reparented or no longer accepts 
 311         if ( (*childLastFocused
)->GetParent() == win 
&& 
 312              (*childLastFocused
)->AcceptsFocusFromKeyboard() ) 
 314             wxLogTrace(_T("focus"), 
 315                        _T("SetFocusToChild() => last child (0x%08x)."), 
 316                        (*childLastFocused
)->GetHandle()); 
 318             (*childLastFocused
)->SetFocus(); 
 323             // it doesn't count as such any more 
 324             *childLastFocused 
= (wxWindow 
*)NULL
; 
 328     // set the focus to the first child who wants it 
 329     wxWindowList::Node 
*node 
= win
->GetChildren().GetFirst(); 
 332         wxWindow 
*child 
= node
->GetData(); 
 334         if ( child
->AcceptsFocusFromKeyboard() && !child
->IsTopLevel() ) 
 336             wxLogTrace(_T("focus"), 
 337                        _T("SetFocusToChild() => first child (0x%08x)."), 
 340             *childLastFocused 
= child
;  // should be redundant, but it is not 
 345         node 
= node
->GetNext();