diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -863,55 +863,31 @@ public: EventState OnKeyPress(WChar key, uint16 keycode) override { - switch (keycode) { - case WKC_UP: - /* scroll up by one */ - if (this->list_pos > 0) this->list_pos--; - break; - case WKC_DOWN: - /* scroll down by one */ - if (this->list_pos < (int)this->content.size() - 1) this->list_pos++; - break; - case WKC_PAGEUP: - /* scroll up a page */ - this->list_pos = (this->list_pos < this->vscroll->GetCapacity()) ? 0 : this->list_pos - this->vscroll->GetCapacity(); - break; - case WKC_PAGEDOWN: - /* scroll down a page */ - this->list_pos = std::min(this->list_pos + this->vscroll->GetCapacity(), (int)this->content.size() - 1); - break; - case WKC_HOME: - /* jump to beginning */ - this->list_pos = 0; - break; - case WKC_END: - /* jump to end */ - this->list_pos = (int)this->content.size() - 1; - break; + if (this->vscroll->UpdateListPositionOnKeyPress(this->list_pos, keycode) == ES_NOT_HANDLED) { + switch (keycode) { + case WKC_SPACE: + case WKC_RETURN: + if (keycode == WKC_RETURN || !IsWidgetFocused(WID_NCL_FILTER)) { + if (this->selected != nullptr) { + _network_content_client.ToggleSelectedState(this->selected); + this->content.ForceResort(); + this->InvalidateData(); + } + if (this->filter_data.types.any()) { + this->content.ForceRebuild(); + this->InvalidateData(); + } + return ES_HANDLED; + } + /* space is pressed and filter is focused. */ + FALLTHROUGH; - case WKC_SPACE: - case WKC_RETURN: - if (keycode == WKC_RETURN || !IsWidgetFocused(WID_NCL_FILTER)) { - if (this->selected != nullptr) { - _network_content_client.ToggleSelectedState(this->selected); - this->content.ForceResort(); - this->InvalidateData(); - } - if (this->filter_data.types.any()) { - this->content.ForceRebuild(); - this->InvalidateData(); - } - return ES_HANDLED; - } - /* space is pressed and filter is focused. */ - FALLTHROUGH; - - default: - return ES_NOT_HANDLED; + default: + return ES_NOT_HANDLED; + } } if (this->content.size() == 0) { - this->list_pos = 0; // above stuff may result in "-1". if (this->UpdateFilterState()) { this->content.ForceRebuild(); this->InvalidateData(); diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -66,8 +66,8 @@ void UpdateNetworkGameWindow() } typedef GUIList GUIGameServerList; -typedef uint16 ServerListPosition; -static const ServerListPosition SLP_INVALID = 0xFFFF; +typedef int ServerListPosition; +static const ServerListPosition SLP_INVALID = -1; /** Full blown container to make it behave exactly as we want :) */ class NWidgetServerListHeader : public NWidgetContainer { @@ -771,39 +771,8 @@ public: EventState state = ES_NOT_HANDLED; /* handle up, down, pageup, pagedown, home and end */ - if (keycode == WKC_UP || keycode == WKC_DOWN || keycode == WKC_PAGEUP || keycode == WKC_PAGEDOWN || keycode == WKC_HOME || keycode == WKC_END) { - if (this->servers.size() == 0) return ES_HANDLED; - switch (keycode) { - case WKC_UP: - /* scroll up by one */ - if (this->list_pos == SLP_INVALID) return ES_HANDLED; - if (this->list_pos > 0) this->list_pos--; - break; - case WKC_DOWN: - /* scroll down by one */ - if (this->list_pos == SLP_INVALID) return ES_HANDLED; - if (this->list_pos < this->servers.size() - 1) this->list_pos++; - break; - case WKC_PAGEUP: - /* scroll up a page */ - if (this->list_pos == SLP_INVALID) return ES_HANDLED; - this->list_pos = (this->list_pos < this->vscroll->GetCapacity()) ? 0 : this->list_pos - this->vscroll->GetCapacity(); - break; - case WKC_PAGEDOWN: - /* scroll down a page */ - if (this->list_pos == SLP_INVALID) return ES_HANDLED; - this->list_pos = std::min(this->list_pos + this->vscroll->GetCapacity(), (int)this->servers.size() - 1); - break; - case WKC_HOME: - /* jump to beginning */ - this->list_pos = 0; - break; - case WKC_END: - /* jump to end */ - this->list_pos = (ServerListPosition)this->servers.size() - 1; - break; - default: NOT_REACHED(); - } + if (this->vscroll->UpdateListPositionOnKeyPress(this->list_pos, keycode) == ES_HANDLED) { + if (this->list_pos == SLP_INVALID) return ES_HANDLED; this->server = this->servers[this->list_pos]; diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -1318,42 +1318,8 @@ struct NewGRFWindow : public Window, New { if (!this->editable) return ES_NOT_HANDLED; - switch (keycode) { - case WKC_UP: - /* scroll up by one */ - if (this->avail_pos > 0) this->avail_pos--; - break; - - case WKC_DOWN: - /* scroll down by one */ - if (this->avail_pos < (int)this->avails.size() - 1) this->avail_pos++; - break; - - case WKC_PAGEUP: - /* scroll up a page */ - this->avail_pos = (this->avail_pos < this->vscroll2->GetCapacity()) ? 0 : this->avail_pos - this->vscroll2->GetCapacity(); - break; + if (this->vscroll2->UpdateListPositionOnKeyPress(this->avail_pos, keycode) == ES_NOT_HANDLED) return ES_NOT_HANDLED; - case WKC_PAGEDOWN: - /* scroll down a page */ - this->avail_pos = std::min(this->avail_pos + this->vscroll2->GetCapacity(), (int)this->avails.size() - 1); - break; - - case WKC_HOME: - /* jump to beginning */ - this->avail_pos = 0; - break; - - case WKC_END: - /* jump to end */ - this->avail_pos = (uint)this->avails.size() - 1; - break; - - default: - return ES_NOT_HANDLED; - } - - if (this->avails.size() == 0) this->avail_pos = -1; if (this->avail_pos >= 0) { this->active_sel = nullptr; DeleteWindowByClass(WC_GRF_PARAMETERS); diff --git a/src/widget.cpp b/src/widget.cpp --- a/src/widget.cpp +++ b/src/widget.cpp @@ -1975,6 +1975,66 @@ int Scrollbar::GetScrolledRowFromWidget( } /** + * Update the given list position as if it were on this scroll bar when the given keycode was pressed. + * This does not update the actual position of this scroll bar, that is left to the caller. It does, + * however use the capacity and count of the scroll bar for the bounds and amount to scroll. + * + * When the count is 0 or the return is ES_NOT_HANDLED, then the position is not updated. + * With WKC_UP and WKC_DOWN the position goes one up or down respectively. + * With WKC_PAGEUP and WKC_PAGEDOWN the position goes one capacity up or down respectively. + * With WKC_HOME the first position is selected and with WKC_END the last position is selected. + * This function ensures that pos is in the range [0..count). + * @param list_position The current position in the list. + * @param key_code The pressed key code. + * @return ES_NOT_HANDLED when another key than the 6 specific keys was pressed, otherwise ES_HANDLED. + */ +EventState Scrollbar::UpdateListPositionOnKeyPress(int &list_position, uint16 keycode) const +{ + int new_pos = list_position; + switch (keycode) { + case WKC_UP: + /* scroll up by one */ + new_pos--; + break; + + case WKC_DOWN: + /* scroll down by one */ + new_pos++; + break; + + case WKC_PAGEUP: + /* scroll up a page */ + new_pos -= this->GetCapacity(); + break; + + case WKC_PAGEDOWN: + /* scroll down a page */ + new_pos += this->GetCapacity(); + break; + + case WKC_HOME: + /* jump to beginning */ + new_pos = 0; + break; + + case WKC_END: + /* jump to end */ + new_pos = this->GetCount() - 1; + break; + + default: + return ES_NOT_HANDLED; + } + + /* If there are no elements, there is nothing to scroll/update. */ + if (this->GetCount() != 0) { + list_position = Clamp(new_pos, 0, this->GetCount() - 1); + } + return ES_HANDLED; +} + + +/** * Set capacity of visible elements from the size and resize properties of a widget. * @param w Window. * @param widget Widget with size and resize properties. diff --git a/src/widget_type.h b/src/widget_type.h --- a/src/widget_type.h +++ b/src/widget_type.h @@ -749,6 +749,7 @@ public: } int GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding = 0, int line_height = -1) const; + EventState UpdateListPositionOnKeyPress(int &list_position, uint16 keycode) const; }; /**