Merge branch 'master' into jgrpp

# Conflicts:
#	.github/workflows/ci-build.yml
#	.github/workflows/release-linux.yml
#	.github/workflows/release-macos.yml
#	.github/workflows/release-windows.yml
#	.gitignore
#	COMPILING.md
#	src/company_gui.cpp
#	src/date_gui.cpp
#	src/engine.cpp
#	src/engine_func.h
#	src/fileio.cpp
#	src/linkgraph/linkgraph_gui.h
#	src/newgrf_debug_gui.cpp
#	src/newgrf_gui.cpp
#	src/order_gui.cpp
#	src/osk_gui.cpp
#	src/rail_gui.cpp
#	src/road_gui.cpp
#	src/script/api/script_event_types.hpp
#	src/sl/oldloader_sl.cpp
#	src/smallmap_gui.cpp
#	src/station_cmd.cpp
#	src/toolbar_gui.cpp
#	src/town_gui.cpp
#	src/transparency_gui.cpp
#	src/vehicle_gui.cpp
#	src/widget.cpp
#	src/widget_type.h
#	src/widgets/dropdown.cpp
#	src/widgets/dropdown_func.h
#	src/widgets/dropdown_type.h
#	src/widgets/group_widget.h
#	src/widgets/vehicle_widget.h
#	src/window.cpp
#	src/window_gui.h
#	src/window_type.h
This commit is contained in:
Jonathan G Rennison
2024-01-02 14:31:56 +00:00
179 changed files with 2191 additions and 1827 deletions

View File

@@ -24,6 +24,9 @@
* API removals:
* \li AIError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, that error is never returned anymore.
*
* Other changes:
* \li AIVehicleList accepts an optional filter function
*
* \b 13.0
*
* API additions:

View File

@@ -84,6 +84,9 @@
* API removals:
* \li GSError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, that error is never returned anymore.
*
* Other changes:
* \li GSVehicleList accepts an optional filter function
*
* \b 13.0
*
* API additions:

View File

