summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorstormcone <48624099+stormcone@users.noreply.github.com>2019-11-23 20:14:44 +0100
committerCharles Pigott <charlespigott@googlemail.com>2020-01-05 20:52:17 +0000
commit70f9c3c655363bd8814f4a7d95e4dd94a85afd00 (patch)
tree8bd7f808d3a4d9389edebd6bb65277c73a3cebcb /src
parentab9042145e429be254ae1ff8a486c98f9b850fe7 (diff)
downloadopenttd-70f9c3c655363bd8814f4a7d95e4dd94a85afd00.tar.xz
Feature: Industry directory cargo filtering
Diffstat (limited to 'src')
-rw-r--r--src/industry_gui.cpp204
-rw-r--r--src/lang/english.txt4
-rw-r--r--src/script/api/game/game_window.hpp.sq2
-rw-r--r--src/script/api/script_window.hpp2
-rw-r--r--src/widgets/industry_widget.h10
5 files changed, 210 insertions, 12 deletions
diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp
index 2461061cc..d6a0d7aa4 100644
--- a/src/industry_gui.cpp
+++ b/src/industry_gui.cpp
@@ -1167,6 +1167,8 @@ static const NWidgetPart _nested_industry_directory_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_ID_DROPDOWN_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_DROPDOWN_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA),
+ NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_FILTER_BY_ACC_CARGO), SetMinimalSize(225, 12), SetFill(0, 1), SetDataTip(STR_INDUSTRY_DIRECTORY_ACCEPTED_CARGO_FILTER, STR_TOOLTIP_FILTER_CRITERIA),
+ NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_FILTER_BY_PROD_CARGO), SetMinimalSize(225, 12), SetFill(0, 1), SetDataTip(STR_INDUSTRY_DIRECTORY_PRODUCED_CARGO_FILTER, STR_TOOLTIP_FILTER_CRITERIA),
NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_BROWN, WID_ID_INDUSTRY_LIST), SetDataTip(0x0, STR_INDUSTRY_DIRECTORY_LIST_CAPTION), SetResize(1, 1), SetScrollbar(WID_ID_SCROLLBAR), EndContainer(),
@@ -1178,7 +1180,68 @@ static const NWidgetPart _nested_industry_directory_widgets[] = {
EndContainer(),
};
-typedef GUIList<const Industry*> GUIIndustryList;
+typedef GUIList<const Industry *, const std::pair<CargoID, CargoID> &> GUIIndustryList;
+
+/** Special cargo filter criteria */
+enum CargoFilterSpecialType {
+ CF_ANY = CT_NO_REFIT, ///< Show all industries (i.e. no filtering)
+ CF_NONE = CT_INVALID, ///< Show only industries which do not produce/accept cargo
+};
+
+/** Cargo filter functions */
+/**
+ * Check whether an industry accepts and produces a certain cargo pair.
+ * @param industry The industry whose cargoes will being checked.
+ * @param cargoes The accepted and produced cargo pair to look for.
+ * @return bool Whether the given cargoes accepted and produced by the industry.
+ */
+static bool CDECL CargoFilter(const Industry * const *industry, const std::pair<CargoID, CargoID> &cargoes)
+{
+ auto accepted_cargo = cargoes.first;
+ auto produced_cargo = cargoes.second;
+
+ bool accepted_cargo_matches;
+
+ switch (accepted_cargo) {
+ case CF_ANY:
+ accepted_cargo_matches = true;
+ break;
+
+ case CF_NONE:
+ accepted_cargo_matches = std::all_of(std::begin((*industry)->accepts_cargo), std::end((*industry)->accepts_cargo), [](CargoID cargo) {
+ return cargo == CT_INVALID;
+ });
+ break;
+
+ default:
+ const auto &ac = (*industry)->accepts_cargo;
+ accepted_cargo_matches = std::find(std::begin(ac), std::end(ac), accepted_cargo) != std::end(ac);
+ break;
+ }
+
+ bool produced_cargo_matches;
+
+ switch (produced_cargo) {
+ case CF_ANY:
+ produced_cargo_matches = true;
+ break;
+
+ case CF_NONE:
+ produced_cargo_matches = std::all_of(std::begin((*industry)->produced_cargo), std::end((*industry)->produced_cargo), [](CargoID cargo) {
+ return cargo == CT_INVALID;
+ });
+ break;
+
+ default:
+ const auto &pc = (*industry)->produced_cargo;
+ produced_cargo_matches = std::find(std::begin(pc), std::end(pc), produced_cargo) != std::end(pc);
+ break;
+ }
+
+ return accepted_cargo_matches && produced_cargo_matches;
+}
+
+static GUIIndustryList::FilterFunction * const _filter_funcs[] = { &CargoFilter };
/**
@@ -1197,6 +1260,82 @@ protected:
GUIIndustryList industries;
Scrollbar *vscroll;
+ CargoID cargo_filter[NUM_CARGO + 2]; ///< Available cargo filters; CargoID or CF_ANY or CF_NONE
+ StringID cargo_filter_texts[NUM_CARGO + 3]; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID
+ CargoID produced_cargo_filter_criteria; ///< Selected produced cargo filter
+ CargoID accepted_cargo_filter_criteria; ///< Selected accepted cargo filter
+
+ /**
+ * Set cargo filter list item index.
+ * @param index The index of the cargo to be set
+ */
+ void SetProducedCargoFilterIndex(int index)
+ {
+ if (this->produced_cargo_filter_criteria != index) {
+ this->produced_cargo_filter_criteria = index;
+ /* deactivate filter if criteria is 'Show All', activate it otherwise */
+ bool is_filtering_necessary = this->cargo_filter[this->produced_cargo_filter_criteria] != CF_ANY || this->cargo_filter[this->accepted_cargo_filter_criteria] != CF_ANY;
+
+ this->industries.SetFilterState(is_filtering_necessary);
+ this->industries.SetFilterType(0);
+ this->industries.ForceRebuild();
+ }
+ }
+
+ /**
+ * Set cargo filter list item index.
+ * @param index The index of the cargo to be set
+ */
+ void SetAcceptedCargoFilterIndex(int index)
+ {
+ if (this->accepted_cargo_filter_criteria != index) {
+ this->accepted_cargo_filter_criteria = index;
+ /* deactivate filter if criteria is 'Show All', activate it otherwise */
+ bool is_filtering_necessary = this->cargo_filter[this->produced_cargo_filter_criteria] != CF_ANY || this->cargo_filter[this->accepted_cargo_filter_criteria] != CF_ANY;
+
+ this->industries.SetFilterState(is_filtering_necessary);
+ this->industries.SetFilterType(0);
+ this->industries.ForceRebuild();
+ }
+ }
+
+ /**
+ * Populate the filter list and set the cargo filter criteria.
+ */
+ void SetCargoFilterArray()
+ {
+ uint filter_items = 0;
+
+ /* Add item for disabling filtering. */
+ this->cargo_filter[filter_items] = CF_ANY;
+ this->cargo_filter_texts[filter_items] = STR_INDUSTRY_DIRECTORY_FILTER_ALL_TYPES;
+ this->produced_cargo_filter_criteria = filter_items;
+ this->accepted_cargo_filter_criteria = filter_items;
+ filter_items++;
+
+ /* Add item for industries not producing anything, e.g. power plants */
+ this->cargo_filter[filter_items] = CF_NONE;
+ this->cargo_filter_texts[filter_items] = STR_INDUSTRY_DIRECTORY_FILTER_NONE;
+ filter_items++;
+
+ /* Collect available cargo types for filtering. */
+ const CargoSpec *cs;
+ FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
+ this->cargo_filter[filter_items] = cs->Index();
+ this->cargo_filter_texts[filter_items] = cs->name;
+ filter_items++;
+ }
+
+ /* Terminate the filter list. */
+ this->cargo_filter_texts[filter_items] = INVALID_STRING_ID;
+
+ this->industries.SetFilterFuncs(_filter_funcs);
+
+ bool is_filtering_necessary = this->cargo_filter[this->produced_cargo_filter_criteria] != CF_ANY || this->cargo_filter[this->accepted_cargo_filter_criteria] != CF_ANY;
+
+ this->industries.SetFilterState(is_filtering_necessary);
+ }
+
/** (Re)Build industries list */
void BuildSortIndustriesList()
{
@@ -1209,12 +1348,19 @@ protected:
this->industries.shrink_to_fit();
this->industries.RebuildDone();
- this->vscroll->SetCount((uint)this->industries.size()); // Update scrollbar as well.
}
- if (!this->industries.Sort()) return;
IndustryDirectoryWindow::last_industry = nullptr; // Reset name sorter sort cache
- this->SetWidgetDirty(WID_ID_INDUSTRY_LIST); // Set the modified widget dirty
+
+ auto filter = std::make_pair(this->cargo_filter[this->accepted_cargo_filter_criteria],
+ this->cargo_filter[this->produced_cargo_filter_criteria]);
+
+ this->industries.Filter(filter);
+ this->industries.Sort();
+
+ this->vscroll->SetCount((uint)this->industries.size()); // Update scrollbar as well.
+
+ this->SetDirty();
}
/**
@@ -1371,9 +1517,26 @@ public:
this->last_sorting = this->industries.GetListing();
}
+ void OnInit() override
+ {
+ this->SetCargoFilterArray();
+ }
+
void SetStringParameters(int widget) const override
{
- if (widget == WID_ID_DROPDOWN_CRITERIA) SetDParam(0, IndustryDirectoryWindow::sorter_names[this->industries.SortType()]);
+ switch (widget) {
+ case WID_ID_DROPDOWN_CRITERIA:
+ SetDParam(0, IndustryDirectoryWindow::sorter_names[this->industries.SortType()]);
+ break;
+
+ case WID_ID_FILTER_BY_ACC_CARGO:
+ SetDParam(0, this->cargo_filter_texts[this->accepted_cargo_filter_criteria]);
+ break;
+
+ case WID_ID_FILTER_BY_PROD_CARGO:
+ SetDParam(0, this->cargo_filter_texts[this->produced_cargo_filter_criteria]);
+ break;
+ }
}
void DrawWidget(const Rect &r, int widget) const override
@@ -1451,6 +1614,14 @@ public:
ShowDropDownMenu(this, IndustryDirectoryWindow::sorter_names, this->industries.SortType(), WID_ID_DROPDOWN_CRITERIA, 0, 0);
break;
+ case WID_ID_FILTER_BY_ACC_CARGO: // Cargo filter dropdown
+ ShowDropDownMenu(this, this->cargo_filter_texts, this->accepted_cargo_filter_criteria, WID_ID_FILTER_BY_ACC_CARGO, 0, 0);
+ break;
+
+ case WID_ID_FILTER_BY_PROD_CARGO: // Cargo filter dropdown
+ ShowDropDownMenu(this, this->cargo_filter_texts, this->produced_cargo_filter_criteria, WID_ID_FILTER_BY_PROD_CARGO, 0, 0);
+ break;
+
case WID_ID_INDUSTRY_LIST: {
uint p = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_ID_INDUSTRY_LIST, WD_FRAMERECT_TOP);
if (p < this->industries.size()) {
@@ -1467,9 +1638,26 @@ public:
void OnDropdownSelect(int widget, int index) override
{
- if (this->industries.SortType() != index) {
- this->industries.SetSortType(index);
- this->BuildSortIndustriesList();
+ switch (widget) {
+ case WID_ID_DROPDOWN_CRITERIA: {
+ if (this->industries.SortType() != index) {
+ this->industries.SetSortType(index);
+ this->BuildSortIndustriesList();
+ }
+ break;
+ }
+
+ case WID_ID_FILTER_BY_ACC_CARGO: {
+ this->SetAcceptedCargoFilterIndex(index);
+ this->BuildSortIndustriesList();
+ break;
+ }
+
+ case WID_ID_FILTER_BY_PROD_CARGO: {
+ this->SetProducedCargoFilterIndex(index);
+ this->BuildSortIndustriesList();
+ break;
+ }
}
}
diff --git a/src/lang/english.txt b/src/lang/english.txt
index d0fa352bd..94b84d2c3 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -3404,6 +3404,10 @@ STR_INDUSTRY_DIRECTORY_ITEM_PROD2 :{ORANGE}{INDUST
STR_INDUSTRY_DIRECTORY_ITEM_PROD3 :{ORANGE}{INDUSTRY} {STRING4}, {STRING4}, {STRING4}
STR_INDUSTRY_DIRECTORY_ITEM_PRODMORE :{ORANGE}{INDUSTRY} {STRING4}, {STRING4}, {STRING4} and {NUM} more...
STR_INDUSTRY_DIRECTORY_LIST_CAPTION :{BLACK}Industry names - click on name to centre main view on industry. Ctrl+Click opens a new viewport on industry location
+STR_INDUSTRY_DIRECTORY_ACCEPTED_CARGO_FILTER :{BLACK}Accepted cargo: {SILVER}{STRING}
+STR_INDUSTRY_DIRECTORY_PRODUCED_CARGO_FILTER :{BLACK}Produced cargo: {SILVER}{STRING}
+STR_INDUSTRY_DIRECTORY_FILTER_ALL_TYPES :All cargo types
+STR_INDUSTRY_DIRECTORY_FILTER_NONE :None
# Industry view
STR_INDUSTRY_VIEW_CAPTION :{WHITE}{INDUSTRY}
diff --git a/src/script/api/game/game_window.hpp.sq b/src/script/api/game/game_window.hpp.sq
index adc790ad9..eb6328da0 100644
--- a/src/script/api/game/game_window.hpp.sq
+++ b/src/script/api/game/game_window.hpp.sq
@@ -589,6 +589,8 @@ void SQGSWindow_Register(Squirrel *engine)
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_DISPLAY, "WID_IV_DISPLAY");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_DROPDOWN_ORDER, "WID_ID_DROPDOWN_ORDER");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_DROPDOWN_CRITERIA, "WID_ID_DROPDOWN_CRITERIA");
+ SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_FILTER_BY_ACC_CARGO, "WID_ID_FILTER_BY_ACC_CARGO");
+ SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_FILTER_BY_PROD_CARGO, "WID_ID_FILTER_BY_PROD_CARGO");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_INDUSTRY_LIST, "WID_ID_INDUSTRY_LIST");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_SCROLLBAR, "WID_ID_SCROLLBAR");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_CAPTION, "WID_IC_CAPTION");
diff --git a/src/script/api/script_window.hpp b/src/script/api/script_window.hpp
index 2b040c8c6..69d6b81f9 100644
--- a/src/script/api/script_window.hpp
+++ b/src/script/api/script_window.hpp
@@ -1523,6 +1523,8 @@ public:
enum IndustryDirectoryWidgets {
WID_ID_DROPDOWN_ORDER = ::WID_ID_DROPDOWN_ORDER, ///< Dropdown for the order of the sort.
WID_ID_DROPDOWN_CRITERIA = ::WID_ID_DROPDOWN_CRITERIA, ///< Dropdown for the criteria of the sort.
+ WID_ID_FILTER_BY_ACC_CARGO = ::WID_ID_FILTER_BY_ACC_CARGO, ///< Accepted cargo filter dropdown list.
+ WID_ID_FILTER_BY_PROD_CARGO = ::WID_ID_FILTER_BY_PROD_CARGO, ///< Produced cargo filter dropdown list.
WID_ID_INDUSTRY_LIST = ::WID_ID_INDUSTRY_LIST, ///< Industry list.
WID_ID_SCROLLBAR = ::WID_ID_SCROLLBAR, ///< Scrollbar of the list.
};
diff --git a/src/widgets/industry_widget.h b/src/widgets/industry_widget.h
index d31de978e..e9fb2b114 100644
--- a/src/widgets/industry_widget.h
+++ b/src/widgets/industry_widget.h
@@ -30,10 +30,12 @@ enum IndustryViewWidgets {
/** Widgets of the #IndustryDirectoryWindow class. */
enum IndustryDirectoryWidgets {
- WID_ID_DROPDOWN_ORDER, ///< Dropdown for the order of the sort.
- WID_ID_DROPDOWN_CRITERIA, ///< Dropdown for the criteria of the sort.
- WID_ID_INDUSTRY_LIST, ///< Industry list.
- WID_ID_SCROLLBAR, ///< Scrollbar of the list.
+ WID_ID_DROPDOWN_ORDER, ///< Dropdown for the order of the sort.
+ WID_ID_DROPDOWN_CRITERIA, ///< Dropdown for the criteria of the sort.
+ WID_ID_FILTER_BY_ACC_CARGO, ///< Accepted cargo filter dropdown list.
+ WID_ID_FILTER_BY_PROD_CARGO, ///< Produced cargo filter dropdown list.
+ WID_ID_INDUSTRY_LIST, ///< Industry list.
+ WID_ID_SCROLLBAR, ///< Scrollbar of the list.
};
/** Widgets of the #IndustryCargoesWindow class */