Fixed issues for new ComboBoxes:

* Navigation using Up/Down Arrows.
* Selection of first element which is started from input letter.
* OSX specific: Revert slider step to 1.
* Linux specific: Implemented possibility to use Up/Down & Left/Right arrows to navigate inside DropDown.
This commit is contained in:
YuSanka 2023-10-26 15:43:40 +02:00
parent 38b75d1ad2
commit 8bd5243b2b
3 changed files with 96 additions and 17 deletions

View File

@ -61,7 +61,10 @@ ComboBox::ComboBox(wxWindow * parent,
for (int i = 0; i < n; ++i) Append(choices[i]); for (int i = 0; i < n; ++i) Append(choices[i]);
} }
int ComboBox::GetSelection() const { return drop.GetSelection(); } int ComboBox::GetSelection() const
{
return drop.GetSelection();
}
void ComboBox::SetSelection(int n) void ComboBox::SetSelection(int n)
{ {
@ -233,6 +236,11 @@ wxBitmap ComboBox::GetItemBitmap(unsigned int n)
return icons[n].GetBitmapFor(m_parent); return icons[n].GetBitmapFor(m_parent);
} }
void ComboBox::OnKeyDown(wxKeyEvent &event)
{
keyDown(event);
}
int ComboBox::DoInsertItems(const wxArrayStringsAdapter &items, int ComboBox::DoInsertItems(const wxArrayStringsAdapter &items,
unsigned int pos, unsigned int pos,
void ** clientData, void ** clientData,
@ -290,10 +298,15 @@ void ComboBox::keyDown(wxKeyEvent& event)
{ {
int key_code = event.GetKeyCode(); int key_code = event.GetKeyCode();
switch (key_code) { switch (key_code) {
#ifndef __WXOSX__
case WXK_RETURN: case WXK_RETURN:
if (drop_down) { if (drop_down) {
drop.DismissAndNotify(); drop.DismissAndNotify();
wxCommandEvent e(wxEVT_COMBOBOX);
e.SetEventObject(this);
e.SetId(GetId());
e.SetInt(GetSelection());
GetEventHandler()->ProcessEvent(e);
} else if (drop.HasDismissLongTime()) { } else if (drop.HasDismissLongTime()) {
drop.autoPosition(); drop.autoPosition();
drop_down = true; drop_down = true;
@ -302,7 +315,6 @@ void ComboBox::keyDown(wxKeyEvent& event)
GetEventHandler()->ProcessEvent(e); GetEventHandler()->ProcessEvent(e);
} }
break; break;
#endif
case WXK_UP: case WXK_UP:
case WXK_DOWN: case WXK_DOWN:
case WXK_LEFT: case WXK_LEFT:
@ -314,20 +326,22 @@ void ComboBox::keyDown(wxKeyEvent& event)
} else { } else {
break; break;
} }
{
wxCommandEvent e(wxEVT_COMBOBOX);
e.SetEventObject(this);
e.SetId(GetId());
e.SetInt(GetSelection());
GetEventHandler()->ProcessEvent(e);
}
break; break;
case WXK_TAB: case WXK_TAB:
HandleAsNavigationKey(event); HandleAsNavigationKey(event);
break; break;
default: default: {
if (drop.IsShown() && HasFlag(wxCB_READONLY)) {
for (size_t n = 0; n < texts.size(); n++) {
if (texts[n].StartsWith(wxString(static_cast<char>(key_code)))) {
SetSelection(int(n));
break;
}
}
}
event.Skip(); event.Skip();
break; break;
}
} }
} }

View File