@@ -925,7 +925,7 @@ public:
* @param number The windownumber that was clicked.
* @param widget The widget in the window that was clicked.
*/
ScriptEventWindowWidgetClick(ScriptWindow::WindowClass window, uint32 number, uint8 widget) :
ScriptEventWindowWidgetClick(ScriptWindow::WindowClass window, uint32_t number, WidgetID widget) :
ScriptEvent(ET_WINDOW_WIDGET_CLICK),
window(window),
number(number),
@@ -956,12 +956,12 @@ public:
* Get the number of the widget that was clicked.
* @return The number of the clicked widget.
*/
uint8 GetWidgetNumber() { return this->widget; }
int GetWidgetNumber() { return this->widget; }
private:
ScriptWindow::WindowClass window; ///< Window of the click.
uint32 number; ///< Number of the click.
uint8 widget; ///< Widget of the click.
uint32_t number; ///< Number of the click.
WidgetID widget; ///< Widget of the click.
};
/**

View File

@@ -18,12 +18,78 @@
#include "../../safeguards.h"
ScriptVehicleList::ScriptVehicleList()
ScriptVehicleList::ScriptVehicleList(HSQUIRRELVM vm)
{
EnforceDeityOrCompanyModeValid_Void();
for (const Vehicle *v : Vehicle::Iterate()) {
if ((v->owner == ScriptObject::GetCompany() || ScriptCompanyMode::IsDeity()) && (v->IsPrimaryVehicle() || (v->type == VEH_TRAIN && ::Train::From(v)->IsFreeWagon()))) this->AddItem(v->index);
int nparam = sq_gettop(vm) - 1;
if (nparam >= 1) {
/* Make sure the filter function is really a function, and not any
* other type. It's parameter 2 for us, but for the user it's the
* first parameter they give. */
SQObjectType valuator_type = sq_gettype(vm, 2);
if (valuator_type != OT_CLOSURE && valuator_type != OT_NATIVECLOSURE) {
throw sq_throwerror(vm, "parameter 1 has an invalid type (expected function)");
}
/* Push the function to call */
sq_push(vm, 2);
}
/* Don't allow docommand from a Valuator, as we can't resume in
* mid C++-code. */
bool backup_allow = ScriptObject::GetAllowDoCommand();
ScriptObject::SetAllowDoCommand(false);
for (const Vehicle *v : Vehicle::Iterate()) {
if (v->owner != ScriptObject::GetCompany() && !ScriptCompanyMode::IsDeity()) continue;
if (!v->IsPrimaryVehicle() && !(v->type == VEH_TRAIN && ::Train::From(v)->IsFreeWagon())) continue;
if (nparam < 1) {
/* No filter, just add the item. */
this->AddItem(v->index);
continue;
}
/* Push the root table as instance object, this is what squirrel does for meta-functions. */
sq_pushroottable(vm);
/* Push all arguments for the valuator function. */
sq_pushinteger(vm, v->index);
for (int i = 0; i < nparam - 1; i++) {
sq_push(vm, i + 3);
}
/* Call the function. Squirrel pops all parameters and pushes the return value. */
if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQTrue))) {
ScriptObject::SetAllowDoCommand(backup_allow);
throw sq_throwerror(vm, "failed to run filter");
}
/* Retrieve the return value */
switch (sq_gettype(vm, -1)) {
case OT_BOOL: {
SQBool add;
sq_getbool(vm, -1, &add);
if (add) this->AddItem(v->index);
break;
}
default: {
ScriptObject::SetAllowDoCommand(backup_allow);
throw sq_throwerror(vm, "return value of filter is not valid (not bool)");
}
}
/* Pop the return value. */
sq_poptop(vm);
}
if (nparam >= 1) {
/* Pop the filter function */
sq_poptop(vm);
}
ScriptObject::SetAllowDoCommand(backup_allow);
}
ScriptVehicleList_Station::ScriptVehicleList_Station(StationID station_id)

View File

