Skip to content

Commit

Permalink
Feature: Filter engine build menu by name and NewGRF extra text
Browse files Browse the repository at this point in the history
  • Loading branch information
2TallTyler committed Mar 3, 2023
1 parent ec8b283 commit 9fce6a8
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 12 deletions.
120 changes: 108 additions & 12 deletions src/build_vehicle_gui.cpp
Expand Up @@ -34,6 +34,9 @@
#include "train_cmd.h"
#include "vehicle_cmd.h"
#include "zoom_func.h"
#include "querystring_gui.h"
#include "stringfilter_type.h"
#include "hotkeys.h"

#include "widgets/build_vehicle_widget.h"

Expand Down Expand Up @@ -69,6 +72,7 @@ static const NWidgetPart _nested_build_vehicle_widgets[] = {
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BV_SHOW_HIDDEN_ENGINES),
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_CARGO_FILTER_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA),
EndContainer(),
NWidget(WWT_EDITBOX, COLOUR_GREY, WID_BV_FILTER), SetMinimalSize(128, 0), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
EndContainer(),
EndContainer(),
/* Vehicle list. */
Expand Down Expand Up @@ -854,28 +858,41 @@ static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_
return y;
}


/**
* Display additional text from NewGRF in the purchase information window
* @param left Left border of text bounding box
* @param right Right border of text bounding box
* @param y Top border of text bounding box
* @param engine Engine to query the additional purchase information for
* @return Bottom border of text bounding box
*
*/
static uint ShowAdditionalText(int left, int right, int y, EngineID engine)
static std::tuple<bool, std::string> GetNewGRFAdditionalText(EngineID engine)
{
uint16 callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, nullptr);
if (callback == CALLBACK_FAILED || callback == 0x400) return y;
if (callback == CALLBACK_FAILED || callback == 0x400) return std::make_tuple(false, "");
const GRFFile *grffile = Engine::Get(engine)->GetGRF();
assert(grffile != nullptr);
if (callback > 0x400) {
ErrorUnknownCallbackResult(grffile->grfid, CBID_VEHICLE_ADDITIONAL_TEXT, callback);
return y;
return std::make_tuple(false, "");
}

StartTextRefStackUsage(grffile, 6);
uint result = DrawStringMultiLine(left, right, y, INT32_MAX, GetGRFStringID(grffile->grfid, 0xD000 + callback), TC_BLACK);
std::string result = GetString(GetGRFStringID(grffile->grfid, 0xD000 + callback));
StopTextRefStackUsage();
return std::make_tuple(true, result);
}

/**
* Display additional text from NewGRF in the purchase information window
* @param left Left border of text bounding box
* @param right Right border of text bounding box
* @param y Top border of text bounding box
* @param engine Engine to query the additional purchase information for
* @return Bottom border of text bounding box
*/
static uint ShowAdditionalText(int left, int right, int y, EngineID engine)
{
std::tuple<bool, std::string> packed = GetNewGRFAdditionalText(engine);
bool succeeded = std::get<0>(packed);
if (!succeeded) return y;
uint result = DrawStringMultiLine(left, right, y, INT32_MAX, std::get<1>(packed), TC_BLACK);
return result;
}

Expand Down Expand Up @@ -1086,6 +1103,11 @@ void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selecte
ShowDropDownMenu(w, _engine_sort_listing[vehicle_type], selected, button, 0, hidden_mask);
}

/** Enum referring to the Hotkeys in the build vehicle window */
enum BuildVehicleHotkeys {
BVHK_FOCUS_FILTER_BOX, ///< Focus the edit box for editing the filter string
};

