mirror of https://github.com/OpenTTD/OpenTTD
Codechange: Add the universal selector widget.
parent
e8be933ee6
commit
8495b4c4f6
|
@ -0,0 +1,433 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file selector_widget.cpp GUI that shows performance graphs. */
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "company_base.h"
|
||||||
|
#include "company_gui.h"
|
||||||
|
#include "strings_func.h"
|
||||||
|
#include "table/sprites.h"
|
||||||
|
#include "widgets/graph_widget.h"
|
||||||
|
#include "selector_widget.h"
|
||||||
|
#include "safeguards.h"
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 parrent window
|
||||||
|
* @see NWidgetFunction
|
||||||
|
*/
|
||||||
|
std::unique_ptr<NWidgetBase> 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_VERTICAL, NC_EQUALSIZE),
|
||||||
|
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
|
||||||
|
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SELECTOR_HIDEALL),
|
||||||
|
SetDataTip(STR_SELECTOR_WIDGET_DISABLE_ALL, STR_SELECTOR_WIDGET_TOOLTIP_DISABLE_ALL),
|
||||||
|
SetResize(1, 0), SetMinimalSize(20, 12), SetFill(1, 0),
|
||||||
|
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SELECTOR_SHOWALL),
|
||||||
|
SetDataTip(STR_SELECTOR_WIDGET_ENABLE_ALL, STR_SELECTOR_WIDGET_TOOLTIP_ENABLE_ALL),
|
||||||
|
SetResize(1, 0), SetMinimalSize(20, 12), SetFill(1, 0),
|
||||||
|
EndContainer(),
|
||||||
|
NWidget(NWID_HORIZONTAL),
|
||||||
|
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SELECTOR_TOGGLE),
|
||||||
|
SetDataTip(STR_SELECTOR_WIDGET_TOGGLE_SELECTED, STR_SELECTOR_WIDGET_TOOLTIP_TOGGLE_SELECTED),
|
||||||
|
SetResize(1, 0), SetMinimalSize(20, 12), SetFill(1, 0),
|
||||||
|
NWidget(WWT_RESIZEBOX, COLOUR_BROWN, WID_GRAPH_RESIZE), SetDataTip(RWV_SHOW_BEVEL, STR_TOOLTIP_RESIZE),
|
||||||
|
SetResize(0, 0),
|
||||||
|
NWidget(NWID_HORIZONTAL),
|
||||||
|
EndContainer(),
|
||||||
|
EndContainer(),
|
||||||
|
};
|
||||||
|
return MakeNWidgets({std::begin(widget_ui), std::end(widget_ui)}, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selector widget initialization function
|
||||||
|
* This function is ment to be called after CreateNestedTree() of the window
|
||||||
|
*
|
||||||
|
* @param w The parrent window of this widget
|
||||||
|
*
|
||||||
|
* @see SelectorWidget::post_init()
|
||||||
|
*/
|
||||||
|
void SelectorWidget::Init(Window* w)
|
||||||
|
{
|
||||||
|
this->w = 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 profile selection function
|
||||||
|
* This function is ment to be called before CreateNestedTree() of the window
|
||||||
|
*
|
||||||
|
* @param p The "profile" the selector widget should use
|
||||||
|
*
|
||||||
|
* A selector widget profile is just a set of function pointers /
|
||||||
|
* possibly parameters in the future, that determine how the widget works,
|
||||||
|
* and help make it more universal.
|
||||||
|
*
|
||||||
|
* @see SelectorWidget::init()
|
||||||
|
*/
|
||||||
|
void SelectorWidget::PreInit(Profile p)
|
||||||
|
{
|
||||||
|
this->profile = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selector widget's OnClick event handler
|
||||||
|
* This function is ment to be called from the parrent'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 theese parameters should be passed straight from the parrent's window's OnClick
|
||||||
|
* Event handler, without any changes, or conditional checks
|
||||||
|
*
|
||||||
|
* @see Window::OnClick()
|
||||||
|
*/
|
||||||
|
void SelectorWidget::OnClick(Point pt, WidgetID widget, int click_count)
|
||||||
|
{
|
||||||
|
if (widget == WID_SELECTOR_HIDEALL){
|
||||||
|
for (uint i = 0; i < this->shown.size(); i++) {
|
||||||
|
this->shown[i] = false;
|
||||||
|
}
|
||||||
|
} else if (widget == WID_SELECTOR_SHOWALL) {
|
||||||
|
for (uint i = 0; i < this->shown.size(); i++) {
|
||||||
|
this->shown[i] = true;
|
||||||
|
}
|
||||||
|
} else if (widget == WID_SELECTOR_TOGGLE) {
|
||||||
|
if (this->selected_id.has_value()) {
|
||||||
|
this->shown[this->selected_id.value()].flip();
|
||||||
|
}
|
||||||
|
} else if (widget == WID_SELECTOR_MATRIX) {
|
||||||
|
const uint selected_row = vscroll->GetScrolledRowFromWidget(pt.y, w, widget);
|
||||||
|
if (selected_row >= this->filtered_list.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selected_id = this->filtered_list[selected_row];
|
||||||
|
if (click_count > 1) {
|
||||||
|
if (this->selected_id.has_value()) {
|
||||||
|
this->shown[this->selected_id.value()].flip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w->InvalidateData(0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selector widget's OnInvalidateData event handler
|
||||||
|
* This function is ment to be called from the parrent's window's OnInvalidateData
|
||||||
|
* Event handler
|
||||||
|
*
|
||||||
|
* @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 theese parameters should be passed straight from the parrent'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->SetCapacityFromWidget(w, WID_SELECTOR_MATRIX);
|
||||||
|
if (this->selected_id.has_value()) {
|
||||||
|
const uint to_select_id = this->selected_id.value();
|
||||||
|
int selected_pos = -1;
|
||||||
|
for (uint i = 0; i < this->filtered_list.size(); i++) {
|
||||||
|
if (this->filtered_list[i] == to_select_id) {
|
||||||
|
selected_pos = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (selected_pos != -1) {
|
||||||
|
const int cap = this->vscroll->GetCapacity();
|
||||||
|
const int pos = this->vscroll->GetPosition();
|
||||||
|
if (selected_pos < pos) {
|
||||||
|
vscroll->SetPosition(selected_pos);
|
||||||
|
} else if (selected_pos > pos + cap) {
|
||||||
|
vscroll->SetPosition(selected_pos - cap + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w->SetDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selector widget's UpdateWidgetSize method
|
||||||
|
* This function is ment to be called from the parrent'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 theese parameters should be passed straight from the parrent'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;
|
||||||
|
this->row_height = GetCharacterHeight(FS_NORMAL) + padding.height;
|
||||||
|
size.height = this->row_height * 7;
|
||||||
|
size.width = 300;
|
||||||
|
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 ment to be called from the parrent's window's OnResize
|
||||||
|
* Event handler
|
||||||
|
*
|
||||||
|
* All of theese parameters should be passed straight from the parrent's window's OnResize
|
||||||
|
* Event handler, without any changes, or conditional checks
|
||||||
|
*
|
||||||
|
* @see Window::OnResize()
|
||||||
|
*/
|
||||||
|
void SelectorWidget::OnResize()
|
||||||
|
{
|
||||||
|
this->vscroll->SetCapacityFromWidget(w, WID_SELECTOR_MATRIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selector widget's OnEditboxChanged event handler
|
||||||
|
* This function is ment to be called from the parrent's window's OnEditboxChanged
|
||||||
|
* Event handler
|
||||||
|
*
|
||||||
|
* @param wid The widget id of the editbox
|
||||||
|
*
|
||||||
|
* All of theese parameters should be passed straight from the parrent'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->w->InvalidateData(0);
|
||||||
|
this->vscroll->SetCount(this->filtered_list.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selector widget's DrawWidget method
|
||||||
|
* This function is ment to be called from the parrent'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 theese parameters should be passed straight from the parrent'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);
|
||||||
|
|
||||||
|
const bool rtl = _current_text_dir == TD_RTL;
|
||||||
|
|
||||||
|
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(ir, COLOUR_BROWN, FR_LOWERED);
|
||||||
|
}
|
||||||
|
this->profile.DrawSection(this, *it, ir.Indent(WidgetDimensions::scaled.fullbevel.Horizontal(), rtl));
|
||||||
|
|
||||||
|
line = line.Translate(0, row_height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is one of the possible functions ment to be used as part of the DrawWidget::Profile
|
||||||
|
* It draws "section" (line) of the scrollable list
|
||||||
|
* @param wid The current SelectionWidget object pointer
|
||||||
|
* @param id the "id" of the item to be drawn, can mean different things depending on the profile
|
||||||
|
* 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 SelectorWidget::DrawSection()
|
||||||
|
* @see SelectorWidget::DrawWidget()
|
||||||
|
* @see SelectorWidget::Profile
|
||||||
|
*/
|
||||||
|
void DrawSectionCompany(SelectorWidget *wid, int id, const Rect &r)
|
||||||
|
{
|
||||||
|
const CompanyID cid = (CompanyID)id;
|
||||||
|
assert(Company::IsValidID(cid));
|
||||||
|
|
||||||
|
const bool rtl = _current_text_dir == TD_RTL;
|
||||||
|
const Dimension d = GetSpriteSize(SPR_COMPANY_ICON);
|
||||||
|
|
||||||
|
DrawCompanyIcon(cid, rtl ? r.right - d.width : r.left, CenterBounds(r.top, r.bottom, d.height));
|
||||||
|
|
||||||
|
const Rect text = r.Indent(d.width + WidgetDimensions::scaled.hsep_normal, rtl);
|
||||||
|
|
||||||
|
SetDParam(0, cid);
|
||||||
|
if (wid->selected_id.value_or(INVALID_OWNER) == cid) {
|
||||||
|
DrawString(text.left, text.right, CenterBounds(text.top, text.bottom, GetCharacterHeight(FS_NORMAL)), STR_COMPANY_NAME, TC_WHITE);
|
||||||
|
} else {
|
||||||
|
DrawString(text.left, text.right, CenterBounds(text.top, text.bottom, GetCharacterHeight(FS_NORMAL)), STR_COMPANY_NAME, TC_BLACK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is one of the possible functions ment to be used as part of the DrawWidget::Profile
|
||||||
|
* It draws "section" (line) of the scrollable list
|
||||||
|
* @param wid The current SelectionWidget object pointer
|
||||||
|
* @param id the "id" of the item to be drawn, can mean different things depending on the profile
|
||||||
|
* 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 SelectorWidget::DrawSection()
|
||||||
|
* @see SelectorWidget::DrawWidget()
|
||||||
|
* @see SelectorWidget::Profile
|
||||||
|
*/
|
||||||
|
static void DrawSectionCargo(SelectorWidget *wid, int id, const Rect &r)
|
||||||
|
{
|
||||||
|
const CargoID cargo_id = (CargoID)id; ///< Id of the current row's cargo
|
||||||
|
const CargoSpec *cargo = CargoSpec::Get(id); ///< cargo spec of the current row's cargo
|
||||||
|
|
||||||
|
const bool rtl = _current_text_dir == TD_RTL;
|
||||||
|
|
||||||
|
const float cargo_rect_scale_factor = 0.85f;
|
||||||
|
const int legend_width = r.Height() * 9 / 6;
|
||||||
|
|
||||||
|
/* Make a rectangle to display the legend color */
|
||||||
|
const Rect cargo_colour = r.Shrink(0, r.Height() * (1.0 - cargo_rect_scale_factor) / 2.0)
|
||||||
|
.WithWidth(legend_width * cargo_rect_scale_factor, rtl);
|
||||||
|
|
||||||
|
/* Cargo-colour box with outline */
|
||||||
|
GfxFillRect(cargo_colour, PC_BLACK);
|
||||||
|
GfxFillRect(cargo_colour.Shrink(WidgetDimensions::scaled.bevel), cargo->legend_colour);
|
||||||
|
|
||||||
|
/* Cargo name */
|
||||||
|
SetDParam(0, cargo->name);
|
||||||
|
const Rect text = r.Shrink(legend_width + WidgetDimensions::scaled.hsep_normal, rtl);
|
||||||
|
if (wid->selected_id.value_or(INVALID_OWNER) == cargo_id) {
|
||||||
|
DrawString(text.left, text.right, CenterBounds(text.top, text.bottom, GetCharacterHeight(FS_NORMAL)), STR_JUST_STRING, TC_WHITE);
|
||||||
|
} else {
|
||||||
|
DrawString(text.left, text.right, CenterBounds(text.top, text.bottom, GetCharacterHeight(FS_NORMAL)), STR_JUST_STRING, TC_BLACK);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is one of the possible functions ment to be used as part of the DrawWidget::Profile
|
||||||
|
* It repopulates the list that the widget uses to keep track of different selectable items
|
||||||
|
* @param wid The current SelectionWidget object pointer
|
||||||
|
* @see SelectorWidget::RebuildList()
|
||||||
|
* @see SelectorWidget::Profile
|
||||||
|
*/
|
||||||
|
static void RebuildListCompany(SelectorWidget *wid) {
|
||||||
|
for (const Company *c: Company::Iterate()) {
|
||||||
|
wid->list.push_back(c->index);
|
||||||
|
if (wid->string_filter.IsEmpty()) {
|
||||||
|
wid->filtered_list.push_back(c->index);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
wid->string_filter.ResetState();
|
||||||
|
|
||||||
|
SetDParam(0, c->index);
|
||||||
|
wid->string_filter.AddLine(GetString(STR_COMPANY_NAME));
|
||||||
|
|
||||||
|
if (wid->string_filter.GetState()) {
|
||||||
|
wid->filtered_list.push_back(c->index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is one of the possible functions ment to be used as part of the DrawWidget::Profile
|
||||||
|
* It repopulates the list that the widget uses to keep track of different selectable items
|
||||||
|
* @param wid The current SelectionWidget object pointer
|
||||||
|
* @see SelectorWidget::RebuildList()
|
||||||
|
* @see SelectorWidget::Profile
|
||||||
|
*/
|
||||||
|
void RebuildListCargo(SelectorWidget *wid) {
|
||||||
|
for (const CargoSpec *cargo : _sorted_standard_cargo_specs){
|
||||||
|
wid->list.push_back(cargo->Index());
|
||||||
|
if (wid->string_filter.IsEmpty()) {
|
||||||
|
wid->filtered_list.push_back(cargo->Index());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
wid->string_filter.ResetState();
|
||||||
|
|
||||||
|
SetDParam(0, cargo->Index());
|
||||||
|
wid->string_filter.AddLine(GetString(STR_JUST_CARGO));
|
||||||
|
|
||||||
|
if (wid->string_filter.GetState()) {
|
||||||
|
wid->filtered_list.push_back(cargo->Index());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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->profile.RebuildList(this);
|
||||||
|
uint32_t max = 0;
|
||||||
|
for (const uint32_t id : list) {
|
||||||
|
if (id > max) {
|
||||||
|
max = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t i = this->shown.size(); i < max + 1; i++) {
|
||||||
|
shown.push_back(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SelectorWidget::Profile SelectorWidget::company_selector_profile = {DrawSectionCompany, RebuildListCompany};
|
||||||
|
const SelectorWidget::Profile SelectorWidget::cargo_selector_profile = {DrawSectionCargo, RebuildListCargo};
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file selector_widget.h GUI that shows performance graphs. */
|
||||||
|
|
||||||
|
#ifndef SELECTOR_WIDGET_H
|
||||||
|
#define SELECTOR_WIDGET_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"
|
||||||
|
|
||||||
|
class SelectorWidget {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* This struct is like a config file for a utility,
|
||||||
|
* it makes the selector widget configurable and extencible.
|
||||||
|
* In it's current form it stores function pointers to functions
|
||||||
|
* that rebuild the lists and draw individual items in the matrix widget
|
||||||
|
*/
|
||||||
|
struct Profile {
|
||||||
|
void (*DrawSection)(SelectorWidget *wid, int id, const Rect &r); ///< A function pointer to a function that draws 1 line of the list
|
||||||
|
void (*RebuildList)(SelectorWidget *wid); ///< A function pointer that rebuilds the item list
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Profile company_selector_profile; ///< One prebuilt profile for selection
|
||||||
|
static const Profile cargo_selector_profile; ///< One prebuilt profile for selection
|
||||||
|
|
||||||
|
std::optional<int> selected_id; ///< Id of the currently selected item
|
||||||
|
std::vector<bool> shown; ///< A vector that determines which items are shown e.g on the graph. Not to be confused with filtered_list
|
||||||
|
std::vector<uint32_t> list; ///< A list of all the items
|
||||||
|
StringFilter string_filter; ///< The filter that checks weather 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<uint32_t> filtered_list;
|
||||||
|
|
||||||
|
static std::unique_ptr<NWidgetBase> MakeSelectorWidgetUI();
|
||||||
|
|
||||||
|
void PreInit(Profile p);
|
||||||
|
void Init(Window* w);
|
||||||
|
void OnClick(Point pt, WidgetID widget, int click_count);
|
||||||
|
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();
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* This enum stores the WidgetIDs of all the widgets that belong to this selector widget.
|
||||||
|
* It starts at a very high value, not to interfear with other widgets of the parrent window
|
||||||
|
*/
|
||||||
|
enum InternalWidgets {
|
||||||
|
WID_SELECTOR_MATRIX = 42069,
|
||||||
|
WID_SELECTOR_SCROLLBAR,
|
||||||
|
WID_SELECTOR_EDITBOX,
|
||||||
|
WID_SELECTOR_HIDEALL,
|
||||||
|
WID_SELECTOR_SHOWALL,
|
||||||
|
WID_SELECTOR_TOGGLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
Profile profile; ///< currently selected profile
|
||||||
|
|
||||||
|
Window *w; ///< The parrent window pointer
|
||||||
|
|
||||||
|
int row_height; ///< The height of 1 row in the WID_SELECTOR_MATRIX widget
|
||||||
|
|
||||||
|
Scrollbar* vscroll; ///< A pointer to the WID_SELECTOR_SCROLLBAR widget
|
||||||
|
|
||||||
|
/** A QueryString modifiable by the WID_SELECTOR_EDITBOX widget */
|
||||||
|
QueryString editbox{MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH, MAX_LENGTH_COMPANY_NAME_CHARS};
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif /* SELECTOR_WIDGET_H */
|
Loading…
Reference in New Issue