@@ -20,7 +20,32 @@
*/
class ScriptVehicleList : public ScriptList {
public:
#ifdef DOXYGEN_API
ScriptVehicleList();
/**
* Apply a filter when building the list.
* @param filter_function The function which will be doing the filtering.
* @param params The params to give to the filters (minus the first param,
* which is always the index-value).
* @note You can write your own filters and use them. Just remember that
* the first parameter should be the index-value, and it should return
* a bool.
* @note Example:
* ScriptVehicleList(ScriptVehicle.IsInDepot);
* function IsType(vehicle_id, type)
* {
* return ScriptVehicle.GetVehicleType(vehicle_id) == type;
* }
* ScriptVehicleList(IsType, ScriptVehicle.VT_ROAD);
*/
ScriptVehicleList(void *filter_function, int params, ...);
#else
/**
* The constructor wrapper from Squirrel.
*/
ScriptVehicleList(HSQUIRRELVM vm);
#endif
};
/**

View File

@@ -97,14 +97,14 @@ struct ScriptListWindow : public Window {
}
}
void SetStringParameters(int widget) const override
void SetStringParameters(WidgetID widget) const override
{
if (widget != WID_SCRL_CAPTION) return;
SetDParam(0, (this->slot == OWNER_DEITY) ? STR_AI_LIST_CAPTION_GAMESCRIPT : STR_AI_LIST_CAPTION_AI);
}
void UpdateWidgetSize(int widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override
void UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override
{
if (widget != WID_SCRL_LIST) return;
@@ -115,7 +115,7 @@ struct ScriptListWindow : public Window {
size->height = 5 * this->line_height;
}
void DrawWidget(const Rect &r, int widget) const override
void DrawWidget(const Rect &r, WidgetID widget) const override
{
switch (widget) {
case WID_SCRL_LIST: {
@@ -192,7 +192,7 @@ struct ScriptListWindow : public Window {
}
}
void OnClick([[maybe_unused]] Point pt, int widget, [[maybe_unused]] int click_count) override
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
{
switch (widget) {
case WID_SCRL_LIST: { // Select one of the Scripts
@@ -351,14 +351,14 @@ struct ScriptSettingsWindow : public Window {
this->vscroll->SetCount(this->visible_settings.size());
}
void SetStringParameters(int widget) const override
void SetStringParameters(WidgetID widget) const override
{
if (widget != WID_SCRS_CAPTION) return;
SetDParam(0, (this->slot == OWNER_DEITY) ? STR_AI_SETTINGS_CAPTION_GAMESCRIPT : STR_AI_SETTINGS_CAPTION_AI);
}
void UpdateWidgetSize(int widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override
void UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override
{
if (widget != WID_SCRS_BACKGROUND) return;
@@ -369,7 +369,7 @@ struct ScriptSettingsWindow : public Window {
size->height = 5 * this->line_height;
}
void DrawWidget(const Rect &r, int widget) const override
void DrawWidget(const Rect &r, WidgetID widget) const override
{
if (widget != WID_SCRS_BACKGROUND) return;
@@ -437,7 +437,7 @@ struct ScriptSettingsWindow : public Window {
this->DrawWidgets();
}
void OnClick([[maybe_unused]] Point pt, int widget, [[maybe_unused]] int click_count) override
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
{
switch (widget) {
case WID_SCRS_BACKGROUND: {
@@ -540,14 +540,14 @@ struct ScriptSettingsWindow : public Window {
SetValue(value);
}
void OnDropdownSelect(int widget, int index) override
void OnDropdownSelect(WidgetID widget, int index) override
{
if (widget != WID_SCRS_SETTING_DROPDOWN) return;
assert(this->clicked_dropdown);
SetValue(index);
}
void OnDropdownClose(Point, int widget, int, bool) override
void OnDropdownClose(Point, WidgetID widget, int, bool) override
{
if (widget != WID_SCRS_SETTING_DROPDOWN) return;
/* We cannot raise the dropdown button just yet. OnClick needs some hint, whether
@@ -652,7 +652,7 @@ struct ScriptTextfileWindow : public TextfileWindow {
this->OnInvalidateData();
}
void SetStringParameters(int widget) const override
void SetStringParameters(WidgetID widget) const override
{
if (widget == WID_TF_CAPTION) {
SetDParam(0, (slot == OWNER_DEITY) ? STR_CONTENT_TYPE_GAME_SCRIPT : STR_CONTENT_TYPE_AI);
@@ -803,19 +803,14 @@ struct ScriptDebugWindow : public Window {
this->CreateNestedTree();
this->vscroll = this->GetScrollbar(WID_SCRD_VSCROLLBAR);
this->hscroll = this->GetScrollbar(WID_SCRD_HSCROLLBAR);
this->show_break_box = _settings_client.gui.ai_developer_tools;
this->GetWidget<NWidgetStacked>(WID_SCRD_BREAK_STRING_WIDGETS)->SetDisplayedPlane(this->show_break_box ? 0 : SZSP_HORIZONTAL);
this->FinishInitNested(number);
if (!this->show_break_box) this->filter.break_check_enabled = false;
this->last_vscroll_pos = 0;
this->autoscroll = true;
this->highlight_row = -1;
this->querystrings[WID_SCRD_BREAK_STR_EDIT_BOX] = &this->break_editbox;
SetWidgetsDisabledState(!this->show_break_box, WID_SCRD_BREAK_STR_ON_OFF_BTN, WID_SCRD_BREAK_STR_EDIT_BOX, WID_SCRD_MATCH_CASE_BTN);
this->hscroll->SetStepSize(10); // Speed up horizontal scrollbar
/* Restore the break string value from static variable, and enable the filter. */
@@ -831,6 +826,11 @@ struct ScriptDebugWindow : public Window {
void OnInit() override
{
this->show_break_box = _settings_client.gui.ai_developer_tools;
this->GetWidget<NWidgetStacked>(WID_SCRD_BREAK_STRING_WIDGETS)->SetDisplayedPlane(this->show_break_box ? 0 : SZSP_HORIZONTAL);
if (!this->show_break_box) this->filter.break_check_enabled = false;
SetWidgetsDisabledState(!this->show_break_box, WID_SCRD_BREAK_STR_ON_OFF_BTN, WID_SCRD_BREAK_STR_EDIT_BOX, WID_SCRD_MATCH_CASE_BTN);
this->InvalidateData(-1);
}
@@ -839,7 +839,7 @@ struct ScriptDebugWindow : public Window {
ScriptDebugWindow::initial_state = this->filter;
}
void UpdateWidgetSize(int widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override
void UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override
{
if (widget == WID_SCRD_LOG_PANEL) {
resize->height = GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal;
@@ -856,7 +856,7 @@ struct ScriptDebugWindow : public Window {
this->DrawWidgets();
}
void SetStringParameters(int widget) const override
void SetStringParameters(WidgetID widget) const override
{
if (widget != WID_SCRD_NAME_TEXT) return;
@@ -877,7 +877,7 @@ struct ScriptDebugWindow : public Window {
}
}
void DrawWidget(const Rect &r, int widget) const override
void DrawWidget(const Rect &r, WidgetID widget) const override
{
switch (widget) {
case WID_SCRD_LOG_PANEL:
@@ -898,7 +898,7 @@ struct ScriptDebugWindow : public Window {
* @param widget Widget index to start.
* @param start Widget index of first company button.
*/
void DrawWidgetCompanyButton(const Rect &r, int widget, int start) const
void DrawWidgetCompanyButton(const Rect &r, WidgetID widget, int start) const
{
if (this->IsWidgetDisabled(widget)) return;
CompanyID cid = (CompanyID)(widget - start);
@@ -1052,7 +1052,7 @@ struct ScriptDebugWindow : public Window {
this->last_vscroll_pos = this->vscroll->GetPosition();
}
void OnClick([[maybe_unused]] Point pt, int widget, [[maybe_unused]] int click_count) override
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
{
/* Also called for hotkeys, so check for disabledness */
if (this->IsWidgetDisabled(widget)) return;
@@ -1128,7 +1128,7 @@ struct ScriptDebugWindow : public Window {
}
}
void OnEditboxChanged(int wid) override
void OnEditboxChanged(WidgetID wid) override
{
if (wid != WID_SCRD_BREAK_STR_EDIT_BOX) return;
@@ -1145,6 +1145,8 @@ struct ScriptDebugWindow : public Window {
*/
void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
{
if (this->show_break_box != _settings_client.gui.ai_developer_tools) this->ReInit();
/* If the log message is related to the active company tab, check the break string.
* This needs to be done in gameloop-scope, so the AI is suspended immediately. */
if (!gui_scope && data == this->filter.script_debug_company &&
@@ -1218,9 +1220,9 @@ struct ScriptDebugWindow : public Window {
};
/** Make a number of rows with buttons for each company for the Script debug window. */
NWidgetBase *MakeCompanyButtonRowsScriptDebug(int *biggest_index)
std::unique_ptr<NWidgetBase> MakeCompanyButtonRowsScriptDebug()
{
return MakeCompanyButtonRows(biggest_index, WID_SCRD_COMPANY_BUTTON_START, WID_SCRD_COMPANY_BUTTON_END, COLOUR_GREY, 8, STR_AI_DEBUG_SELECT_AI_TOOLTIP);
return MakeCompanyButtonRows(WID_SCRD_COMPANY_BUTTON_START, WID_SCRD_COMPANY_BUTTON_END, COLOUR_GREY, 8, STR_AI_DEBUG_SELECT_AI_TOOLTIP);
}
/**