better key handling for MSW and GTK (patch 1526666)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@40579 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2006-08-13 00:35:02 +00:00
parent d1af8e2dd9
commit b445b6a76e
7 changed files with 157 additions and 87 deletions

View File

@@ -297,6 +297,14 @@ public:
// Utilies needed by the popups or native implementations
//
// Returns true if given key combination should toggle the popup.
// NB: This is a separate from other keyboard handling because:
// 1) Replaceability.
// 2) Centralized code (otherwise it'd be split up between
// wxComboCtrl key handler and wxVListBoxComboPopup's
// key handler).
virtual bool IsKeyPopupToggle(const wxKeyEvent& event) const = 0;
// Draws focus background (on combo control) in a way typical on platform.
// Unless you plan to paint your own focus indicator, you should always call this
// in your wxComboPopup::PaintComboControl implementation.
@@ -351,7 +359,7 @@ protected:
void CreateTextCtrl( int extraStyle, const wxValidator& validator );
// Installs standard input handler to combo (and optionally to the textctrl)
void InstallInputHandlers( bool alsoTextCtrl = true );
void InstallInputHandlers();
// Draws dropbutton. Using wxRenderer or bitmaps, as appropriate.
void DrawButton( wxDC& dc, const wxRect& rect, bool paintBg = true );
@@ -402,6 +410,7 @@ protected:
void OnFocusEvent(wxFocusEvent& event);
void OnTextCtrlEvent(wxCommandEvent& event);
void OnSysColourChanged(wxSysColourChangedEvent& event);
void OnKeyEvent(wxKeyEvent& event);
// Set customization flags (directs how wxComboCtrlBase helpers behave)
void Customize( wxUint32 flags ) { m_iFlags |= flags; }
@@ -432,10 +441,7 @@ protected:
// popup interface
wxComboPopup* m_popupInterface;
// this is for this control itself
wxEvtHandler* m_extraEvtHandler;
// this is for text
// this is input etc. handler for the text control
wxEvtHandler* m_textEvtHandler;
// this is for the top level window

View File

@@ -65,6 +65,8 @@ public:
virtual ~wxGenericComboControl();
virtual bool IsKeyPopupToggle(const wxKeyEvent& event) const;
static int GetFeatures() { return wxComboCtrlFeatures::All; }
#if defined(__WXUNIVERSAL__)

View File

@@ -60,6 +60,7 @@ public:
virtual ~wxComboCtrl();
virtual void DrawFocusBackground( wxDC& dc, const wxRect& rect, int flags ) const;
virtual bool IsKeyPopupToggle(const wxKeyEvent& event) const;
static int GetFeatures() { return wxComboCtrlFeatures::All; }

View File

