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
|
||||
//
|
||||
|
||||
// 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
|
||||
|
@@ -65,6 +65,8 @@ public:
|
||||
|
||||
virtual ~wxGenericComboControl();
|
||||
|
||||
virtual bool IsKeyPopupToggle(const wxKeyEvent& event) const;
|
||||
|
||||
static int GetFeatures() { return wxComboCtrlFeatures::All; }
|
||||
|
||||
#if defined(__WXUNIVERSAL__)
|
||||
|
@@ -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; }
|
||||
|
||||
|
@@ -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();
|
||||
}
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -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();
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user