moved knd handling logic from wxPanel to wxControlContainer (sorry for

the dull name Julian ;-)


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@11289 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2001-08-06 00:49:59 +00:00
parent ec4f95c40f
commit 456bc6d9b8
12 changed files with 592 additions and 421 deletions

View File

@@ -110,6 +110,7 @@ cmdproc.cpp Common
cmndata.cpp Common
clipcmn.cpp Common
config.cpp Common Base
containr.cpp Common
cshelp.cpp Common
ctrlcmn.cpp Common
ctrlsub.cpp Common
@@ -616,6 +617,7 @@ colour.h WXH
combobox.h WXH
confbase.h WXH Base
config.h WXH Base
containr.h WXH
control.h WXH
ctrlsub.h WXH
cursor.h WXH

135
include/wx/containr.h Normal file
View File

@@ -0,0 +1,135 @@
///////////////////////////////////////////////////////////////////////////////
// Name: wx/containr.h
// Purpose: wxControlContainer class declration: a "mix-in" class which
// implements the TAB navigation between the controls
// Author: Vadim Zeitlin
// Modified by:
// Created: 06.08.01
// RCS-ID: $Id$
// Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#ifndef _WX_CONTAINR_H_
#define _WX_CONTAINR_H_
#ifdef __GNUG__
#pragma implementation "containr.h"
#endif
class WXDLLEXPORT wxFocusEvent;
class WXDLLEXPORT wxNavigationKeyEvent;
class WXDLLEXPORT wxWindow;
/*
Implementation note: wxControlContainer is not a real mix-in but rather
a class meant to be agregated with (and not inherited from). Although
logically it should be a mix-in, doing it like this has no advantage from
the point of view of the existing code but does have some problems (we'd
need to play tricks with event handlers which may be difficult to do
safely). The price we pay for this simplicity is the ugly macros below.
*/
// ----------------------------------------------------------------------------
// wxControlContainer
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxControlContainer
{
public:
// ctors and such
wxControlContainer(wxWindow *winParent);
wxWindow *GetDefaultItem() const { return m_winDefault; }
wxWindow *SetDefaultItem(wxWindow *win)
{ wxWindow *winOld = m_winDefault; m_winDefault = win; return winOld; }
void SetLastFocus(wxWindow *win);
// the methods to be called from the window event handlers
void HandleOnNavigationKey(wxNavigationKeyEvent& event);
void HandleOnFocus(wxFocusEvent& event);
void HandleOnWindowDestroy(wxWindowBase *child);
// should be called from SetFocus()
void DoSetFocus();
protected:
// set the focus to the child which had it the last time
bool SetFocusToChild();
// the parent window we manage the children for
wxWindow *m_winParent;
// the child which had the focus last time this panel was activated
wxWindow *m_winLastFocused;
// a default window (e.g. a button) or NULL
wxWindow *m_winDefault;
};
// this function is for wxWindows internal use only
extern bool wxSetFocusToChild(wxWindow *win, wxWindow **child);
// ----------------------------------------------------------------------------
// macros which may be used by the classes wishing to implement TAB navigation
// among their children
// ----------------------------------------------------------------------------
// declare the methods to be forwarded
#define WX_DECLARE_CONTROL_CONTAINER() \
void OnNavigationKey(wxNavigationKeyEvent& event); \
void OnFocus(wxFocusEvent& event); \
virtual void OnChildFocus(wxChildFocusEvent& event); \
virtual void SetFocus(); \
virtual void RemoveChild(wxWindowBase *child); \
virtual wxWindow *GetDefaultItem() const; \
virtual wxWindow *SetDefaultItem(wxWindow *child) \
// implement the event table entries for wxControlContainer
#define WX_EVENT_TABLE_CONTROL_CONTAINER(classname) \
EVT_SET_FOCUS(classname::OnFocus) \
EVT_CHILD_FOCUS(classname::OnChildFocus) \
EVT_NAVIGATION_KEY(classname::OnNavigationKey)
// implement the methods forwarding to the wxControlContainer
#define WX_DELEGATE_TO_CONTROL_CONTAINER(classname, container) \
wxWindow *classname::SetDefaultItem(wxWindow *child) \
{ \
return container->SetDefaultItem(child); \
} \
\
wxWindow *classname::GetDefaultItem() const \
{ \
return container->GetDefaultItem(); \
} \
\
void classname::OnNavigationKey( wxNavigationKeyEvent& event ) \
{ \
container->HandleOnNavigationKey(event); \
} \
\
void classname::RemoveChild(wxWindowBase *child) \
{ \
container->HandleOnWindowDestroy(child); \
\
wxWindow::RemoveChild(child); \
} \
\
void classname::SetFocus() \
{ \
container->DoSetFocus(); \
} \
\
void classname::OnChildFocus(wxChildFocusEvent& event) \
{ \
container->SetLastFocus(event.GetWindow()); \
} \
\
void classname::OnFocus(wxFocusEvent& event) \
{ \
container->HandleOnFocus(event); \
}
#endif // _WX_CONTAINR_H_

