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 // 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. // 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 // Unless you plan to paint your own focus indicator, you should always call this
// in your wxComboPopup::PaintComboControl implementation. // in your wxComboPopup::PaintComboControl implementation.
@@ -351,7 +359,7 @@ protected:
void CreateTextCtrl( int extraStyle, const wxValidator& validator ); void CreateTextCtrl( int extraStyle, const wxValidator& validator );
// Installs standard input handler to combo (and optionally to the textctrl) // 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. // Draws dropbutton. Using wxRenderer or bitmaps, as appropriate.
void DrawButton( wxDC& dc, const wxRect& rect, bool paintBg = true ); void DrawButton( wxDC& dc, const wxRect& rect, bool paintBg = true );
@@ -402,6 +410,7 @@ protected:
void OnFocusEvent(wxFocusEvent& event); void OnFocusEvent(wxFocusEvent& event);
void OnTextCtrlEvent(wxCommandEvent& event); void OnTextCtrlEvent(wxCommandEvent& event);
void OnSysColourChanged(wxSysColourChangedEvent& event); void OnSysColourChanged(wxSysColourChangedEvent& event);
void OnKeyEvent(wxKeyEvent& event);
// Set customization flags (directs how wxComboCtrlBase helpers behave) // Set customization flags (directs how wxComboCtrlBase helpers behave)
void Customize( wxUint32 flags ) { m_iFlags |= flags; } void Customize( wxUint32 flags ) { m_iFlags |= flags; }
@@ -432,10 +441,7 @@ protected:
// popup interface // popup interface
wxComboPopup* m_popupInterface; wxComboPopup* m_popupInterface;
// this is for this control itself // this is input etc. handler for the text control
wxEvtHandler* m_extraEvtHandler;
// this is for text
wxEvtHandler* m_textEvtHandler; wxEvtHandler* m_textEvtHandler;
// this is for the top level window // this is for the top level window

View File

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

View File

@@ -60,6 +60,7 @@ public:
virtual ~wxComboCtrl(); virtual ~wxComboCtrl();
virtual void DrawFocusBackground( wxDC& dc, const wxRect& rect, int flags ) const; virtual void DrawFocusBackground( wxDC& dc, const wxRect& rect, int flags ) const;
virtual bool IsKeyPopupToggle(const wxKeyEvent& event) const;
static int GetFeatures() { return wxComboCtrlFeatures::All; } 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 // This is pushed to the event handler queue of the child textctrl.
// or its textctrl (latter if not readonly combo).
// //
class wxComboBoxExtraInputHandler : public wxEvtHandler class wxComboBoxExtraInputHandler : public wxEvtHandler
{ {
@@ -459,44 +458,16 @@ END_EVENT_TABLE()
void wxComboBoxExtraInputHandler::OnKey(wxKeyEvent& event) 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() ) event.SetId(combo->GetId());
{ event.SetEventObject(combo);
wxNavigationKeyEvent evt; combo->GetEventHandler()->ProcessEvent(event);
evt.SetFlags(wxNavigationKeyEvent::FromTab|
(!event.ShiftDown()?wxNavigationKeyEvent::IsForward:
wxNavigationKeyEvent::IsBackward));
evt.SetEventObject(m_combo);
m_combo->GetParent()->GetEventHandler()->AddPendingEvent(evt);
return;
}
if ( m_combo->IsPopupShown() ) event.SetId(((wxWindow*)prevObj)->GetId());
{ event.SetEventObject(prevObj);
// 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();
}
} }
void wxComboBoxExtraInputHandler::OnFocus(wxFocusEvent& event) void wxComboBoxExtraInputHandler::OnFocus(wxFocusEvent& event)
@@ -511,17 +482,15 @@ void wxComboBoxExtraInputHandler::OnFocus(wxFocusEvent& event)
m_combo->SetSelection(-1,-1); m_combo->SetSelection(-1,-1);
} }
if ( event.GetId() != m_combo->GetId() ) // Send focus indication to parent.
{ // NB: This is needed for cases where the textctrl gets focus
// Add textctrl set focus events as combo set focus events // instead of its parent. While this may trigger multiple
// NOTE: Simply changing the event and skipping didn't seem // wxEVT_SET_FOCUSes (since m_text->SetFocus is called
// to do the trick. // from combo's focus event handler), they should be quite
wxFocusEvent evt2(wxEVT_SET_FOCUS,m_combo->GetId()); // harmless.
evt2.SetEventObject(m_combo); wxFocusEvent evt2(wxEVT_SET_FOCUS,m_combo->GetId());
m_combo->GetEventHandler()->ProcessEvent(evt2); evt2.SetEventObject(m_combo);
} m_combo->GetEventHandler()->ProcessEvent(evt2);
else
event.Skip();
event.Skip(); event.Skip();
} }
@@ -633,6 +602,7 @@ BEGIN_EVENT_TABLE(wxComboCtrlBase, wxControl)
EVT_SET_FOCUS(wxComboCtrlBase::OnFocusEvent) EVT_SET_FOCUS(wxComboCtrlBase::OnFocusEvent)
EVT_KILL_FOCUS(wxComboCtrlBase::OnFocusEvent) EVT_KILL_FOCUS(wxComboCtrlBase::OnFocusEvent)
//EVT_BUTTON(wxID_ANY,wxComboCtrlBase::OnButtonClickEvent) //EVT_BUTTON(wxID_ANY,wxComboCtrlBase::OnButtonClickEvent)
EVT_KEY_DOWN(wxComboCtrlBase::OnKeyEvent)
EVT_TEXT_ENTER(wxID_ANY,wxComboCtrlBase::OnTextCtrlEvent) EVT_TEXT_ENTER(wxID_ANY,wxComboCtrlBase::OnTextCtrlEvent)
EVT_SYS_COLOUR_CHANGED(wxComboCtrlBase::OnSysColourChanged) EVT_SYS_COLOUR_CHANGED(wxComboCtrlBase::OnSysColourChanged)
END_EVENT_TABLE() END_EVENT_TABLE()
@@ -652,7 +622,6 @@ void wxComboCtrlBase::Init()
m_text = (wxTextCtrl*) NULL; m_text = (wxTextCtrl*) NULL;
m_popupInterface = (wxComboPopup*) NULL; m_popupInterface = (wxComboPopup*) NULL;
m_extraEvtHandler = (wxEvtHandler*) NULL;
m_popupExtraHandler = (wxEvtHandler*) NULL; m_popupExtraHandler = (wxEvtHandler*) NULL;
m_textEvtHandler = (wxEvtHandler*) NULL; m_textEvtHandler = (wxEvtHandler*) NULL;
@@ -718,17 +687,13 @@ bool wxComboCtrlBase::Create(wxWindow *parent,
return true; return true;
} }
void wxComboCtrlBase::InstallInputHandlers( bool alsoTextCtrl ) void wxComboCtrlBase::InstallInputHandlers()
{ {
if ( m_text && alsoTextCtrl ) if ( m_text )
{ {
m_textEvtHandler = new wxComboBoxExtraInputHandler(this); m_textEvtHandler = new wxComboBoxExtraInputHandler(this);
m_text->PushEventHandler(m_textEvtHandler); m_text->PushEventHandler(m_textEvtHandler);
} }
wxComboBoxExtraInputHandler* inputHandler = new wxComboBoxExtraInputHandler(this);
PushEventHandler(inputHandler);
m_extraEvtHandler = inputHandler;
} }
void void
@@ -774,13 +739,10 @@ wxComboCtrlBase::~wxComboCtrlBase()
DestroyPopup(); DestroyPopup();
RemoveEventHandler(m_extraEvtHandler);
if ( m_text ) if ( m_text )
m_text->RemoveEventHandler(m_textEvtHandler); m_text->RemoveEventHandler(m_textEvtHandler);
delete m_textEvtHandler; delete m_textEvtHandler;
delete m_extraEvtHandler;
} }
@@ -1476,23 +1438,68 @@ void wxComboCtrlBase::HandleNormalMouseEvent( wxMouseEvent& event )
event.Skip(); event.Skip();
} }
void wxComboCtrlBase::OnFocusEvent( wxFocusEvent& ) void wxComboCtrlBase::OnKeyEvent(wxKeyEvent& event)
{ {
// First click is the first part of double-click if ( IsPopupShown() )
// 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 )
{ {
m_text->SetFocus(); // pass it to the popped up control
GetPopupControl()->GetControl()->AddPendingEvent(event);
} }
else else // no popup
// no need to check for m_widthCustomPaint - that {
// area never gets special handling when selected int keycode = event.GetKeyCode();
// (in writable mode, that is)
Refresh(); 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 && m_text != ::wxWindow::FindFocus() )
m_text->SetFocus();
}
Refresh();
} }
void wxComboCtrlBase::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event)) void wxComboCtrlBase::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))

