diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5f7847ff8a..e015544b5e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -378,6 +378,8 @@ add_files(
screenshot_gui.h
screenshot.cpp
screenshot.h
+ selector_gui.cpp
+ selector_gui.h
settings.cpp
settings_cmd.h
settings_func.h
diff --git a/src/lang/english.txt b/src/lang/english.txt
index 87a8d3c594..65fd0c6cd8 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -619,18 +619,18 @@ STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION :{WHITE}Cargo Pa
STR_GRAPH_CARGO_PAYMENT_RATES_DAYS :{TINY_FONT}{BLACK}Days in transit
STR_GRAPH_CARGO_PAYMENT_RATES_SECONDS :{TINY_FONT}{BLACK}Seconds in transit
STR_GRAPH_CARGO_PAYMENT_RATES_TITLE :{TINY_FONT}{BLACK}Payment for delivering 10 units (or 10,000 litres) of cargo a distance of 20 squares
-STR_GRAPH_CARGO_ENABLE_ALL :{TINY_FONT}{BLACK}Enable all
-STR_GRAPH_CARGO_DISABLE_ALL :{TINY_FONT}{BLACK}Disable all
-STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL :{BLACK}Display all cargoes on the cargo payment rates graph
-STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}Display no cargoes on the cargo payment rates graph
-STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Toggle graph of this cargo type
-STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING}
+
+# Selector widget
+STR_SELECTOR_WIDGET_ALL :{BLACK}All
+STR_SELECTOR_WIDGET_NONE :{BLACK}None
+STR_SELECTOR_WIDGET_TOOLTIP_ALL :{BLACK}Display all of the items in the list
+STR_SELECTOR_WIDGET_TOOLTIP_NONE :{BLACK}Display none of the items in the list
STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Show detailed performance ratings
# Graph key window
STR_GRAPH_KEY_CAPTION :{WHITE}Key to company graphs
-STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP :{BLACK}Toggle graph of this company
+STR_GRAPH_CARGO_KEY_CAPTION :{WHITE}Key to cargo graphs
# Company league window
STR_COMPANY_LEAGUE_TABLE_CAPTION :{WHITE}Company League Table
diff --git a/src/selector_gui.cpp b/src/selector_gui.cpp
new file mode 100644
index 0000000000..574c2fa918
--- /dev/null
+++ b/src/selector_gui.cpp
@@ -0,0 +1,375 @@
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
+ */
+
+/** @file selector_gui.cpp A composable selector widget. */
+
+#include "stdafx.h"
+#include "company_base.h"
+#include "company_gui.h"
+#include "strings_func.h"
+#include "table/sprites.h"
+#include "selector_gui.h"
+#include "widget_type.h"
+#include "widgets/selector_widget.h"
+#include "zoom_func.h"
+
+#include "safeguards.h"
+
+/**
+ * Create a new NWidgetBase with all the widgets needed by the SelectorWidget widget
+ * This function is made to be passed in NWidgetFunction, when creating UI for a parent window
+ * @see NWidgetFunction
+ */
+std::unique_ptr SelectorWidget::MakeSelectorWidgetUI()
+{
+ static constexpr NWidgetPart widget_ui[] = {
+ NWidget(WWT_PANEL, COLOUR_BROWN),
+ NWidget(WWT_EDITBOX, COLOUR_BROWN, WID_SELECTOR_EDITBOX), SetFill(1, 0), SetResize(1, 0), SetPadding(2),
+ SetDataTip(STR_LIST_FILTER_TOOLTIP, STR_LIST_FILTER_TOOLTIP),
+ EndContainer(),
+ NWidget(NWID_VERTICAL),
+ NWidget(NWID_HORIZONTAL),
+ NWidget(WWT_MATRIX, COLOUR_BROWN, WID_SELECTOR_MATRIX),
+ SetScrollbar(WID_SELECTOR_SCROLLBAR), SetResize(1, 1), SetMatrixDataTip(1, 0, STR_NULL), SetFill(1, 1),
+ NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_SELECTOR_SCROLLBAR),
+ EndContainer(),
+ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
+ NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SELECTOR_SHOWALL),
+ SetDataTip(STR_SELECTOR_WIDGET_ALL, STR_SELECTOR_WIDGET_TOOLTIP_ALL), SetResize(1, 0), SetFill(1, 0),
+ NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SELECTOR_HIDEALL),
+ SetDataTip(STR_SELECTOR_WIDGET_NONE, STR_SELECTOR_WIDGET_TOOLTIP_NONE), SetResize(1, 0), SetFill(1, 0),
+ NWidget(WWT_RESIZEBOX, COLOUR_BROWN, WID_SELECTOR_RESIZE), SetDataTip(RWV_SHOW_BEVEL, STR_TOOLTIP_RESIZE), SetResize(0, 0),
+ EndContainer(),
+ EndContainer(),
+ };
+ return MakeNWidgets(widget_ui, nullptr);
+}
+
+/**
+ * Selector widget initialization function
+ * This function is meant to be called after CreateNestedTree() of the parent window
+ *
+ * @param w The parent window of this widget.
+ */
+void SelectorWidget::Init(Window *w)
+{
+ this->parent_window = w;
+ this->vscroll = w->GetScrollbar(WID_SELECTOR_SCROLLBAR);
+ assert(this->vscroll != nullptr);
+ RebuildList();
+ w->querystrings[WID_SELECTOR_EDITBOX] = &this->editbox;
+ this->vscroll->SetCount(this->filtered_list.size());
+ this->vscroll->SetCapacityFromWidget(w, WID_SELECTOR_MATRIX);
+}
+
+/**
+ * Selector widget's OnClick event handler
+ * This function is meant to be called from the parent's window's OnClick
+ * Event handler
+ *
+ * @param pt The click coordinate.
+ * @param widget The id of the targeted widget.
+ * @param click_count The number of clicks.
+ *
+ * All of these parameters should be passed straight from the parent's window's OnClick
+ * Event handler, without any changes, or conditional checks
+ *
+ * @see Window::OnClick()
+ */
+void SelectorWidget::OnClick(Point pt, WidgetID widget, [[maybe_unused]]int click_count)
+{
+ switch (widget) {
+ case WID_SELECTOR_HIDEALL:
+ for (uint i = 0; i < this->shown.size(); i++) {
+ this->shown[i] = false;
+ }
+ this->OnChanged();
+ this->parent_window->InvalidateData(0, true);
+ break;
+
+ case WID_SELECTOR_SHOWALL:
+ for (uint i = 0; i < this->shown.size(); i++) {
+ this->shown[i] = true;
+ }
+ this->OnChanged();
+ this->parent_window->InvalidateData(0, true);
+ break;
+
+ case WID_SELECTOR_MATRIX: {
+ size_t pos = vscroll->GetScrolledRowFromWidget(pt.y, this->parent_window, widget);
+
+ /* Check if the click was out of range. */
+ if (pos >= filtered_list.size()) return;
+ int id = this->filtered_list[pos];
+
+ this->shown[id].flip();
+ this->OnChanged();
+ this->parent_window->InvalidateData(0, true);
+ break;
+ }
+ }
+}
+
+void SelectorWidget::OnMouseOver(Point pt, WidgetID widget)
+{
+ if (widget != WID_SELECTOR_MATRIX) return;
+
+ auto it = vscroll->GetScrolledItemFromWidget(this->filtered_list, pt.y, this->parent_window, widget);
+ /* Check if the hover was out of range. */
+ if (it == this->filtered_list.end()) return;
+
+ /* Check if the selection actually changed. */
+ if (*it == this->selected_id) return;
+
+ this->selected_id = *it;
+
+ this->OnChanged();
+ this->parent_window->InvalidateData(0, true);
+}
+
+/**
+ * Selector widget's OnInvalidateData event handler
+ * This function is meant to be called from the parent's window's OnInvalidateData
+ * Event handler. This function will do nothing when runnning ouside of the gui scope.
+ *
+ * @param data Information about the changed data.
+ * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
+ *
+ * All of these parameters should be passed straight from the parent's window's OnInvalidateData
+ * Event handler, without any changes, or conditional checks
+ *
+ * @see Window::OnInvalidateData()
+ */
+void SelectorWidget::OnInvalidateData([[maybe_unused]] int data, bool gui_scope)
+{
+ if (!gui_scope) return;
+ RebuildList();
+ this->vscroll->SetCount(this->filtered_list.size());
+ this->vscroll->SetCapacityFromWidget(parent_window, WID_SELECTOR_MATRIX);
+
+ /* This does not assume that the IDs must be contiguous. */
+ auto it = std::find(std::begin(this->filtered_list), std::end(this->filtered_list), this->selected_id);
+
+ if (it != std::end(this->filtered_list)) {
+ int selected_pos = std::distance(std::begin(this->filtered_list), it);
+ this->vscroll->ScrollTowards(selected_pos);
+ }
+}
+
+/**
+ * Selector widget's UpdateWidgetSize method
+ * This function is meant to be called from the parent's window's UpdateWidgetSize method
+ *
+ * @param widget Widget number.
+ * @param[In,out] size Size of the widget.
+ * @param padding Recommended amount of space between the widget content and the widget edge.
+ * @param[In,out] fill Fill step of the widget.
+ * @param[In,out] resize Resize step of the widget.
+ *
+ * All of these parameters should be passed straight from the parent's window's UpdateWidgetSize
+ * method, without any changes, or conditional checks.
+ *
+ * @see Window::UpdateWidgetSize()
+ */
+void SelectorWidget::UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize)
+{
+ if (widget != WID_SELECTOR_MATRIX) return;
+
+ const int min_rows = 11; ///< The minimal number of rows shown
+ const int min_width = ScaleGUITrad(100); ///< The minimal width of the widget
+
+
+ this->row_height = GetCharacterHeight(FS_NORMAL) + padding.height;
+
+ size.height = this->row_height * min_rows;
+ size.width = min_width;
+ resize.width = 1;
+ resize.height = this->row_height;
+ fill.width = 1;
+ fill.height = this->row_height;
+}
+
+/**
+ * Selector widget's OnResize event handler
+ * This function is meant to be called from the parent's window's OnResize
+ * Event handler
+ *
+ * All of these parameters should be passed straight from the parent's window's OnResize
+ * Event handler, without any changes, or conditional checks
+ *
+ * @see Window::OnResize()
+ */
+void SelectorWidget::OnResize()
+{
+ this->vscroll->SetCapacityFromWidget(parent_window, WID_SELECTOR_MATRIX);
+}
+
+/**
+ * Selector widget's OnEditboxChanged event handler
+ * This function is meant to be called from the parent's window's OnEditboxChanged
+ * Event handler
+ *
+ * @param wid The widget id of the editbox.
+ *
+ * All of these parameters should be passed straight from the parent's window's OnEditboxChanged
+ * Event handler, without any changes, or conditional checks
+ *
+ * @see Window::OnEditboxChanged()
+ */
+void SelectorWidget::OnEditboxChanged(WidgetID wid)
+{
+ if (wid != WID_SELECTOR_EDITBOX) return;
+
+ this->string_filter.SetFilterTerm(this->editbox.text.buf);
+ this->parent_window->InvalidateData(0);
+ this->vscroll->SetCount(this->filtered_list.size());
+}
+
+/**
+ * Selector widget's DrawWidget method
+ * This function is meant to be called from the parent's window's DrawWidget
+ * method
+ *
+ * @param widget Widget number.
+ * @param[In,out] size Size of the widget.
+ * @param padding Recommended amount of space between the widget content and the widget edge.
+ * @param[In,out] fill Fill step of the widget.
+ * @param[In,out] resize Resize step of the widget.
+ *
+ * All of these parameters should be passed straight from the parent's window's DrawWidget
+ * Event handler, without any changes, or conditional checks
+ *
+ * This function calls a profile defined function this->profile.DrawSection(),
+ * that actually draws the fields
+ *
+ * @see Window::DrawWidget()
+ * @see SelectorWidget::Profile
+ */
+void SelectorWidget::DrawWidget(const Rect &r, WidgetID widget)
+{
+ if (widget != WID_SELECTOR_MATRIX) return;
+
+ Rect line = r.WithHeight(row_height);
+
+ auto [first, last] = this->vscroll->GetVisibleRangeIterators(filtered_list);
+
+ for (auto it = first; it != last; ++it) {
+ const Rect ir = line.Shrink(WidgetDimensions::scaled.framerect);
+
+ if (this->shown[*it]) {
+ DrawFrameRect(line, COLOUR_BROWN, FR_LOWERED);
+ }
+ this->DrawSection(*it, ir.Shrink(WidgetDimensions::scaled.matrix));
+
+ line = line.Translate(0, row_height);
+ }
+}
+
+/**
+ * A function that updates and rebuilds the list of selectable items
+ * This function calls a profile defined function this->profile.RebuildList(),
+ * that actually rebuilds the list of items.
+ *
+ * It is also manages the shown items and the filtered_list lists
+ *
+ * @see SelectorWidget::Profile
+ */
+void SelectorWidget::RebuildList()
+{
+ this->list.clear();
+ this->filtered_list.clear();
+ this->PopulateList();
+ uint32_t max = *std::max_element(std::begin(this->list), std::end(this->list));
+
+ this->shown.reserve(max);
+ for (size_t i = this->shown.size(); i <= max ; i++) {
+ this->shown.push_back(true);
+ }
+}
+
+/* virtual */ void CargoSelectorWidget::PopulateList()
+{
+ for (const CargoSpec *cargo : _sorted_standard_cargo_specs){
+ this->list.push_back(cargo->Index());
+ if (this->string_filter.IsEmpty()) {
+ this->filtered_list.push_back(cargo->Index());
+ continue;
+ }
+ this->string_filter.ResetState();
+
+ SetDParam(0, cargo->name);
+ this->string_filter.AddLine(GetString(STR_JUST_STRING));
+
+ if (this->string_filter.GetState()) {
+ this->filtered_list.push_back(cargo->Index());
+ }
+ }
+}
+
+/* virtual */ void CargoSelectorWidget::DrawSection(uint id, const Rect &r)
+{
+ const CargoID cargo_id = static_cast(id); ///< CargoID of the current row's cargo
+ const CargoSpec *cargo = CargoSpec::Get(id); ///< CargoSpec of the current row's cargo
+
+ const bool rtl = _current_text_dir == TD_RTL;
+
+ int legend_height = GetCharacterHeight(FS_SMALL);
+ int legend_width = legend_height * 9 / 6;
+
+ Rect cargo_swatch = r.WithWidth(legend_width, rtl);
+ cargo_swatch.top = CenterBounds(r.top, r.bottom, legend_height) - 1;
+ cargo_swatch.bottom = cargo_swatch.top + legend_height;
+
+ /* Cargo-colour box with outline. */
+ GfxFillRect(cargo_swatch, PC_BLACK);
+ GfxFillRect(cargo_swatch.Shrink(WidgetDimensions::scaled.bevel), cargo->legend_colour);
+
+ /* Cargo name. */
+ SetDParam(0, cargo->name);
+ const Rect text = r.Indent(legend_width + WidgetDimensions::scaled.hsep_wide, rtl);
+
+ const TextColour colour = (this->selected_id.value_or(INVALID_OWNER) == cargo_id) ? TC_WHITE : TC_BLACK;
+ DrawString(text.left, text.right, CenterBounds(text.top, text.bottom, GetCharacterHeight(FS_NORMAL)), STR_JUST_STRING, colour);
+}
+
+
+/* virtual */ void CompanySelectorWidget::PopulateList()
+{
+ for (const Company *c: Company::Iterate()) {
+ this->list.push_back(c->index);
+ if (this->string_filter.IsEmpty()) {
+ this->filtered_list.push_back(c->index);
+ continue;
+ }
+ this->string_filter.ResetState();
+
+ SetDParam(0, c->index);
+ this->string_filter.AddLine(GetString(STR_COMPANY_NAME));
+
+ if (this->string_filter.GetState()) {
+ this->filtered_list.push_back(c->index);
+ }
+ }
+}
+
+/* virtual */ void CompanySelectorWidget::DrawSection(uint id, const Rect &r)
+{
+ const CompanyID cid = static_cast(id);
+ assert(Company::IsValidID(cid));
+
+ const bool rtl = _current_text_dir == TD_RTL;
+ const Dimension icon_size = GetSpriteSize(SPR_COMPANY_ICON);
+
+ DrawCompanyIcon(cid, rtl ? r.right - icon_size.width : r.left, CenterBounds(r.top, r.bottom, icon_size.height));
+
+ const Rect text = r.Indent(icon_size.width + WidgetDimensions::scaled.hsep_wide, rtl);
+
+ SetDParam(0, cid);
+
+ const TextColour colour = (this->selected_id.value_or(INVALID_OWNER) == cid) ? TC_WHITE : TC_BLACK;
+ DrawString(text.left, text.right, CenterBounds(text.top, text.bottom, GetCharacterHeight(FS_NORMAL)), STR_COMPANY_NAME, colour);
+}
diff --git a/src/selector_gui.h b/src/selector_gui.h
new file mode 100644
index 0000000000..8e31c5bb7c
--- /dev/null
+++ b/src/selector_gui.h
@@ -0,0 +1,95 @@
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
+ */
+
+/** @file selector_gui.h Functions/types etc. related to the selector widget. */
+
+#ifndef SELECTOR_GUI_H
+#define SELECTOR_GUI_H
+
+#include "stdafx.h"
+#include "querystring_gui.h"
+#include "stringfilter_type.h"
+#include "strings_type.h"
+#include "widget_type.h"
+#include "window_gui.h"
+#include "window_type.h"
+#include "safeguards.h"
+
+struct SelectorWidget {
+
+ std::optional selected_id; ///< ID of the currently selected item
+ std::vector shown; ///< A vector that determines which items are shown e.g on the graph. Not to be confused with filtered_list
+ std::vector list; ///< A list of all the items
+ StringFilter string_filter; ///< The filter that checks wether an item should be displayed based on the editbox
+
+ /** A list of items displayed in WID_SELECTION_MATRIX after the editbox filtering
+ * It is a strict subset of SelectorWidget::list */
+ std::vector filtered_list;
+
+ static std::unique_ptr MakeSelectorWidgetUI();
+
+ void Init(Window *w);
+ void OnClick(Point pt, WidgetID widget, int click_count);
+ void OnMouseOver(Point pt, WidgetID widget);
+ void OnInvalidateData(int data, bool gui_scope);
+ void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize);
+ void OnResize();
+ void OnEditboxChanged(WidgetID wid);
+ void DrawWidget(const Rect &r, WidgetID widget);
+ void RebuildList();
+
+ virtual ~SelectorWidget() {};
+
+private:
+ Window *parent_window; ///< The parent window pointer
+
+ int row_height; ///< The height of 1 row in the WID_SELECTOR_MATRIX widget
+
+ Scrollbar *vscroll; ///< The vertical scrollbar
+
+ /** A QueryString modifiable by the WID_SELECTOR_EDITBOX widget */
+ QueryString editbox{MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH, MAX_LENGTH_COMPANY_NAME_CHARS};
+
+ /**
+ * Draws "section" (line) of the scrollable list.
+ * Called by #DrawWidget
+ * @param id The "id" of the item to be drawn, can mean different things depending on what the selector widget is displaying.
+ * e.g when this widget displays companies, the id is a unique and valid CompanyID
+ * @param r The rectangle where the item is to be drawn.
+ *
+ * @see CargoSelectorWidget::DrawSection()
+ * @see CompanySelectorWidget::DrawSection()
+ * @see SelectorWidget::PopulateList()
+ * @see SelectorWidget::DrawWidget()
+ */
+ virtual void DrawSection(uint id, const Rect &r) = 0;
+
+ /**
+ * Repopulates the list that the widget uses to keep track of different selectable items
+ * @see CargoSelectorWidget::PopulateList()
+ * @see CompanySelectorWidget::PopulateList()
+ */
+ virtual void PopulateList() = 0;
+
+ /**
+ * Called when the widget selection or visibility of some item is changed.
+ * Used to update things that depend on the selector widget's data.
+ */
+ virtual void OnChanged() = 0;
+};
+
+struct CargoSelectorWidget : SelectorWidget {
+ virtual void DrawSection(uint id, const Rect &r) override;
+ virtual void PopulateList() override;
+};
+
+struct CompanySelectorWidget : SelectorWidget {
+ virtual void DrawSection(uint id, const Rect &r) override;
+ virtual void PopulateList() override;
+};
+
+#endif /* SELECTOR_GUI_H */
diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt
index a69f7e7b16..e21af2869b 100644
--- a/src/widgets/CMakeLists.txt
+++ b/src/widgets/CMakeLists.txt
@@ -45,6 +45,7 @@ add_files(
screenshot_widget.h
script_widget.h
settings_widget.h
+ selector_widget.h
sign_widget.h
smallmap_widget.h
station_widget.h
diff --git a/src/widgets/selector_widget.h b/src/widgets/selector_widget.h
new file mode 100644
index 0000000000..f6e403c0df
--- /dev/null
+++ b/src/widgets/selector_widget.h
@@ -0,0 +1,25 @@
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
+ */
+
+/** @file selector_widget.h Types related to the selector widget widgets. */
+
+#ifndef WIDGETS_SELECTOR_WIDGET_H
+#define WIDGETS_SELECTOR_WIDGET_H
+
+/** Widgets of the #SelectorWidget class. */
+enum SelectorClassWindowWidgets : WidgetID {
+ WID_SELECTOR_START = (1 << 16) + 1000, ///< Dummy to ensure widgets don't overlap.
+
+ WID_SELECTOR_MATRIX, ///< Item list.
+ WID_SELECTOR_SCROLLBAR, ///< Vertical scrollbar.
+ WID_SELECTOR_EDITBOX, ///< Editbox filter.
+ WID_SELECTOR_HIDEALL, ///< Hide all button.
+ WID_SELECTOR_SHOWALL, ///< Show all button.
+ WID_SELECTOR_RESIZE, ///< Resize handle
+};
+
+#endif /* WIDGETS_SELECTOR_WIDGET_H */