View File

@@ -155,7 +155,8 @@ BEGIN_DECLARE_EVENT_TYPES()
DECLARE_EVENT_TYPE(wxEVT_RIGHT_DCLICK, 111)
DECLARE_EVENT_TYPE(wxEVT_SET_FOCUS, 112)
DECLARE_EVENT_TYPE(wxEVT_KILL_FOCUS, 113)
DECLARE_EVENT_TYPE(wxEVT_MOUSEWHEEL, 114)
DECLARE_EVENT_TYPE(wxEVT_CHILD_FOCUS, 114)
DECLARE_EVENT_TYPE(wxEVT_MOUSEWHEEL, 115)
// Non-client mouse events
DECLARE_EVENT_TYPE(wxEVT_NC_LEFT_DOWN, 200)
@@ -959,6 +960,18 @@ private:
DECLARE_DYNAMIC_CLASS(wxFocusEvent)
};
// wxChildFocusEvent notifies the parent that a child has got the focus: unlike
// wxFocusEvent it is propgated upwards the window chain
class WXDLLEXPORT wxChildFocusEvent : public wxCommandEvent
{
public:
wxChildFocusEvent(wxWindow *win = NULL);
wxWindow *GetWindow() const { return (wxWindow *)GetEventObject(); }
DECLARE_DYNAMIC_CLASS(wxChildFocusEvent)
};
// Activate event class
/*
wxEVT_ACTIVATE
@@ -1759,6 +1772,7 @@ typedef void (wxEvtHandler::*wxEraseEventFunction)(wxEraseEvent&);
typedef void (wxEvtHandler::*wxMouseEventFunction)(wxMouseEvent&);
typedef void (wxEvtHandler::*wxCharEventFunction)(wxKeyEvent&);
typedef void (wxEvtHandler::*wxFocusEventFunction)(wxFocusEvent&);
typedef void (wxEvtHandler::*wxChildFocusEventFunction)(wxChildFocusEvent&);
typedef void (wxEvtHandler::*wxActivateEventFunction)(wxActivateEvent&);
typedef void (wxEvtHandler::*wxMenuEventFunction)(wxMenuEvent&);
typedef void (wxEvtHandler::*wxJoystickEventFunction)(wxJoystickEvent&);
@@ -1826,6 +1840,7 @@ typedef void (wxEvtHandler::*wxContextMenuEventFunction)(wxContextMenuEvent&);
#define EVT_MENU_HIGHLIGHT_ALL(func) DECLARE_EVENT_TABLE_ENTRY( wxEVT_MENU_HIGHLIGHT, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxMenuEventFunction) & func, (wxObject *) NULL ),
#define EVT_SET_FOCUS(func) DECLARE_EVENT_TABLE_ENTRY( wxEVT_SET_FOCUS, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxFocusEventFunction) & func, (wxObject *) NULL ),
#define EVT_KILL_FOCUS(func) DECLARE_EVENT_TABLE_ENTRY( wxEVT_KILL_FOCUS, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxFocusEventFunction) & func, (wxObject *) NULL ),
#define EVT_CHILD_FOCUS(func) DECLARE_EVENT_TABLE_ENTRY( wxEVT_CHILD_FOCUS, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) (wxChildFocusEventFunction) & func, (wxObject *) NULL ),
#define EVT_ACTIVATE(func) DECLARE_EVENT_TABLE_ENTRY( wxEVT_ACTIVATE, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxActivateEventFunction) & func, (wxObject *) NULL ),
#define EVT_ACTIVATE_APP(func) DECLARE_EVENT_TABLE_ENTRY( wxEVT_ACTIVATE_APP, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxActivateEventFunction) & func, (wxObject *) NULL ),
#define EVT_END_SESSION(func) DECLARE_EVENT_TABLE_ENTRY( wxEVT_END_SESSION, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxCloseEventFunction) & func, (wxObject *) NULL ),

View File

@@ -21,8 +21,10 @@
// ----------------------------------------------------------------------------
#include "wx/window.h"
#include "wx/containr.h"
class WXDLLEXPORT wxButton;
class WXDLLEXPORT wxControlContainer;
WXDLLEXPORT_DATA(extern const wxChar*) wxPanelNameStr;
@@ -67,62 +69,34 @@ public:
long style = wxTAB_TRAVERSAL | wxNO_BORDER,
const wxString& name = wxPanelNameStr);
// Sends an OnInitDialog event, which in turns transfers data to
// to the dialog via validators.
virtual void InitDialog();
#if wxUSE_BUTTON
// a default button is activated when Enter is pressed
wxButton *GetDefaultItem() const { return m_btnDefault; }
void SetDefaultItem(wxButton *btn) { m_btnDefault = btn; }
#endif // wxUSE_BUTTON
virtual ~wxPanel();
// implementation from now on
// --------------------------
// Sends an OnInitDialog event, which in turns transfers data to
// to the dialog via validators.
virtual void InitDialog();
// responds to colour changes
void OnSysColourChanged(wxSysColourChangedEvent& event);
// process a keyboard navigation message (Tab traversal)
void OnNavigationKey(wxNavigationKeyEvent& event);
// set the focus to the first child if we get it
void OnFocus(wxFocusEvent& event);
// calls layout for layout constraints and sizers
void OnSize(wxSizeEvent& event);
// overridden to tab move focus into first focusable child
virtual void SetFocus();
// called by wxWindow whenever it gets focus
void SetLastFocus(wxWindow *win) { m_winLastFocused = win; }
wxWindow *GetLastFocus() const { return m_winLastFocused; }
virtual void RemoveChild(wxWindowBase *child);
WX_DECLARE_CONTROL_CONTAINER();
protected:
// common part of all ctors
void Init();
// set the focus to the child which had it the last time
bool SetFocusToChild();
// the child which had the focus last time this panel was activated
wxWindow *m_winLastFocused;
#if wxUSE_BUTTON
// a default button or NULL
wxButton *m_btnDefault;
#endif // wxUSE_BUTTON
// the object which implements the TAB traversal logic
wxControlContainer *m_container;
private:
DECLARE_DYNAMIC_CLASS(wxPanel)
DECLARE_EVENT_TABLE()
};
// this function is for wxWindows use only
extern bool wxSetFocusToChild(wxWindow *win, wxWindow **child);
#endif
// _WX_GENERIC_PANEL_H_

View File

@@ -170,6 +170,10 @@ public:
// window attributes
// -----------------
// NB: in future versions of wxWindows Set/GetTitle() will only work
// with the top level windows (such as dialogs and frames) and
// Set/GetLabel() only with the other ones (i.e. all controls).
// the title (or label, see below) of the window: the text which the
// window shows
virtual void SetTitle( const wxString& WXUNUSED(title) ) {}
@@ -361,8 +365,8 @@ public:
virtual void SetThemeEnabled(bool enableTheme) { m_themeEnabled = enableTheme; }
virtual bool GetThemeEnabled() const { return m_themeEnabled; }
// focus handling
// --------------
// focus and keyboard handling
// ---------------------------
// set focus to this window
virtual void SetFocus() = 0;
@@ -378,6 +382,17 @@ public:
// click it
virtual bool AcceptsFocusFromKeyboard() const { return AcceptsFocus(); }
// NB: these methods really don't belong here but with the current
// class hierarchy there is no other place for them :-(
// get the default child of this parent, i.e. the one which is
// activated by pressing <Enter>
virtual wxWindow *GetDefaultItem() const { return NULL; }
// set this child as default, return the old default
virtual wxWindow *SetDefaultItem(wxWindow * WXUNUSED(child))
{ return NULL; }
// parent/children relations
// -------------------------
@@ -786,7 +801,7 @@ protected:
// the window id - a number which uniquely identifies a window among
// its siblings unless it is -1
wxWindowID m_windowId;
// the parent window of this window (or NULL) and the list of the children
// of this window
wxWindow *m_parent;

353
src/common/containr.cpp Normal file
View File

@@ -0,0 +1,353 @@
///////////////////////////////////////////////////////////////////////////////
// Name: src/common/containr.cpp
// Purpose: implementation of wxControlContainer
// Author: Vadim Zeitlin
// Modified by:
// Created: 06.08.01
// RCS-ID: $Id$
// Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
// License: wxWindows license
///////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#ifdef __GNUG__
#pragma implementation "containr.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#endif //WX_PRECOMP
#include "wx/containr.h"
// ============================================================================
// implementation
// ============================================================================
wxControlContainer::wxControlContainer(wxWindow *winParent)
{
m_winParent = winParent;
m_winLastFocused =
m_winDefault = NULL;
}
void wxControlContainer::SetLastFocus(wxWindow *win)
{
// find the last _immediate_ child which got focus
while ( win )
{
wxWindow *parent = win->GetParent();
if ( parent == m_winParent )
break;
win = parent;
}
wxASSERT_MSG( win, _T("attempt to set last focus to not a child?") );
m_winLastFocused = win;
}
// ----------------------------------------------------------------------------
// Keyboard handling - this is the place where the TAB traversal logic is
// implemented. As this code is common to all ports, this ensures consistent
// behaviour even if we don't specify how exactly the wxNavigationKeyEvent are
// generated and this is done in platform specific code which also ensures that
// we can follow the given platform standards.
// ----------------------------------------------------------------------------
void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event )
{
wxWindow *parent = m_winParent->GetParent();
// the event is propagated downwards if the event emitter was our parent
bool goingDown = event.GetEventObject() == parent;
const wxWindowList& children = m_winParent->GetChildren();
// there is not much to do if we don't have children and we're not
// interested in "notebook page change" events here
if ( !children.GetCount() || event.IsWindowChange() )
{
// let the parent process it unless it already comes from our parent
// of we don't have any
if ( goingDown ||
!parent || !parent->GetEventHandler()->ProcessEvent(event) )
{
event.Skip();
}
return;
}
// 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;
// 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 = m_winParent;
while ( parent )
{
// 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;
parent = parent->GetParent();
}
}
//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->AcceptsFocusFromKeyboard() )
{
// 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
event.SetEventObject(m_winParent);
if ( !child->GetEventHandler()->ProcessEvent(event) )
{
// everything is simple: just give focus to it
child->SetFocus();
m_winLastFocused = child;
}
//else: the child manages its focus itself
event.Skip( FALSE );
return;
}
node = forward ? node->GetNext() : node->GetPrevious();
}
// we cycled through all of our children and none of them wanted to accept
// focus
event.Skip();
}
void wxControlContainer::HandleOnWindowDestroy(wxWindowBase *child)
{
if ( child == m_winLastFocused )
m_winLastFocused = NULL;
if ( child == m_winDefault )
m_winDefault = NULL;
}
// ----------------------------------------------------------------------------
// focus handling
// ----------------------------------------------------------------------------
void wxControlContainer::DoSetFocus()
{
wxLogTrace(_T("focus"), _T("SetFocus on wxPanel 0x%08x."),
m_winParent->GetHandle());
// If the panel gets the focus *by way of getting it set directly*
// we move the focus to the first window that can get it.
// VZ: no, we set the focus to the last window too. I don't understand why
// should we make this distinction: if an app wants to set focus to
// some precise control, it may always do it directly, but if we don't
// use m_winLastFocused here, the focus won't be set correctly after a
// notebook page change nor after frame activation under MSW (it calls
// SetFocus too)
//
// RR: yes, when I the tab key to navigate in a panel with some controls and
// a notebook and the focus jumps to the notebook (typically coming from
// a button at the top) the notebook should focus the first child in the
// current notebook page, not the last one which would otherwise get the
// focus if you used the tab key to navigate from the current notebook
// page to button at the bottom. See every page in the controls sample.
//
// VZ: ok, but this still doesn't (at least I don't see how it can) take
// care of first/last child problem: i.e. if Shift-TAB is pressed in a
// situation like above, the focus should be given to the last child,
// not the first one (and not to the last focused one neither) - I
// think my addition to OnNavigationKey() above takes care of it.
// Keeping #ifdef __WXGTK__ for now, but please try removing it and see
// what happens.
//
// RR: Removed for now. Let's see what happens..
if ( !SetFocusToChild() )
{
m_winParent->SetFocus();
}
}
void wxControlContainer::HandleOnFocus(wxFocusEvent& event)
{
wxLogTrace(_T("focus"), _T("OnFocus on wxPanel 0x%08x, name: %s"),
m_winParent->GetHandle(),
m_winParent->GetName().c_str() );
// If we panel got the focus *by way of getting clicked on*
// we move the focus to either the last window that had the
// focus or the first one that can get it.
(void)SetFocusToChild();
event.Skip();
}
bool wxControlContainer::SetFocusToChild()
{
return wxSetFocusToChild(m_winParent, &m_winLastFocused);
}
// ----------------------------------------------------------------------------
// SetFocusToChild(): this function is used by wxPanel but also by wxFrame in
// wxMSW, this is why it is outside of wxControlContainer class
// ----------------------------------------------------------------------------
bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused)
{
wxCHECK_MSG( win, FALSE, _T("wxSetFocusToChild(): invalid window") );
if ( *childLastFocused )
{
// It might happen that the window got reparented or no longer accepts
// the focus.
if ( (*childLastFocused)->GetParent() == win &&
(*childLastFocused)->AcceptsFocusFromKeyboard() )
{
wxLogTrace(_T("focus"),
_T("SetFocusToChild() => last child (0x%08x)."),
(*childLastFocused)->GetHandle());
(*childLastFocused)->SetFocus();
return TRUE;
}
else
{
// it doesn't count as such any more
*childLastFocused = (wxWindow *)NULL;
}
}
// set the focus to the first child who wants it
wxWindowList::Node *node = win->GetChildren().GetFirst();
while ( node )
{
wxWindow *child = node->GetData();
if ( child->AcceptsFocusFromKeyboard() && !child->IsTopLevel() )
{
wxLogTrace(_T("focus"),
_T("SetFocusToChild() => first child (0x%08x)."),
child->GetHandle());
*childLastFocused = child; // should be redundant, but it is not
child->SetFocus();
return TRUE;
}
node = node->GetNext();
}
return FALSE;
}

View File

@@ -67,6 +67,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxIdleEvent, wxEvent)
IMPLEMENT_DYNAMIC_CLASS(wxEraseEvent, wxEvent)
IMPLEMENT_DYNAMIC_CLASS(wxMoveEvent, wxEvent)
IMPLEMENT_DYNAMIC_CLASS(wxFocusEvent, wxEvent)
IMPLEMENT_DYNAMIC_CLASS(wxChildFocusEvent, wxCommandEvent)
IMPLEMENT_DYNAMIC_CLASS(wxCloseEvent, wxEvent)
IMPLEMENT_DYNAMIC_CLASS(wxShowEvent, wxEvent)
IMPLEMENT_DYNAMIC_CLASS(wxMaximizeEvent, wxEvent)
@@ -150,6 +151,7 @@ DEFINE_EVENT_TYPE(wxEVT_MIDDLE_DCLICK)
DEFINE_EVENT_TYPE(wxEVT_RIGHT_DCLICK)
DEFINE_EVENT_TYPE(wxEVT_SET_FOCUS)
DEFINE_EVENT_TYPE(wxEVT_KILL_FOCUS)
DEFINE_EVENT_TYPE(wxEVT_CHILD_FOCUS)
DEFINE_EVENT_TYPE(wxEVT_MOUSEWHEEL)
// Non-client mouse events
@@ -732,6 +734,16 @@ void wxIdleEvent::CopyObject(wxObject& obj_d) const
obj->m_requestMore = m_requestMore;
}
wxChildFocusEvent::wxChildFocusEvent(wxWindow *win)
: wxCommandEvent(wxEVT_CHILD_FOCUS)
{
SetEventObject(win);
}
// ----------------------------------------------------------------------------
// wxEvtHandler
// ----------------------------------------------------------------------------
/*
* Event handler
*/