View File

@@ -161,7 +161,7 @@ bool wxGenericComboControl::Create(wxWindow *parent,
CreateTextCtrl( wxNO_BORDER, validator ); CreateTextCtrl( wxNO_BORDER, validator );
// Add keyboard input handlers for main control and textctrl // Add keyboard input handlers for main control and textctrl
InstallInputHandlers( true ); InstallInputHandlers();
// Set background // Set background
SetBackgroundStyle( wxBG_STYLE_CUSTOM ); // for double-buffering 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__ #ifdef __WXUNIVERSAL__
bool wxGenericComboControl::PerformAction(const wxControlAction& action, bool wxGenericComboControl::PerformAction(const wxControlAction& action,

View File

@@ -410,17 +410,24 @@ void wxVListBoxComboPopup::OnLeftClick(wxMouseEvent& WXUNUSED(event))
void wxVListBoxComboPopup::OnKey(wxKeyEvent& event) void wxVListBoxComboPopup::OnKey(wxKeyEvent& event)
{ {
// Select item if ENTER is pressed // Hide popup if certain key or key combination was pressed
if ( event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER ) if ( m_combo->IsKeyPopupToggle(event) )
{
DismissWithEvent();
}
// Hide popup if ESC is pressed
else if ( event.GetKeyCode() == WXK_ESCAPE )
{ {
StopPartialCompletion(); StopPartialCompletion();
Dismiss(); 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 else
{ {
int comboStyle = m_combo->GetWindowStyle(); int comboStyle = m_combo->GetWindowStyle();

View File

@@ -135,7 +135,7 @@ bool wxComboCtrl::Create(wxWindow *parent,
CreateTextCtrl( wxNO_BORDER, validator ); CreateTextCtrl( wxNO_BORDER, validator );
// Add keyboard input handlers for main control and textctrl // Add keyboard input handlers for main control and textctrl
InstallInputHandlers( true ); InstallInputHandlers();
// Prepare background for double-buffering // Prepare background for double-buffering
SetBackgroundStyle( wxBG_STYLE_CUSTOM ); SetBackgroundStyle( wxBG_STYLE_CUSTOM );
@@ -529,5 +529,30 @@ wxCoord wxComboCtrl::GetNativeTextIndent() const
return NATIVE_TEXT_INDENT_CLASSIC; 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 #endif // wxUSE_COMBOCTRL