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:
@@ -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
|
||||||
|
@@ -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__)
|
||||||
|
@@ -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; }
|
||||||
|
|
||||||
|
@@ -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))
|
||||||
|
@@ -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,
|
||||||
|
@@ -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();
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user