Skip to content

Commit

Permalink
Scroll the selection box when navigating <select> options with cont…
Browse files Browse the repository at this point in the history
…roller/keyboard (#566)

And scroll the selected option into view when opening the selection box.

Further, add ability to programmatically show or hide the selection box.

Co-authored-by: Michael Ragazzon <michael.ragazzon@gmail.com>
  • Loading branch information
Paril and mikke89 authored Oct 31, 2024
1 parent 2f76544 commit ad62159
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 28 deletions.
7 changes: 7 additions & 0 deletions Include/RmlUi/Core/Elements/ElementFormControlSelect.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ class RMLUICORE_API ElementFormControlSelect : public ElementFormControl {

/// Removes all options from the select control.
void RemoveAll();

/// Show the selection box.
void ShowSelectBox();
/// Hide the selection box.
void HideSelectBox();
/// Check whether the select box is opened or not.
bool IsSelectBoxVisible();

protected:
/// Moves all children to be under control of the widget.
Expand Down
15 changes: 15 additions & 0 deletions Source/Core/Elements/ElementFormControlSelect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,21 @@ void ElementFormControlSelect::RemoveAll()
widget->ClearOptions();
}

void ElementFormControlSelect::ShowSelectBox()
{
widget->ShowSelectBox();
}

void ElementFormControlSelect::HideSelectBox()
{
widget->HideSelectBox();
}

bool ElementFormControlSelect::IsSelectBoxVisible()
{
return widget->IsSelectBoxVisible();
}

void ElementFormControlSelect::OnUpdate()
{
ElementFormControl::OnUpdate();
Expand Down
70 changes: 45 additions & 25 deletions Source/Core/Elements/WidgetDropDown.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ WidgetDropDown::WidgetDropDown(ElementFormControl* element)
lock_selection = false;
selection_dirty = false;
box_layout_dirty = false;
box_opened_since_last_format = false;
value_rml_dirty = false;
value_layout_dirty = false;
box_visible = false;
Expand Down Expand Up @@ -230,6 +231,19 @@ void WidgetDropDown::OnRender()
selection_element->SetOffset(Vector2f(offset_x, offset_y), parent_element);
}

int selection = GetSelection();

// Scroll selected element into view, if we have one
if (selection != -1)
{
ScrollIntoViewOptions scroll_options = {
box_opened_since_last_format ? ScrollAlignment::Center : ScrollAlignment::Nearest,
ScrollAlignment::Nearest,
ScrollBehavior::Instant,
};
GetOption(selection)->ScrollIntoView(scroll_options);
}
box_opened_since_last_format = false;
box_layout_dirty = false;
}

Expand Down Expand Up @@ -502,7 +516,7 @@ void WidgetDropDown::ProcessEvent(Event& event)
SetSelection(current_element);
event.StopPropagation();

ShowSelectBox(false);
HideSelectBox();
parent_element->Focus();
}
}
Expand All @@ -523,9 +537,9 @@ void WidgetDropDown::ProcessEvent(Event& event)
}

if (selection_element->GetComputedValues().visibility() == Style::Visibility::Hidden)
ShowSelectBox(true);
ShowSelectBox();
else
ShowSelectBox(false);
HideSelectBox();
}
}
break;
Expand All @@ -542,7 +556,7 @@ void WidgetDropDown::ProcessEvent(Event& event)
{
if (event.GetTargetElement() == parent_element)
{
ShowSelectBox(false);
HideSelectBox();
value_element->SetPseudoClass("focus", false);
button_element->SetPseudoClass("focus", false);
}
Expand Down Expand Up @@ -604,36 +618,42 @@ void WidgetDropDown::ProcessEvent(Event& event)
}

if (!scrolls_selection_box)
ShowSelectBox(false);
HideSelectBox();
}
}
break;
default: break;
}
}

void WidgetDropDown::ShowSelectBox(bool show)
void WidgetDropDown::ShowSelectBox()
{
if (show)
{
selection_element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Visible));
selection_element->SetPseudoClass("checked", true);
value_element->SetPseudoClass("checked", true);
button_element->SetPseudoClass("checked", true);
box_layout_dirty = true;
AttachScrollEvent();
}
else
{
selection_element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden));
selection_element->RemoveProperty(PropertyId::Height);
selection_element->SetPseudoClass("checked", false);
value_element->SetPseudoClass("checked", false);
button_element->SetPseudoClass("checked", false);
DetachScrollEvent();
}
selection_element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Visible));
selection_element->SetPseudoClass("checked", true);
value_element->SetPseudoClass("checked", true);
button_element->SetPseudoClass("checked", true);
box_layout_dirty = true;
box_opened_since_last_format = true;
AttachScrollEvent();

box_visible = show;
box_visible = true;
}

void WidgetDropDown::HideSelectBox()
{
selection_element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden));
selection_element->RemoveProperty(PropertyId::Height);
selection_element->SetPseudoClass("checked", false);
value_element->SetPseudoClass("checked", false);
button_element->SetPseudoClass("checked", false);
DetachScrollEvent();

box_visible = false;
}

bool WidgetDropDown::IsSelectBoxVisible()
{
return box_visible;
}

} // namespace Rml
11 changes: 8 additions & 3 deletions Source/Core/Elements/WidgetDropDown.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,14 @@ class WidgetDropDown : public EventListener {
/// Processes the incoming event.
void ProcessEvent(Event& event) override;

private:
// Shows or hides the selection box.
void ShowSelectBox(bool show);
/// Shows the selection box.
void ShowSelectBox();
/// Hides the selection box.
void HideSelectBox();
/// Check whether the select box is visible or not.
bool IsSelectBoxVisible();

private:
void AttachScrollEvent();
void DetachScrollEvent();

Expand All @@ -120,6 +124,7 @@ class WidgetDropDown : public EventListener {
bool value_rml_dirty;
bool value_layout_dirty;
bool box_layout_dirty;
bool box_opened_since_last_format;
bool box_visible;
};

Expand Down

0 comments on commit ad62159

Please sign in to comment.