View File

@@ -36,7 +36,8 @@
#include "wx/log.h"
#endif
#include "wx/generic/panelg.h"
#include "wx/containr.h"
#include "wx/panel.h"
// ----------------------------------------------------------------------------
// wxWin macros
@@ -45,26 +46,26 @@
IMPLEMENT_DYNAMIC_CLASS(wxPanel, wxWindow)
BEGIN_EVENT_TABLE(wxPanel, wxWindow)
EVT_SYS_COLOUR_CHANGED(wxPanel::OnSysColourChanged)
EVT_SET_FOCUS(wxPanel::OnFocus)
EVT_NAVIGATION_KEY(wxPanel::OnNavigationKey)
EVT_SIZE(wxPanel::OnSize)
EVT_SYS_COLOUR_CHANGED(wxPanel::OnSysColourChanged)
EVT_SIZE(wxPanel::OnSize)
WX_EVENT_TABLE_CONTROL_CONTAINER(wxPanel)
END_EVENT_TABLE()
// ============================================================================
// implementation
// ============================================================================
WX_DELEGATE_TO_CONTROL_CONTAINER(wxPanel, m_container)
// ----------------------------------------------------------------------------
// wxPanel creation
// ----------------------------------------------------------------------------
void wxPanel::Init()
{
m_winLastFocused = (wxWindow *)NULL;
#if wxUSE_BUTTON
m_btnDefault = (wxButton *)NULL;
#endif // wxUSE_BUTTON
m_container = new wxControlContainer(this);
}
bool wxPanel::Create(wxWindow *parent, wxWindowID id,
@@ -76,6 +77,11 @@ bool wxPanel::Create(wxWindow *parent, wxWindowID id,
return wxWindow::Create(parent, id, pos, size, style, name);
}
wxPanel::~wxPanel()
{
delete m_container;
}
// ----------------------------------------------------------------------------
// misc
// ----------------------------------------------------------------------------
@@ -102,297 +108,6 @@ void wxPanel::OnSize(wxSizeEvent& WXUNUSED(event))
#if wxUSE_CONSTRAINTS
if (GetAutoLayout())
Layout();
#endif
#endif // wxUSE_CONSTRAINTS
}
// ----------------------------------------------------------------------------
// Keyboard handling - this is the place where the TAB traversal logic is
// implemented. As this code is common to all ports, this ensures consistent
// behaviour even if we don't specify how exactly the wxNavigationKeyEvent are
// generated and this is done in platform specific code which also ensures that
// we can follow the given platform standards.
// ----------------------------------------------------------------------------
void wxPanel::OnNavigationKey( wxNavigationKeyEvent& event )
{
// the event is propagated downwards if the event emitter was our parent
bool goingDown = event.GetEventObject() == GetParent();
const wxWindowList& children = GetChildren();
// there is not much to do if we don't have children and we're not
// interested in "notebook page change" events here
if ( !children.GetCount() || event.IsWindowChange() )
{
// let the parent process it unless it already comes from our parent
// of we don't have any
wxWindow *parent = GetParent();
if ( goingDown ||
!parent || !parent->GetEventHandler()->ProcessEvent(event) )
{
event.Skip();
}
return;
}
// 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;
// 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->AcceptsFocusFromKeyboard() )
{
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();
}
// we cycled through all of our children and none of them wanted to accept
// focus
event.Skip();
}
void wxPanel::RemoveChild(wxWindowBase *child)
{
if ( child == m_winLastFocused )
m_winLastFocused = NULL;
wxWindow::RemoveChild(child);
}
void wxPanel::SetFocus()
{
wxLogTrace(_T("focus"), _T("SetFocus on wxPanel 0x%08x."), GetHandle());
// If the panel gets the focus *by way of getting it set directly*
// we move the focus to the first window that can get it.
// VZ: no, we set the focus to the last window too. I don't understand why
// should we make this distinction: if an app wants to set focus to
// some precise control, it may always do it directly, but if we don't
// use m_winLastFocused here, the focus won't be set correctly after a
// notebook page change nor after frame activation under MSW (it calls
// SetFocus too)
//
// RR: yes, when I the tab key to navigate in a panel with some controls and
// a notebook and the focus jumps to the notebook (typically coming from
// a button at the top) the notebook should focus the first child in the
// current notebook page, not the last one which would otherwise get the
// focus if you used the tab key to navigate from the current notebook
// page to button at the bottom. See every page in the controls sample.
//
// VZ: ok, but this still doesn't (at least I don't see how it can) take
// care of first/last child problem: i.e. if Shift-TAB is pressed in a
// situation like above, the focus should be given to the last child,
// not the first one (and not to the last focused one neither) - I
// think my addition to OnNavigationKey() above takes care of it.
// Keeping #ifdef __WXGTK__ for now, but please try removing it and see
// what happens.
//
// RR: Removed for now. Let's see what happens..
if ( !SetFocusToChild() )
{
wxWindow::SetFocus();
}
}
void wxPanel::OnFocus(wxFocusEvent& event)
{
wxLogTrace(_T("focus"), _T("OnFocus on wxPanel 0x%08x, name: %s"), GetHandle(), GetName().c_str() );
// If the panel gets the focus *by way of getting clicked on*
// we move the focus to either the last window that had the
// focus or the first one that can get it.
(void)SetFocusToChild();
event.Skip();
}
bool wxPanel::SetFocusToChild()
{
return wxSetFocusToChild(this, &m_winLastFocused);
}
// ----------------------------------------------------------------------------
// SetFocusToChild(): this function is used by wxPanel but also by wxFrame in
// wxMSW, this is why it is outside of wxPanel class
// ----------------------------------------------------------------------------
bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused)
{
wxCHECK_MSG( win, FALSE, _T("wxSetFocusToChild(): invalid window") );
if ( *childLastFocused )
{
// It might happen that the window got reparented or no longer accepts
// the focus.
if ( (*childLastFocused)->GetParent() == win &&
(*childLastFocused)->AcceptsFocusFromKeyboard() )
{
wxLogTrace(_T("focus"),
_T("SetFocusToChild() => last child (0x%08x)."),
(*childLastFocused)->GetHandle());
(*childLastFocused)->SetFocus();
return TRUE;
}
else
{
// it doesn't count as such any more
*childLastFocused = (wxWindow *)NULL;
}
}
// set the focus to the first child who wants it
wxWindowList::Node *node = win->GetChildren().GetFirst();
while ( node )
{
wxWindow *child = node->GetData();
if ( child->AcceptsFocusFromKeyboard() && !child->IsTopLevel() )
{
wxLogTrace(_T("focus"),
_T("SetFocusToChild() => first child (0x%08x)."),
child->GetHandle());
*childLastFocused = child; // should be redundant, but it is not
child->SetFocus();
return TRUE;
}
node = node->GetNext();
}
return FALSE;
}

