home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / common / containr.cpp < prev    next >
C/C++ Source or Header  |  2002-07-19  |  15KB  |  411 lines

  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: containr.cpp,v 1.14 2002/07/16 14:23:24 VZ Exp $
  8. // Copyright:   (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
  9. // License:     wxWindows license
  10. ///////////////////////////////////////////////////////////////////////////////
  11.  
  12. // ============================================================================
  13. // declarations
  14. // ============================================================================
  15.  
  16. // ----------------------------------------------------------------------------
  17. // headers
  18. // ----------------------------------------------------------------------------
  19.  
  20. #ifdef __GNUG__
  21.     #pragma implementation "containr.h"
  22. #endif
  23.  
  24. // For compilers that support precompilation, includes "wx.h".
  25. #include "wx/wxprec.h"
  26.  
  27. #ifdef __BORLANDC__
  28.     #pragma hdrstop
  29. #endif
  30.  
  31. #ifndef WX_PRECOMP
  32.     #include "wx/log.h"
  33.     #include "wx/event.h"
  34.     #include "wx/window.h"
  35. #endif //WX_PRECOMP
  36.  
  37. #include "wx/containr.h"
  38.  
  39. // ============================================================================
  40. // implementation
  41. // ============================================================================
  42.  
  43. wxControlContainer::wxControlContainer(wxWindow *winParent)
  44. {
  45.     m_winParent = winParent;
  46.  
  47.     m_winLastFocused =
  48.     m_winTmpDefault =
  49.     m_winDefault = NULL;
  50. }
  51.  
  52. void wxControlContainer::SetLastFocus(wxWindow *win)
  53. {
  54.     // the panel itself should never get the focus at all but if it does happen
  55.     // temporarily (as it seems to do under wxGTK), at the very least don't
  56.     // forget our previous m_winLastFocused
  57.     if ( win != m_winParent )
  58.     {
  59.         // if we're setting the focus
  60.         if ( win )
  61.         {
  62.             // find the last _immediate_ child which got focus
  63.             wxWindow *winParent = win;
  64.             while ( winParent != m_winParent )
  65.             {
  66.                 win = winParent;
  67.                 winParent = win->GetParent();
  68.  
  69.                 // Yes, this can happen, though in a totally pathological case.
  70.                 // like when detaching a menubar from a frame with a child
  71.                 // which has pushed itself as an event handler for the menubar.
  72.                 // (under wxGTK)
  73.  
  74.                 wxASSERT_MSG( winParent,
  75.                               _T("Setting last focus for a window that is not our child?") );
  76.             }
  77.         }
  78.  
  79.         m_winLastFocused = win;
  80.  
  81.         if ( win )
  82.         {
  83.             wxLogTrace(_T("focus"), _T("Set last focus to %s(%s)"),
  84.                        win->GetClassInfo()->GetClassName(),
  85.                        win->GetLabel().c_str());
  86.         }
  87.         else
  88.         {
  89.             wxLogTrace(_T("focus"), _T("No more last focus"));
  90.         }
  91.     }
  92.  
  93.     // propagate the last focus upwards so that our parent can set focus back
  94.     // to us if it loses it now and regains later
  95.     wxWindow *parent = m_winParent->GetParent();
  96.     if ( parent )
  97.     {
  98.         wxChildFocusEvent eventFocus(m_winParent);
  99.         parent->GetEventHandler()->ProcessEvent(eventFocus);
  100.     }
  101. }
  102.  
  103. // ----------------------------------------------------------------------------
  104. // Keyboard handling - this is the place where the TAB traversal logic is
  105. // implemented. As this code is common to all ports, this ensures consistent
  106. // behaviour even if we don't specify how exactly the wxNavigationKeyEvent are
  107. // generated and this is done in platform specific code which also ensures that
  108. // we can follow the given platform standards.
  109. // ----------------------------------------------------------------------------
  110.  
  111. void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event )
  112. {
  113.     wxWindow *parent = m_winParent->GetParent();
  114.  
  115.     // the event is propagated downwards if the event emitter was our parent
  116.     bool goingDown = event.GetEventObject() == parent;
  117.  
  118.     const wxWindowList& children = m_winParent->GetChildren();
  119.  
  120.     // there is not much to do if we don't have children and we're not
  121.     // interested in "notebook page change" events here
  122.     if ( !children.GetCount() || event.IsWindowChange() )
  123.     {
  124.         // let the parent process it unless it already comes from our parent
  125.         // of we don't have any
  126.         if ( goingDown ||
  127.              !parent || !parent->GetEventHandler()->ProcessEvent(event) )
  128.         {
  129.             event.Skip();
  130.         }
  131.  
  132.         return;
  133.     }
  134.  
  135.     // where are we going?
  136.     bool forward = event.GetDirection();
  137.  
  138.     // the node of the children list from which we should start looking for the
  139.     // next acceptable child
  140.     wxWindowList::Node *node, *start_node;
  141.  
  142.     // we should start from the first/last control and not from the one which
  143.     // had focus the last time if we're propagating the event downwards because
  144.     // for our parent we look like a single control
  145.     if ( goingDown )
  146.     {
  147.         // just to be sure it's not used (normally this is not necessary, but
  148.         // doesn't hurt neither)
  149.         m_winLastFocused = (wxWindow *)NULL;
  150.  
  151.         // start from first or last depending on where we're going
  152.         node = forward ? children.GetFirst() : children.GetLast();
  153.  
  154.         // we want to cycle over all nodes
  155.         start_node = (wxWindowList::Node *)NULL;
  156.     }
  157.     else
  158.     {
  159.         // try to find the child which has the focus currently
  160.  
  161.         // the event emitter might have done this for us
  162.         wxWindow *winFocus = event.GetCurrentFocus();
  163.  
  164.         // but if not, we might know where the focus was ourselves
  165.         if (!winFocus)
  166.             winFocus = m_winLastFocused;
  167.  
  168.         // if still no luck, do it the hard way
  169.         if (!winFocus)
  170.             winFocus = wxWindow::FindFocus();
  171.  
  172.         if ( winFocus )
  173.         {
  174.             // ok, we found the focus - now is it our child?
  175.             start_node = children.Find( winFocus );
  176.         }
  177.         else
  178.         {
  179.             start_node = (wxWindowList::Node *)NULL;
  180.         }
  181.  
  182.         if ( !start_node && m_winLastFocused )
  183.         {
  184.             // window which has focus isn't our child, fall back to the one
  185.             // which had the focus the last time
  186.             start_node = children.Find( m_winLastFocused );
  187.         }
  188.  
  189.         // if we still didn't find anything, we should start with the first one
  190.         if ( !start_node )
  191.         {
  192.             start_node = children.GetFirst();
  193.         }
  194.  
  195.         // and the first child which we can try setting focus to is the next or
  196.         // the previous one
  197.         node = forward ? start_node->GetNext() : start_node->GetPrevious();
  198.     }
  199.  
  200.     // we want to cycle over all elements passing by NULL
  201.     while ( node != start_node )
  202.     {
  203.         // Have we come to the last or first item on the panel?
  204.         if ( !node )
  205.         {
  206.             if ( !goingDown )
  207.             {
  208.                 // Check if our (may be grand) parent is another panel: if this
  209.                 // is the case, they will know what to do with this navigation
  210.                 // key and so give them the chance to process it instead of
  211.                 // looping inside this panel (normally, the focus will go to
  212.                 // the next/previous item after this panel in the parent
  213.                 // panel).
  214.                 wxWindow *focussed_child_of_parent = m_winParent;
  215.                 while ( parent )
  216.                 {
  217.                     // we don't want to tab into a different dialog or frame
  218.                     if ( focussed_child_of_parent->IsTopLevel() )
  219.                         break;
  220.  
  221.                     event.SetCurrentFocus( focussed_child_of_parent );
  222.                     if ( parent->GetEventHandler()->ProcessEvent( event ) )
  223.                         return;
  224.  
  225.                     focussed_child_of_parent = parent;
  226.  
  227.                     parent = parent->GetParent();
  228.                 }
  229.             }
  230.             //else: as the focus came from our parent, we definitely don't want
  231.             //      to send it back to it!
  232.  
  233.             // no, we are not inside another panel so process this ourself
  234.             node = forward ? children.GetFirst() : children.GetLast();
  235.  
  236.             continue;
  237.         }
  238.  
  239.         wxWindow *child = node->GetData();
  240.  
  241.         if ( child->AcceptsFocusFromKeyboard() )
  242.         {
  243.             // if we're setting the focus to a child panel we should prevent it
  244.             // from giving it to the child which had the focus the last time
  245.             // and instead give it to the first/last child depending from which
  246.             // direction we're coming
  247.             event.SetEventObject(m_winParent);
  248.             if ( !child->GetEventHandler()->ProcessEvent(event) )
  249.             {
  250.                 // everything is simple: just give focus to it
  251.                 child->SetFocusFromKbd();
  252.  
  253.                 m_winLastFocused = child;
  254.             }
  255.             //else: the child manages its focus itself
  256.  
  257.             event.Skip( FALSE );
  258.  
  259.             return;
  260.         }
  261.  
  262.         node = forward ? node->GetNext() : node->GetPrevious();
  263.     }
  264.  
  265.     // we cycled through all of our children and none of them wanted to accept
  266.     // focus
  267.     event.Skip();
  268. }
  269.  
  270. void wxControlContainer::HandleOnWindowDestroy(wxWindowBase *child)
  271. {
  272.     if ( child == m_winLastFocused )
  273.         m_winLastFocused = NULL;
  274.  
  275.     if ( child == m_winDefault )
  276.         m_winDefault = NULL;
  277.  
  278.     if ( child == m_winTmpDefault )
  279.         m_winTmpDefault = NULL;
  280. }
  281.  
  282. // ----------------------------------------------------------------------------
  283. // focus handling
  284. // ----------------------------------------------------------------------------
  285.  
  286. bool wxControlContainer::DoSetFocus()
  287. {
  288.     wxLogTrace(_T("focus"), _T("SetFocus on wxPanel 0x%08lx."),
  289.                (unsigned long)m_winParent->GetHandle());
  290.  
  291.     // If the panel gets the focus *by way of getting it set directly*
  292.     // we move the focus to the first window that can get it.
  293.  
  294.     // VZ: no, we set the focus to the last window too. I don't understand why
  295.     //     should we make this distinction: if an app wants to set focus to
  296.     //     some precise control, it may always do it directly, but if we don't
  297.     //     use m_winLastFocused here, the focus won't be set correctly after a
  298.     //     notebook page change nor after frame activation under MSW (it calls
  299.     //     SetFocus too)
  300.     //
  301.     // RR: yes, when I the tab key to navigate in a panel with some controls and
  302.     //     a notebook and the focus jumps to the notebook (typically coming from
  303.     //     a button at the top) the notebook should focus the first child in the
  304.     //     current notebook page, not the last one which would otherwise get the
  305.     //     focus if you used the tab key to navigate from the current notebook
  306.     //     page to button at the bottom. See every page in the controls sample.
  307.     //
  308.     // VZ: ok, but this still doesn't (at least I don't see how it can) take
  309.     //     care of first/last child problem: i.e. if Shift-TAB is pressed in a
  310.     //     situation like above, the focus should be given to the last child,
  311.     //     not the first one (and not to the last focused one neither) - I
  312.     //     think my addition to OnNavigationKey() above takes care of it.
  313.     //     Keeping #ifdef __WXGTK__ for now, but please try removing it and see
  314.     //     what happens.
  315.     //
  316.     // RR: Removed for now. Let's see what happens..
  317.  
  318.     // if our child already has focus, don't take it away from it
  319.     wxWindow *win = wxWindow::FindFocus();
  320.     while ( win )
  321.     {
  322.         if ( win == m_winParent )
  323.             return TRUE;
  324.  
  325.         if ( win->IsTopLevel() )
  326.         {
  327.             // don't look beyond the first top level parent - useless and
  328.             // unnecessary
  329.             break;
  330.         }
  331.  
  332.         win = win->GetParent();
  333.     }
  334.  
  335.     return SetFocusToChild();
  336. }
  337.  
  338. void wxControlContainer::HandleOnFocus(wxFocusEvent& event)
  339. {
  340.     wxLogTrace(_T("focus"), _T("OnFocus on wxPanel 0x%08lx, name: %s"),
  341.                (unsigned long)m_winParent->GetHandle(),
  342.                m_winParent->GetName().c_str() );
  343.  
  344.     // If we panel got the focus *by way of getting clicked on*
  345.     // we move the focus to either the last window that had the
  346.     // focus or the first one that can get it.
  347.     (void)SetFocusToChild();
  348.  
  349.     event.Skip();
  350. }
  351.  
  352. bool wxControlContainer::SetFocusToChild()
  353. {
  354.     return wxSetFocusToChild(m_winParent, &m_winLastFocused);
  355. }
  356.  
  357. // ----------------------------------------------------------------------------
  358. // SetFocusToChild(): this function is used by wxPanel but also by wxFrame in
  359. // wxMSW, this is why it is outside of wxControlContainer class
  360. // ----------------------------------------------------------------------------
  361.  
  362. bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused)
  363. {
  364.     wxCHECK_MSG( win, FALSE, _T("wxSetFocusToChild(): invalid window") );
  365.     wxCHECK_MSG( childLastFocused, FALSE,
  366.                  _T("wxSetFocusToChild(): NULL child poonter") );
  367.  
  368.     if ( *childLastFocused )
  369.     {
  370.         // It might happen that the window got reparented
  371.         if ( (*childLastFocused)->GetParent() == win )
  372.         {
  373.             wxLogTrace(_T("focus"),
  374.                        _T("SetFocusToChild() => last child (0x%08lx)."),
  375.                        (unsigned long)(*childLastFocused)->GetHandle());
  376.  
  377.             // not SetFocusFromKbd(): we're restoring focus back to the old
  378.             // window and not setting it as the result of a kbd action
  379.             (*childLastFocused)->SetFocus();
  380.             return TRUE;
  381.         }
  382.         else
  383.         {
  384.             // it doesn't count as such any more
  385.             *childLastFocused = (wxWindow *)NULL;
  386.         }
  387.     }
  388.  
  389.     // set the focus to the first child who wants it
  390.     wxWindowList::Node *node = win->GetChildren().GetFirst();
  391.     while ( node )
  392.     {
  393.         wxWindow *child = node->GetData();
  394.  
  395.         if ( child->AcceptsFocusFromKeyboard() && !child->IsTopLevel() )
  396.         {
  397.             wxLogTrace(_T("focus"),
  398.                        _T("SetFocusToChild() => first child (0x%08lx)."),
  399.                        (unsigned long)child->GetHandle());
  400.  
  401.             *childLastFocused = child;  // should be redundant, but it is not
  402.             child->SetFocusFromKbd();
  403.             return TRUE;
  404.         }
  405.  
  406.         node = node->GetNext();
  407.     }
  408.  
  409.     return FALSE;
  410. }
  411.