@ -66,6 +66,8 @@ public:
wxBitmap GetItemBitmap(unsigned int n); wxBitmap GetItemBitmap(unsigned int n);
void OnKeyDown(wxKeyEvent& event);
protected: protected:
virtual int DoInsertItems(const wxArrayStringsAdapter &items, virtual int DoInsertItems(const wxArrayStringsAdapter &items,
unsigned int pos, unsigned int pos,

View File

@ -1,4 +1,5 @@
#include "DropDown.hpp" #include "DropDown.hpp"
#include "ComboBox.hpp"
#include "../GUI_App.hpp" #include "../GUI_App.hpp"
#include "../OptionsGroup.hpp" #include "../OptionsGroup.hpp"
@ -60,10 +61,60 @@ DropDown::DropDown(wxWindow * parent,
Create(parent, style); Create(parent, style);
} }
#ifdef __WXGTK__
static gint gtk_popup_key_press (GtkWidget *widget, GdkEvent *gdk_event, wxPopupWindow* win )
{
// Ignore events sent out before we connected to the signal
if (win->m_time >= ((GdkEventKey*)gdk_event)->time)
return FALSE;
GtkWidget *child = gtk_get_event_widget (gdk_event);
/* We don't ask for button press events on the grab widget, so
* if an event is reported directly to the grab widget, it must
* be on a window outside the application (and thus we remove
* the popup window). Otherwise, we check if the widget is a child
* of the grab widget, and only remove the popup window if it
* is not. */
if (child != widget) {
while (child) {
if (child == widget)
return FALSE;
child = gtk_widget_get_parent(child);
}
}
gchar* keyval = gdk_keyval_name(((GdkEventKey*)gdk_event)->keyval);
const long keyCode = strcmp(keyval, "Up") == 0 ? WXK_UP :
strcmp(keyval, "Down") == 0 ? WXK_DOWN :
strcmp(keyval, "Left") == 0 ? WXK_LEFT :
strcmp(keyval, "Right") == 0 ? WXK_RIGHT :
strcmp(keyval, "Return") == 0 ? WXK_RETURN : WXK_NONE;
if (keyCode != WXK_NONE) {
wxKeyEvent event( wxEVT_KEY_DOWN, win->GetId());
event.m_keyCode = keyCode;
event.SetEventObject( win );
(void)win->HandleWindowEvent( event );
}
return TRUE;
}
#endif
void DropDown::Create(wxWindow * parent, void DropDown::Create(wxWindow * parent,
long style) long style)
{ {
wxPopupTransientWindow::Create(parent); wxPopupTransientWindow::Create(parent);
#ifdef __WXGTK__
g_signal_connect (m_widget, "key_press_event", G_CALLBACK (gtk_popup_key_press), this);
Bind(wxEVT_KEY_DOWN, [parent](wxKeyEvent &e) {
if (ComboBox* cb = dynamic_cast<ComboBox*>(parent))
cb->OnKeyDown(e);
});
#endif
if (!wxOSX) SetBackgroundStyle(wxBG_STYLE_PAINT); if (!wxOSX) SetBackgroundStyle(wxBG_STYLE_PAINT);
state_handler.attach({&border_color, &text_color, &selector_border_color, &selector_background_color}); state_handler.attach({&border_color, &text_color, &selector_border_color, &selector_background_color});
state_handler.update_binds(); state_handler.update_binds();
@ -95,6 +146,8 @@ void DropDown::SetSelection(int n)
n = -1; n = -1;
if (selection == n) return; if (selection == n) return;
selection = n; selection = n;
if (IsShown())
autoPosition();
paintNow(); paintNow();
} }
@ -212,7 +265,11 @@ void DropDown::SetTransparentBG(wxDC& dc, wxWindow* win)
} }
constexpr int slider_width = 12; constexpr int slider_width = 12;
#ifdef __WXOSX__
constexpr int slider_step = 1;
#else
constexpr int slider_step = 5; constexpr int slider_step = 5;
#endif
constexpr int items_padding = 2; constexpr int items_padding = 2;
/* /*
@ -423,14 +480,14 @@ void DropDown::autoPosition()
if (use_content_width && texts.size() <= 15) size.x += 6; if (use_content_width && texts.size() <= 15) size.x += 6;
size.y = drect.GetBottom() - GetPosition().y - 10; size.y = drect.GetBottom() - GetPosition().y - 10;
wxWindow::SetSize(size); wxWindow::SetSize(size);
if (selection >= 0) {
if (offset.y + rowSize.y * (selection + 1) > size.y)
offset.y = size.y - rowSize.y * (selection + 1);
else if (offset.y + rowSize.y * selection < 0)
offset.y = -rowSize.y * selection;
}
} }
} }
if (selection >= 0) {
if (offset.y + rowSize.y * (selection + 1) > size.y)
offset.y = size.y - rowSize.y * (selection + 3);
else if (offset.y + rowSize.y * selection < 0)
offset.y = -rowSize.y * selection;
}
} }
void DropDown::mouseDown(wxMouseEvent& event) void DropDown::mouseDown(wxMouseEvent& event)
@ -461,6 +518,10 @@ void DropDown::mouseReleased(wxMouseEvent& event)
if (HasCapture()) if (HasCapture())
ReleaseMouse(); ReleaseMouse();
if (hover_item >= 0) { // not moved if (hover_item >= 0) { // not moved
#ifdef __WXOSX__
// To avoid cases, when some dialog appears after item selection, but DropDown is still shown
Hide();
#endif
sendDropDownEvent(); sendDropDownEvent();
DismissAndNotify(); DismissAndNotify();
} }
@ -507,6 +568,8 @@ void DropDown::mouseMove(wxMouseEvent &event)
void DropDown::mouseWheelMoved(wxMouseEvent &event) void DropDown::mouseWheelMoved(wxMouseEvent &event)
{ {
if (event.GetWheelRotation() == 0)
return;
auto delta = event.GetWheelRotation() > 0 ? rowSize.y : -rowSize.y; auto delta = event.GetWheelRotation() > 0 ? rowSize.y : -rowSize.y;
wxPoint pt2 = offset + wxPoint{0, slider_step * delta}; wxPoint pt2 = offset + wxPoint{0, slider_step * delta};
int text_size = int(texts.size()); int text_size = int(texts.size());