View File

@@ -1692,11 +1692,10 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
printf( ".\n" );
*/
wxPanel *panel = wxDynamicCast(win->GetParent(), wxPanel);
if (panel)
{
panel->SetLastFocus(win);
}
// notify the parent keeping track of focus for the kbd navigation
// purposes that we got it
wxChildFocusEvent eventFocus(this);
(void)GetEventHandler()->ProcessEvent(eventFocus);
#ifdef HAVE_XIM
if (win->m_ic)

View File

@@ -1692,11 +1692,10 @@ static gint gtk_window_focus_in_callback( GtkWidget *widget,
printf( ".\n" );
*/
wxPanel *panel = wxDynamicCast(win->GetParent(), wxPanel);
if (panel)
{
panel->SetLastFocus(win);
}
// notify the parent keeping track of focus for the kbd navigation
// purposes that we got it
wxChildFocusEvent eventFocus(this);
(void)GetEventHandler()->ProcessEvent(eventFocus);
#ifdef HAVE_XIM
if (win->m_ic)

View File

@@ -128,15 +128,6 @@ bool wxButton::Create(wxWindow *parent,
wxButton::~wxButton()
{
wxPanel *panel = wxDynamicCast(GetParent(), wxPanel);
if ( panel )
{
if ( panel->GetDefaultItem() == this )
{
// don't leave the panel with invalid default item
panel->SetDefaultItem(NULL);
}
}
}
// ----------------------------------------------------------------------------
@@ -197,20 +188,20 @@ wxSize wxButtonBase::GetDefaultSize()
void wxButton::SetDefault()
{
wxWindow *parent = GetParent();
wxButton *btnOldDefault = NULL;
wxPanel *panel = wxDynamicCast(parent, wxPanel);
if ( panel )
{
btnOldDefault = panel->GetDefaultItem();
panel->SetDefaultItem(this);
}
wxButton *btnOldDefault;
if ( parent )
{
SendMessage(GetWinHwnd(parent), DM_SETDEFID, m_windowId, 0L);
wxWindow *winOldDefault = parent->SetDefaultItem(this);
btnOldDefault = wxDynamicCast(winOldDefault, wxButton);
::SendMessage(GetWinHwnd(parent), DM_SETDEFID, m_windowId, 0L);
}
else // is a button without parent really normal?
{
btnOldDefault = NULL;
}
if ( btnOldDefault )
if ( btnOldDefault && btnOldDefault != this )
{
// remove the BS_DEFPUSHBUTTON style from the other button
long style = GetWindowLong(GetHwndOf(btnOldDefault), GWL_STYLE);

View File

@@ -39,7 +39,6 @@
#include "wx/dcclient.h"
#include "wx/utils.h"
#include "wx/app.h"
#include "wx/panel.h"
#include "wx/layout.h"
#include "wx/dialog.h"
#include "wx/frame.h"
@@ -177,7 +176,6 @@ BEGIN_EVENT_TABLE(wxWindowMSW, wxWindowBase)
EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged)
EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog)
EVT_IDLE(wxWindowMSW::OnIdle)
EVT_SET_FOCUS(wxWindowMSW::OnSetFocus)
END_EVENT_TABLE()
// ===========================================================================
@@ -1845,18 +1843,13 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
bProcess = FALSE;
}
// FIXME: this should be handled by
// wxNavigationKeyEvent handler and not here!!
#if wxUSE_BUTTON
else
{
wxPanel *panel = wxDynamicCastThis(wxPanel);
wxButton *btn = NULL;
if ( panel )
{
// panel may have a default button which should
// be activated by Enter
btn = panel->GetDefaultItem();
}
wxButton *btn = wxDynamicCast(GetDefaultItem(),
wxButton);
if ( btn && btn->IsEnabled() )
{
// if we do have a default button, do press it
@@ -1885,15 +1878,6 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
if ( GetEventHandler()->ProcessEvent(event) )
{
#if wxUSE_BUTTON
wxButton *btn = wxDynamicCast(FindFocus(), wxButton);
if ( btn )
{
// the button which has focus should be default
btn->SetDefault();
}
#endif // wxUSE_BUTTON
return TRUE;
}
}
@@ -3089,33 +3073,6 @@ bool wxWindowMSW::HandleDestroy()
// activation/focus
// ---------------------------------------------------------------------------
void wxWindowMSW::OnSetFocus(wxFocusEvent& event)
{
// panel wants to track the window which was the last to have focus in it,
// so we want to set ourselves as the window which last had focus
//
// notice that it's also important to do it upwards the tree becaus
// otherwise when the top level panel gets focus, it won't set it back to
// us, but to some other sibling
wxWindow *win = (wxWindow *)this;
while ( win )
{
wxWindow *parent = win->GetParent();
wxPanel *panel = wxDynamicCast(parent, wxPanel);
if ( panel )
{
panel->SetLastFocus(win);
}
win = parent;
}
wxLogTrace(_T("focus"), _T("%s (0x%08x) gets focus"),
GetClassInfo()->GetClassName(), GetHandle());
event.Skip();
}
bool wxWindowMSW::HandleActivate(int state,
bool WXUNUSED(minimized),
WXHWND WXUNUSED(activate))
@@ -3130,6 +3087,11 @@ bool wxWindowMSW::HandleActivate(int state,
bool wxWindowMSW::HandleSetFocus(WXHWND hwnd)
{
// notify the parent keeping track of focus for the kbd navigation
// purposes that we got it
wxChildFocusEvent eventFocus(this);
(void)GetEventHandler()->ProcessEvent(eventFocus);
#if wxUSE_CARET
// Deal with caret
if ( m_caret )
@@ -3140,13 +3102,12 @@ bool wxWindowMSW::HandleSetFocus(WXHWND hwnd)
#if wxUSE_TEXTCTRL
// If it's a wxTextCtrl don't send the event as it will be done
// after the control gets to process it.
wxTextCtrl *ctrl = wxDynamicCastThis(wxTextCtrl);
if ( ctrl )
// after the control gets to process it from EN_FOCUS handler
if ( wxDynamicCastThis(wxTextCtrl) )
{
return FALSE;
}
#endif
#endif // wxUSE_TEXTCTRL
wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId);
event.SetEventObject(this);