/** GUI for building vehicles. */
struct BuildVehicleWindow : Window {
VehicleType vehicle_type; ///< Type of vehicles shown in the window.
Expand All @@ -1107,6 +1129,9 @@ struct BuildVehicleWindow : Window {
Scrollbar *vscroll;
TestedEngineDetails te; ///< Tested cost and capacity after refit.

StringFilter string_filter; ///< Filter for vehicle name
QueryString vehicle_editbox; ///< Filter editbox

void SetBuyVehicleText()
{
NWidgetCore *widget = this->GetWidget<NWidgetCore>(WID_BV_BUILD);
Expand Down Expand Up @@ -1144,7 +1169,7 @@ struct BuildVehicleWindow : Window {
}
}

BuildVehicleWindow(WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc)
BuildVehicleWindow(WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc), vehicle_editbox(MAX_LENGTH_VEHICLE_NAME_CHARS * MAX_CHAR_LENGTH, MAX_LENGTH_VEHICLE_NAME_CHARS)
{
this->vehicle_type = type;
this->listview_mode = tile == INVALID_TILE;
Expand Down Expand Up @@ -1185,6 +1210,9 @@ struct BuildVehicleWindow : Window {

this->FinishInitNested(tile == INVALID_TILE ? (int)type : (int)tile);

this->querystrings[WID_BV_FILTER] = &this->vehicle_editbox;
this->vehicle_editbox.cancel_button = QueryString::ACTION_CLEAR;

this->owner = (tile != INVALID_TILE) ? GetTileOwner(tile) : _local_company;

this->eng_list.ForceRebuild();
Expand Down Expand Up @@ -1330,6 +1358,28 @@ struct BuildVehicleWindow : Window {
return CargoAndEngineFilter(&item, filter_type);
}

/** Filter by name and NewGRF extra text */
bool FilterByText(const Engine *e)
{
/* Do not filter if the filter text box is empty */
if (this->string_filter.IsEmpty()) {
return true;
}

/* Filter engine name */
char buffer[DRAW_STRING_BUFFER];
GetString(buffer, e->info.string_id, lastof(buffer));
this->string_filter.ResetState();
this->string_filter.AddLine(buffer);

/* Filter NewGRF extra text */
std::tuple<bool, std::string> packed = GetNewGRFAdditionalText(e->index);
bool succeeded = std::get<0>(packed);
if (succeeded) this->string_filter.AddLine(std::get<1>(packed));

return this->string_filter.GetState();
}

/* Figure out what train EngineIDs to put in the list */
void GenerateBuildTrainList(GUIEngineList &list)
{
Expand All @@ -1354,6 +1404,9 @@ struct BuildVehicleWindow : Window {
/* Filter now! So num_engines and num_wagons is valid */
if (!FilterSingleEngine(eid)) continue;

/* Filter by name or NewGRF extra text */
if (!(FilterByText(e))) continue;

list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);

if (rvi->railveh_type != RAILVEH_WAGON) num_engines++;
Expand Down Expand Up @@ -1400,6 +1453,9 @@ struct BuildVehicleWindow : Window {
if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue;
if (this->filter.roadtype != INVALID_ROADTYPE && !HasPowerOnRoad(e->u.road.roadtype, this->filter.roadtype)) continue;

/* Filter by name or NewGRF extra text */
if (!(FilterByText(e))) continue;

this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);

if (eid == this->sel_engine) sel_id = eid;
Expand All @@ -1417,6 +1473,10 @@ struct BuildVehicleWindow : Window {
if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue;
EngineID eid = e->index;
if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue;

/* Filter by name or NewGRF extra text */
if (!(FilterByText(e))) continue;

this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);

if (eid == this->sel_engine) sel_id = eid;
Expand Down Expand Up @@ -1444,7 +1504,11 @@ struct BuildVehicleWindow : Window {
/* First VEH_END window_numbers are fake to allow a window open for all different types at once */
if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue;

/* Filter by name or NewGRF extra text */
if (!(FilterByText(e))) continue;

this->eng_list.emplace_back(eid, e->info.variant_id, e->display_flags, 0);

if (eid == this->sel_engine) sel_id = eid;
}

Expand Down Expand Up @@ -1785,13 +1849,45 @@ struct BuildVehicleWindow : Window {
{
this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST);
}

void OnEditboxChanged(int wid) override
{
if (wid == WID_BV_FILTER) {
this->string_filter.SetFilterTerm(this->vehicle_editbox.text.buf);
this->InvalidateData();
}
}

EventState OnHotkey(int hotkey) override
{
switch (hotkey) {
case BVHK_FOCUS_FILTER_BOX:
this->SetFocusedWidget(WID_BV_FILTER);
SetFocusedWindow(this); // The user has asked to give focus to the text box, so make sure this window is focused.
break;

default:
return ES_NOT_HANDLED;
}

return ES_HANDLED;
}

static HotkeyList hotkeys;
};

static Hotkey buildvehicle_hotkeys[] = {
Hotkey('F', "focus_filter_box", BVHK_FOCUS_FILTER_BOX),
HOTKEY_LIST_END
};
HotkeyList BuildVehicleWindow::hotkeys("buildvehicle", buildvehicle_hotkeys);

static WindowDesc _build_vehicle_desc(
WDP_AUTO, "build_vehicle", 240, 268,
WC_BUILD_VEHICLE, WC_NONE,
WDF_CONSTRUCTION,
_nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets)
_nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets),
&BuildVehicleWindow::hotkeys
);

void ShowBuildVehicleWindow(TileIndex tile, VehicleType type)
Expand Down
13 changes: 13 additions & 0 deletions src/stringfilter.cpp
Expand Up @@ -116,6 +116,19 @@ void StringFilter::AddLine(const char *str)
}
}

/**
* Pass another text line from the current item to the filter.
*
* You can call this multiple times for a single item, if the filter shall apply to multiple things.
* Before processing the next item you have to call ResetState().
*
* @param string Another line from the item.
*/
void StringFilter::AddLine(std::string str)
{
AddLine(str.c_str());
}

/**
* Pass another text line from the current item to the filter.
*
Expand Down
1 change: 1 addition & 0 deletions src/stringfilter_type.h
Expand Up @@ -59,6 +59,7 @@ struct StringFilter {
bool IsEmpty() const { return this->word_index.size() == 0; }

void ResetState();
void AddLine(std::string string);
void AddLine(const char *str);
void AddLine(StringID str);

Expand Down
1 change: 1 addition & 0 deletions src/widgets/build_vehicle_widget.h
Expand Up @@ -16,6 +16,7 @@ enum BuildVehicleWidgets {
WID_BV_SORT_ASCENDING_DESCENDING, ///< Sort direction.
WID_BV_SORT_DROPDOWN, ///< Criteria of sorting dropdown.
WID_BV_CARGO_FILTER_DROPDOWN, ///< Cargo filter dropdown.
WID_BV_FILTER, ///< Filter by name.
WID_BV_SHOW_HIDDEN_ENGINES, ///< Toggle whether to display the hidden vehicles.
WID_BV_LIST, ///< List of vehicles.
WID_BV_SCROLLBAR, ///< Scrollbar of list.
Expand Down

0 comments on commit 9fce6a8

Please sign in to comment.