@@ -427,8 +427,7 @@ void wxComboPopup::Dismiss()
// ----------------------------------------------------------------------------
//
// This is pushed to the event handler queue of either combo box
// or its textctrl (latter if not readonly combo).
// This is pushed to the event handler queue of the child textctrl.
//
class wxComboBoxExtraInputHandler : public wxEvtHandler
{
@@ -459,44 +458,16 @@ END_EVENT_TABLE()
void wxComboBoxExtraInputHandler::OnKey(wxKeyEvent& event)
{
int keycode = event.GetKeyCode();
// Let the wxComboCtrl event handler have a go first.
wxComboCtrlBase* combo = m_combo;
wxObject* prevObj = event.GetEventObject();
if ( keycode == WXK_TAB && !m_combo->IsPopupShown() )
{
wxNavigationKeyEvent evt;
evt.SetFlags(wxNavigationKeyEvent::FromTab|
(!event.ShiftDown()?wxNavigationKeyEvent::IsForward:
wxNavigationKeyEvent::IsBackward));
evt.SetEventObject(m_combo);
m_combo->GetParent()->GetEventHandler()->AddPendingEvent(evt);
return;
}
event.SetId(combo->GetId());
event.SetEventObject(combo);
combo->GetEventHandler()->ProcessEvent(event);
if ( m_combo->IsPopupShown() )
{
// pass it to the popped up control
m_combo->GetPopupControl()->GetControl()->AddPendingEvent(event);
}
else // no popup
{
int comboStyle = m_combo->GetWindowStyle();
wxComboPopup* popupInterface = m_combo->GetPopupControl();
if ( !popupInterface )
{
event.Skip();
return;
}
if ( (comboStyle & wxCB_READONLY) ||
( keycode != WXK_RIGHT && keycode != WXK_LEFT )
)
{
popupInterface->OnComboKeyEvent(event);
}
else
event.Skip();
}
event.SetId(((wxWindow*)prevObj)->GetId());
event.SetEventObject(prevObj);
}
void wxComboBoxExtraInputHandler::OnFocus(wxFocusEvent& event)
@@ -511,17 +482,15 @@ void wxComboBoxExtraInputHandler::OnFocus(wxFocusEvent& event)
m_combo->SetSelection(-1,-1);
}
if ( event.GetId() != m_combo->GetId() )
{
// Add textctrl set focus events as combo set focus events
// NOTE: Simply changing the event and skipping didn't seem
// to do the trick.
// Send focus indication to parent.
// NB: This is needed for cases where the textctrl gets focus
// instead of its parent. While this may trigger multiple
// wxEVT_SET_FOCUSes (since m_text->SetFocus is called
// from combo's focus event handler), they should be quite
// harmless.
wxFocusEvent evt2(wxEVT_SET_FOCUS,m_combo->GetId());
evt2.SetEventObject(m_combo);
m_combo->GetEventHandler()->ProcessEvent(evt2);
}
else
event.Skip();
event.Skip();
}
@@ -633,6 +602,7 @@ BEGIN_EVENT_TABLE(wxComboCtrlBase, wxControl)
EVT_SET_FOCUS(wxComboCtrlBase::OnFocusEvent)
EVT_KILL_FOCUS(wxComboCtrlBase::OnFocusEvent)
//EVT_BUTTON(wxID_ANY,wxComboCtrlBase::OnButtonClickEvent)
EVT_KEY_DOWN(wxComboCtrlBase::OnKeyEvent)
EVT_TEXT_ENTER(wxID_ANY,wxComboCtrlBase::OnTextCtrlEvent)
EVT_SYS_COLOUR_CHANGED(wxComboCtrlBase::OnSysColourChanged)
END_EVENT_TABLE()
@@ -652,7 +622,6 @@ void wxComboCtrlBase::Init()
m_text = (wxTextCtrl*) NULL;
m_popupInterface = (wxComboPopup*) NULL;
m_extraEvtHandler = (wxEvtHandler*) NULL;
m_popupExtraHandler = (wxEvtHandler*) NULL;
m_textEvtHandler = (wxEvtHandler*) NULL;
@@ -718,17 +687,13 @@ bool wxComboCtrlBase::Create(wxWindow *parent,
return true;
}
void wxComboCtrlBase::InstallInputHandlers( bool alsoTextCtrl )
void wxComboCtrlBase::InstallInputHandlers()
{
if ( m_text && alsoTextCtrl )
if ( m_text )
{
m_textEvtHandler = new wxComboBoxExtraInputHandler(this);
m_text->PushEventHandler(m_textEvtHandler);
}
wxComboBoxExtraInputHandler* inputHandler = new wxComboBoxExtraInputHandler(this);
PushEventHandler(inputHandler);
m_extraEvtHandler = inputHandler;
}
void
@@ -774,13 +739,10 @@ wxComboCtrlBase::~wxComboCtrlBase()
DestroyPopup();
RemoveEventHandler(m_extraEvtHandler);
if ( m_text )
m_text->RemoveEventHandler(m_textEvtHandler);
delete m_textEvtHandler;
delete m_extraEvtHandler;
}
@@ -1476,22 +1438,67 @@ void wxComboCtrlBase::HandleNormalMouseEvent( wxMouseEvent& event )
event.Skip();
}
void wxComboCtrlBase::OnFocusEvent( wxFocusEvent& )
void wxComboCtrlBase::OnKeyEvent(wxKeyEvent& event)
{
if ( IsPopupShown() )
{
// pass it to the popped up control
GetPopupControl()->GetControl()->AddPendingEvent(event);
}
else // no popup
{
int keycode = event.GetKeyCode();
if ( keycode == WXK_TAB )
{
wxNavigationKeyEvent evt;
evt.SetFlags(wxNavigationKeyEvent::FromTab|
(!event.ShiftDown() ? wxNavigationKeyEvent::IsForward
: wxNavigationKeyEvent::IsBackward));
evt.SetEventObject(this);
GetParent()->GetEventHandler()->AddPendingEvent(evt);
return;
}
if ( IsKeyPopupToggle(event) )
{
OnButtonClick();
return;
}
int comboStyle = GetWindowStyle();
wxComboPopup* popupInterface = GetPopupControl();
if ( !popupInterface )
{
event.Skip();
return;
}
if ( (comboStyle & wxCB_READONLY) ||
(keycode != WXK_RIGHT && keycode != WXK_LEFT) )
{
popupInterface->OnComboKeyEvent(event);
}
else
event.Skip();
}
}
void wxComboCtrlBase::OnFocusEvent( wxFocusEvent& event )
{
if ( event.GetEventType() == wxEVT_SET_FOCUS )
{
// First click is the first part of double-click
// Some platforms don't generate down-less mouse up-event
// (Windows does, GTK+2 doesn't), so that's why we have
// to do this.
m_timeLastMouseUp = ::wxGetLocalTimeMillis();
if ( m_text )
{
if ( m_text && m_text != ::wxWindow::FindFocus() )
m_text->SetFocus();
}
else
// no need to check for m_widthCustomPaint - that
// area never gets special handling when selected
// (in writable mode, that is)
Refresh();
}

View File

@@ -161,7 +161,7 @@ bool wxGenericComboControl::Create(wxWindow *parent,
CreateTextCtrl( wxNO_BORDER, validator );
// Add keyboard input handlers for main control and textctrl
InstallInputHandlers( true );
InstallInputHandlers();
// Set background
SetBackgroundStyle( wxBG_STYLE_CUSTOM ); // for double-buffering
@@ -321,6 +321,28 @@ void wxGenericComboControl::OnMouseEvent( wxMouseEvent& event )
}
bool wxGenericComboControl::IsKeyPopupToggle(const wxKeyEvent& event) const
{
int keycode = event.GetKeyCode();
bool isPopupShown = IsPopupShown();
// This code is AFAIK appropriate for wxGTK.
if ( isPopupShown )
{
if ( keycode == WXK_ESCAPE ||
( keycode == WXK_UP && event.AltDown() ) )
return true;
}
else
{
if ( keycode == WXK_DOWN && event.AltDown() )
return true;
}
return false;
}
#ifdef __WXUNIVERSAL__
bool wxGenericComboControl::PerformAction(const wxControlAction& action,

View File

@@ -410,17 +410,24 @@ void wxVListBoxComboPopup::OnLeftClick(wxMouseEvent& WXUNUSED(event))
void wxVListBoxComboPopup::OnKey(wxKeyEvent& event)
{
// Select item if ENTER is pressed
if ( event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER )
{
DismissWithEvent();
}
// Hide popup if ESC is pressed
else if ( event.GetKeyCode() == WXK_ESCAPE )
// Hide popup if certain key or key combination was pressed
if ( m_combo->IsKeyPopupToggle(event) )
{
StopPartialCompletion();
Dismiss();
}
else if ( event.AltDown() )
{
// On both wxGTK and wxMSW, pressing Alt down seems to
// completely freeze things in popup (ie. arrow keys and
// enter won't work).
return;
}
// Select item if ENTER is pressed
else if ( event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER )
{
DismissWithEvent();
}
else
{
int comboStyle = m_combo->GetWindowStyle();

View File

@@ -135,7 +135,7 @@ bool wxComboCtrl::Create(wxWindow *parent,
CreateTextCtrl( wxNO_BORDER, validator );
// Add keyboard input handlers for main control and textctrl
InstallInputHandlers( true );
InstallInputHandlers();
// Prepare background for double-buffering
SetBackgroundStyle( wxBG_STYLE_CUSTOM );
@@ -529,5 +529,30 @@ wxCoord wxComboCtrl::GetNativeTextIndent() const
return NATIVE_TEXT_INDENT_CLASSIC;
}
bool wxComboCtrl::IsKeyPopupToggle(const wxKeyEvent& event) const
{
int keycode = event.GetKeyCode();
bool isPopupShown = IsPopupShown();
if ( isPopupShown && keycode == WXK_ESCAPE )
return true;
// On XP or with writable combo in Classic,
// Alt is required, in addition to up/down, to
// show the popup.
if ( keycode == WXK_DOWN || keycode == WXK_UP )
{
if ( event.AltDown() ||
( !isPopupShown &&
HasFlag(wxCB_READONLY) &&
!wxUxThemeEngine::GetIfActive()
) )
{
return true;
}
}
return false;
}
#endif // wxUSE_COMBOCTRL