From 7fd0e6c27d33206a11f97b87a89c9f96a8ba14fd Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sun, 23 Feb 2025 09:18:14 +0000 Subject: [PATCH] Codechange: Use local string parameters for order and timetable windows. Order display is now composed of concatenated strings instead of a complex 10-parameter format string, which simplifies things and fixes duplicate spaces. --- src/lang/english.txt | 84 ++++++++++++----------- src/order_gui.cpp | 133 +++++++++++++++++-------------------- src/timetable.h | 4 +- src/timetable_gui.cpp | 151 ++++++++++++++++++++++-------------------- 4 files changed, 185 insertions(+), 187 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index d4f74c1caa..1b6a54a484 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -4592,7 +4592,6 @@ STR_ORDERS_TIMETABLE_VIEW_TOOLTIP :{BLACK}Switch t STR_ORDERS_LIST_TOOLTIP :{BLACK}Order list - click on an order to highlight it. Ctrl+Click to scroll to the order's destination STR_ORDER_INDEX :{COMMA}:{NBSP} -STR_ORDER_TEXT :{STRING4} {STRING2} {STRING} {STRING} STR_ORDERS_END_OF_ORDERS :- - End of Orders - - STR_ORDERS_END_OF_SHARED_ORDERS :- - End of Shared Orders - - @@ -4691,63 +4690,62 @@ STR_ORDER_GO_NON_STOP_TO_WAYPOINT :Go non-stop via STR_ORDER_SERVICE_AT :Service at STR_ORDER_SERVICE_NON_STOP_AT :Service non-stop at -STR_ORDER_NEAREST_DEPOT :the nearest -STR_ORDER_NEAREST_HANGAR :the nearest Hangar ###length 3 STR_ORDER_TRAIN_DEPOT :Train Depot STR_ORDER_ROAD_VEHICLE_DEPOT :Road Vehicle Depot STR_ORDER_SHIP_DEPOT :Ship Depot ###next-name-looks-similar -STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} {STRING} {STRING} +STR_ORDER_GO_TO_NEAREST_HANGAR_FORMAT :{STRING} the nearest Hangar +STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} the nearest {STRING} STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT} -STR_ORDER_REFIT_ORDER :(Refit to {STRING}) -STR_ORDER_REFIT_STOP_ORDER :(Refit to {STRING} and stop) -STR_ORDER_STOP_ORDER :(Stop) +STR_ORDER_REFIT_ORDER :{SPACE}(Refit to {STRING}) +STR_ORDER_REFIT_STOP_ORDER :{SPACE}(Refit to {STRING} and stop) +STR_ORDER_STOP_ORDER :{SPACE}(Stop) -STR_ORDER_WAIT_TO_UNBUNCH :(Wait to unbunch) +STR_ORDER_WAIT_TO_UNBUNCH :{SPACE}(Wait to unbunch) -STR_ORDER_GO_TO_STATION :{STRING} {STATION} {STRING1} -STR_ORDER_GO_TO_STATION_CAN_T_USE_STATION :{PUSH_COLOUR}{RED}(Can't use station){POP_COLOUR} {STRING} {STATION} {STRING1} +STR_ORDER_GO_TO_STATION :{STRING} {STATION} +STR_ORDER_GO_TO_STATION_CAN_T_USE_STATION :{PUSH_COLOUR}{RED}(Can't use station){POP_COLOUR} {STRING} {STATION} -STR_ORDER_IMPLICIT :(Implicit) +STR_ORDER_IMPLICIT :{SPACE}(Implicit) -STR_ORDER_FULL_LOAD :(Full load) -STR_ORDER_FULL_LOAD_ANY :(Full load any cargo) -STR_ORDER_NO_LOAD :(No loading) -STR_ORDER_UNLOAD :(Unload and take cargo) -STR_ORDER_UNLOAD_FULL_LOAD :(Unload and wait for full load) -STR_ORDER_UNLOAD_FULL_LOAD_ANY :(Unload and wait for any full load) -STR_ORDER_UNLOAD_NO_LOAD :(Unload and leave empty) -STR_ORDER_TRANSFER :(Transfer and take cargo) -STR_ORDER_TRANSFER_FULL_LOAD :(Transfer and wait for full load) -STR_ORDER_TRANSFER_FULL_LOAD_ANY :(Transfer and wait for any full load) -STR_ORDER_TRANSFER_NO_LOAD :(Transfer and leave empty) -STR_ORDER_NO_UNLOAD :(No unloading and take cargo) -STR_ORDER_NO_UNLOAD_FULL_LOAD :(No unloading and wait for full load) -STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :(No unloading and wait for any full load) -STR_ORDER_NO_UNLOAD_NO_LOAD :(No unloading and no loading) +STR_ORDER_FULL_LOAD :{SPACE}(Full load) +STR_ORDER_FULL_LOAD_ANY :{SPACE}(Full load any cargo) +STR_ORDER_NO_LOAD :{SPACE}(No loading) +STR_ORDER_UNLOAD :{SPACE}(Unload and take cargo) +STR_ORDER_UNLOAD_FULL_LOAD :{SPACE}(Unload and wait for full load) +STR_ORDER_UNLOAD_FULL_LOAD_ANY :{SPACE}(Unload and wait for any full load) +STR_ORDER_UNLOAD_NO_LOAD :{SPACE}(Unload and leave empty) +STR_ORDER_TRANSFER :{SPACE}(Transfer and take cargo) +STR_ORDER_TRANSFER_FULL_LOAD :{SPACE}(Transfer and wait for full load) +STR_ORDER_TRANSFER_FULL_LOAD_ANY :{SPACE}(Transfer and wait for any full load) +STR_ORDER_TRANSFER_NO_LOAD :{SPACE}(Transfer and leave empty) +STR_ORDER_NO_UNLOAD :{SPACE}(No unloading and take cargo) +STR_ORDER_NO_UNLOAD_FULL_LOAD :{SPACE}(No unloading and wait for full load) +STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :{SPACE}(No unloading and wait for any full load) +STR_ORDER_NO_UNLOAD_NO_LOAD :{SPACE}(No unloading and no loading) -STR_ORDER_AUTO_REFIT :(Refit to {STRING}) -STR_ORDER_FULL_LOAD_REFIT :(Full load with refit to {STRING}) -STR_ORDER_FULL_LOAD_ANY_REFIT :(Full load any cargo with refit to {STRING}) -STR_ORDER_UNLOAD_REFIT :(Unload and take cargo with refit to {STRING}) -STR_ORDER_UNLOAD_FULL_LOAD_REFIT :(Unload and wait for full load with refit to {STRING}) -STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :(Unload and wait for any full load with refit to {STRING}) -STR_ORDER_TRANSFER_REFIT :(Transfer and take cargo with refit to {STRING}) -STR_ORDER_TRANSFER_FULL_LOAD_REFIT :(Transfer and wait for full load with refit to {STRING}) -STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :(Transfer and wait for any full load with refit to {STRING}) -STR_ORDER_NO_UNLOAD_REFIT :(No unloading and take cargo with refit to {STRING}) -STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :(No unloading and wait for full load with refit to {STRING}) -STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :(No unloading and wait for any full load with refit to {STRING}) +STR_ORDER_AUTO_REFIT :{SPACE}(Refit to {STRING}) +STR_ORDER_FULL_LOAD_REFIT :{SPACE}(Full load with refit to {STRING}) +STR_ORDER_FULL_LOAD_ANY_REFIT :{SPACE}(Full load any cargo with refit to {STRING}) +STR_ORDER_UNLOAD_REFIT :{SPACE}(Unload and take cargo with refit to {STRING}) +STR_ORDER_UNLOAD_FULL_LOAD_REFIT :{SPACE}(Unload and wait for full load with refit to {STRING}) +STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :{SPACE}(Unload and wait for any full load with refit to {STRING}) +STR_ORDER_TRANSFER_REFIT :{SPACE}(Transfer and take cargo with refit to {STRING}) +STR_ORDER_TRANSFER_FULL_LOAD_REFIT :{SPACE}(Transfer and wait for full load with refit to {STRING}) +STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :{SPACE}(Transfer and wait for any full load with refit to {STRING}) +STR_ORDER_NO_UNLOAD_REFIT :{SPACE}(No unloading and take cargo with refit to {STRING}) +STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :{SPACE}(No unloading and wait for full load with refit to {STRING}) +STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :{SPACE}(No unloading and wait for any full load with refit to {STRING}) STR_ORDER_AUTO_REFIT_ANY :available cargo ###length 3 -STR_ORDER_STOP_LOCATION_NEAR_END :[near end] -STR_ORDER_STOP_LOCATION_MIDDLE :[middle] -STR_ORDER_STOP_LOCATION_FAR_END :[far end] +STR_ORDER_STOP_LOCATION_NEAR_END :{SPACE}[near end] +STR_ORDER_STOP_LOCATION_MIDDLE :{SPACE}[middle] +STR_ORDER_STOP_LOCATION_FAR_END :{SPACE}[far end] STR_ORDER_OUT_OF_RANGE :{RED} (Next destination is out of range) @@ -4772,8 +4770,8 @@ STR_TIMETABLE_TRAVEL_FOR :Travel for {STR STR_TIMETABLE_TRAVEL_FOR_SPEED :Travel for {STRING1} with at most {VELOCITY} STR_TIMETABLE_TRAVEL_FOR_ESTIMATED :Travel (for {STRING1}, not timetabled) STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED :Travel (for {STRING1}, not timetabled) with at most {VELOCITY} -STR_TIMETABLE_STAY_FOR_ESTIMATED :(stay for {STRING1}, not timetabled) -STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :(travel for {STRING1}, not timetabled) +STR_TIMETABLE_STAY_FOR_ESTIMATED :{SPACE}(stay for {STRING1}, not timetabled) +STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :{SPACE}(travel for {STRING1}, not timetabled) STR_TIMETABLE_STAY_FOR :and stay for {STRING1} STR_TIMETABLE_AND_TRAVEL_FOR :and travel for {STRING1} diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 727e5f44bd..c881825966 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -45,7 +45,7 @@ static const StringID _station_load_types[][5][5] = { { /* No refitting. */ { - STR_EMPTY, + INVALID_STRING_ID, INVALID_STRING_ID, STR_ORDER_FULL_LOAD, STR_ORDER_FULL_LOAD_ANY, @@ -68,6 +68,7 @@ static const StringID _station_load_types[][5][5] = { INVALID_STRING_ID, INVALID_STRING_ID, INVALID_STRING_ID, + INVALID_STRING_ID, }, { STR_ORDER_NO_UNLOAD, INVALID_STRING_ID, @@ -101,6 +102,7 @@ static const StringID _station_load_types[][5][5] = { INVALID_STRING_ID, INVALID_STRING_ID, INVALID_STRING_ID, + INVALID_STRING_ID, }, { STR_ORDER_NO_UNLOAD_REFIT, INVALID_STRING_ID, @@ -199,6 +201,15 @@ static const StringID _order_refit_action_dropdown[] = { STR_ORDER_DROP_REFIT_AUTO_ANY, }; +static StringID GetOrderGoToString(const Order &order) +{ + if (order.GetDepotOrderType() & ODTFB_SERVICE) { + return (order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) ? STR_ORDER_SERVICE_NON_STOP_AT : STR_ORDER_SERVICE_AT; + } else { + return (order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) ? STR_ORDER_GO_NON_STOP_TO : STR_ORDER_GO_TO; + } +} + /** * Draws an order in order or timetable GUI * @param v Vehicle the order belongs to @@ -233,30 +244,18 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int colour = TC_WHITE; } - SetDParam(0, order_index + 1); - DrawString(left, rtl ? right - 2 * sprite_size.width - 3 : middle, y, STR_ORDER_INDEX, colour, SA_RIGHT | SA_FORCE); + DrawString(left, rtl ? right - 2 * sprite_size.width - 3 : middle, y, GetString(STR_ORDER_INDEX, order_index + 1), colour, SA_RIGHT | SA_FORCE); - SetDParam(5, STR_EMPTY); - SetDParam(8, STR_EMPTY); - SetDParam(9, STR_EMPTY); - - /* Check range for aircraft. */ - if (v->type == VEH_AIRCRAFT && Aircraft::From(v)->GetRange() > 0 && order->IsGotoOrder()) { - const Order *next = order->next != nullptr ? order->next : v->GetFirstOrder(); - if (GetOrderDistance(order, next, v) > Aircraft::From(v)->acache.cached_max_range_sqr) SetDParam(9, STR_ORDER_OUT_OF_RANGE); - } + std::string line; switch (order->GetType()) { case OT_DUMMY: - SetDParam(0, STR_INVALID_ORDER); - SetDParam(1, order->GetDestination()); + line = GetString(STR_INVALID_ORDER); break; case OT_IMPLICIT: - SetDParam(0, STR_ORDER_GO_TO_STATION); - SetDParam(1, STR_ORDER_GO_TO); - SetDParam(2, order->GetDestination()); - SetDParam(3, timetable ? STR_EMPTY : STR_ORDER_IMPLICIT); + line = GetString(STR_ORDER_GO_TO_STATION, STR_ORDER_GO_TO, order->GetDestination()); + if (!timetable) line += GetString(STR_ORDER_IMPLICIT); break; case OT_GOTO_STATION: { @@ -264,30 +263,30 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int OrderUnloadFlags unload = order->GetUnloadType(); bool valid_station = CanVehicleUseStation(v, Station::Get(order->GetDestination().ToStationID())); - SetDParam(0, valid_station ? STR_ORDER_GO_TO_STATION : STR_ORDER_GO_TO_STATION_CAN_T_USE_STATION); - SetDParam(1, STR_ORDER_GO_TO + (v->IsGroundVehicle() ? order->GetNonStopType() : 0)); - SetDParam(2, order->GetDestination()); - + line = GetString(valid_station ? STR_ORDER_GO_TO_STATION : STR_ORDER_GO_TO_STATION_CAN_T_USE_STATION, STR_ORDER_GO_TO + (v->IsGroundVehicle() ? order->GetNonStopType() : 0), order->GetDestination()); if (timetable) { /* Show only wait time in the timetable window. */ - SetDParam(3, STR_EMPTY); - if (order->GetWaitTime() > 0) { - SetDParam(5, order->IsWaitTimetabled() ? STR_TIMETABLE_STAY_FOR : STR_TIMETABLE_STAY_FOR_ESTIMATED); - SetTimetableParams(6, 7, order->GetWaitTime()); + auto [str, value] = GetTimetableParameters(order->GetWaitTime()); + line += GetString(order->IsWaitTimetabled() ? STR_TIMETABLE_STAY_FOR : STR_TIMETABLE_STAY_FOR_ESTIMATED, str, value); } } else { /* Show non-stop, refit and stop location only in the order window. */ - SetDParam(3, (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) ? STR_EMPTY : _station_load_types[order->IsRefit()][unload][load]); - if (order->IsRefit()) { - SetDParam(4, order->IsAutoRefit() ? STR_ORDER_AUTO_REFIT_ANY : CargoSpec::Get(order->GetRefitCargo())->name); + if (!(order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) { + StringID str = _station_load_types[order->IsRefit()][unload][load]; + if (str != INVALID_STRING_ID) { + if (order->IsRefit()) { + line += GetString(str, order->IsAutoRefit() ? STR_ORDER_AUTO_REFIT_ANY : CargoSpec::Get(order->GetRefitCargo())->name); + } else { + line += GetString(str); + } + } } + if (v->type == VEH_TRAIN && (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) == 0) { /* Only show the stopping location if other than the default chosen by the player. */ if (order->GetStopLocation() != (OrderStopLocation)(_settings_client.gui.stop_location)) { - SetDParam(5, STR_ORDER_STOP_LOCATION_NEAR_END + order->GetStopLocation()); - } else { - SetDParam(5, STR_EMPTY); + line += GetString(STR_ORDER_STOP_LOCATION_NEAR_END + order->GetStopLocation()); } } } @@ -295,79 +294,71 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int } case OT_GOTO_DEPOT: - if (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) { - /* Going to the nearest depot. */ - SetDParam(0, STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT); - if (v->type == VEH_AIRCRAFT) { - SetDParam(2, STR_ORDER_NEAREST_HANGAR); - SetDParam(3, STR_EMPTY); - } else { - SetDParam(2, STR_ORDER_NEAREST_DEPOT); - SetDParam(3, STR_ORDER_TRAIN_DEPOT + v->type); - } - } else { + if (!(order->GetDepotActionType() & ODATFB_NEAREST_DEPOT)) { /* Going to a specific depot. */ - SetDParam(0, STR_ORDER_GO_TO_DEPOT_FORMAT); - SetDParam(2, v->type); - SetDParam(3, order->GetDestination()); - } - - if (order->GetDepotOrderType() & ODTFB_SERVICE) { - SetDParam(1, (order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) ? STR_ORDER_SERVICE_NON_STOP_AT : STR_ORDER_SERVICE_AT); + line = GetString(STR_ORDER_GO_TO_DEPOT_FORMAT, GetOrderGoToString(*order), v->type, order->GetDestination()); + } else if (v->type == VEH_AIRCRAFT) { + /* Going to the nearest hangar. */ + line = GetString(STR_ORDER_GO_TO_NEAREST_HANGAR_FORMAT, GetOrderGoToString(*order)); } else { - SetDParam(1, (order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) ? STR_ORDER_GO_NON_STOP_TO : STR_ORDER_GO_TO); + /* Going to the nearest depot. */ + line = GetString(STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT, GetOrderGoToString(*order), STR_ORDER_TRAIN_DEPOT + v->type); } /* Do not show stopping in the depot in the timetable window. */ if (!timetable && (order->GetDepotActionType() & ODATFB_HALT)) { - SetDParam(5, STR_ORDER_STOP_ORDER); + line += GetString(STR_ORDER_STOP_ORDER); } /* Do not show refitting in the depot in the timetable window. */ if (!timetable && order->IsRefit()) { - SetDParam(5, (order->GetDepotActionType() & ODATFB_HALT) ? STR_ORDER_REFIT_STOP_ORDER : STR_ORDER_REFIT_ORDER); - SetDParam(6, CargoSpec::Get(order->GetRefitCargo())->name); + line += GetString((order->GetDepotActionType() & ODATFB_HALT) ? STR_ORDER_REFIT_STOP_ORDER : STR_ORDER_REFIT_ORDER, CargoSpec::Get(order->GetRefitCargo())->name); } /* Show unbunching depot in both order and timetable windows. */ if (order->GetDepotActionType() & ODATFB_UNBUNCH) { - SetDParam(8, STR_ORDER_WAIT_TO_UNBUNCH); + line += GetString(STR_ORDER_WAIT_TO_UNBUNCH); } - break; case OT_GOTO_WAYPOINT: - SetDParam(0, (order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) ? STR_ORDER_GO_NON_STOP_TO_WAYPOINT : STR_ORDER_GO_TO_WAYPOINT); - SetDParam(1, order->GetDestination()); + line = GetString((order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) ? STR_ORDER_GO_NON_STOP_TO_WAYPOINT : STR_ORDER_GO_TO_WAYPOINT, order->GetDestination()); break; case OT_CONDITIONAL: - SetDParam(1, order->GetConditionSkipToOrder() + 1); if (order->GetConditionVariable() == OCV_UNCONDITIONALLY) { - SetDParam(0, STR_ORDER_CONDITIONAL_UNCONDITIONAL); + line = GetString(STR_ORDER_CONDITIONAL_UNCONDITIONAL, order->GetConditionSkipToOrder() + 1); } else { OrderConditionComparator occ = order->GetConditionComparator(); - SetDParam(0, (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) ? STR_ORDER_CONDITIONAL_TRUE_FALSE : STR_ORDER_CONDITIONAL_NUM); - SetDParam(2, STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE + order->GetConditionVariable()); - SetDParam(3, STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS + occ); uint value = order->GetConditionValue(); if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value, v->type); - SetDParam(4, value); + + line = GetString((occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) ? STR_ORDER_CONDITIONAL_TRUE_FALSE : STR_ORDER_CONDITIONAL_NUM, + order->GetConditionSkipToOrder() + 1, + STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE + order->GetConditionVariable(), + STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS + occ, + value); } if (timetable && order->GetWaitTime() > 0) { - SetDParam(5, order->IsWaitTimetabled() ? STR_TIMETABLE_AND_TRAVEL_FOR : STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED); - SetTimetableParams(6, 7, order->GetWaitTime()); - } else { - SetDParam(5, STR_EMPTY); + auto [str, value] = GetTimetableParameters(order->GetWaitTime()); + line += GetString(order->IsWaitTimetabled() ? STR_TIMETABLE_AND_TRAVEL_FOR : STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED, str, value); } break; default: NOT_REACHED(); } - DrawString(rtl ? left : middle, rtl ? middle : right, y, STR_ORDER_TEXT, colour); + /* Check range for aircraft. */ + if (v->type == VEH_AIRCRAFT && Aircraft::From(v)->GetRange() > 0 && order->IsGotoOrder()) { + const Order *next = order->next != nullptr ? order->next : v->GetFirstOrder(); + if (GetOrderDistance(order, next, v) > Aircraft::From(v)->acache.cached_max_range_sqr) { + line += GetString(STR_ORDER_OUT_OF_RANGE); + } + } + + DrawString(rtl ? left : middle, rtl ? middle : right, y, line, colour); } /** @@ -1116,8 +1107,8 @@ public: Rect ir = r.Shrink(WidgetDimensions::scaled.frametext, WidgetDimensions::scaled.framerect); bool rtl = _current_text_dir == TD_RTL; - SetDParamMaxValue(0, this->vehicle->GetNumOrders(), 2); - int index_column_width = GetStringBoundingBox(STR_ORDER_INDEX).width + 2 * GetSpriteSize(rtl ? SPR_ARROW_RIGHT : SPR_ARROW_LEFT).width + WidgetDimensions::scaled.hsep_normal; + uint64_t max_value = GetParamMaxValue(this->vehicle->GetNumOrders(), 2); + int index_column_width = GetStringBoundingBox(GetString(STR_ORDER_INDEX, max_value)).width + 2 * GetSpriteSize(rtl ? SPR_ARROW_RIGHT : SPR_ARROW_LEFT).width + WidgetDimensions::scaled.hsep_normal; int middle = rtl ? ir.right - index_column_width : ir.left + index_column_width; int y = ir.top; diff --git a/src/timetable.h b/src/timetable.h index dd1607e294..1c15c00d40 100644 --- a/src/timetable.h +++ b/src/timetable.h @@ -10,6 +10,7 @@ #ifndef TIMETABLE_H #define TIMETABLE_H +#include "strings_type.h" #include "timer/timer_game_tick.h" #include "timer/timer_game_economy.h" #include "vehicle_type.h" @@ -27,6 +28,7 @@ TimerGameEconomy::Date GetDateFromStartTick(TimerGameTick::TickCounter start_tic void ShowTimetableWindow(const Vehicle *v); void UpdateVehicleTimetable(Vehicle *v, bool travelling); -void SetTimetableParams(int param1, int param2, TimerGameTick::Ticks ticks); + +std::pair GetTimetableParameters(TimerGameTick::Ticks ticks); #endif /* TIMETABLE_H */ diff --git a/src/timetable_gui.cpp b/src/timetable_gui.cpp index 5b3d3208db..cbe56d655a 100644 --- a/src/timetable_gui.cpp +++ b/src/timetable_gui.cpp @@ -42,26 +42,16 @@ struct TimetableArrivalDeparture { }; /** - * Set the timetable parameters in the format as described by the setting. - * @param param1 the first DParam to fill - * @param param2 the second DParam to fill - * @param ticks the number of ticks to 'draw' + * Get parameters to format timetable time. + * @param ticks Number of ticks to format. + * @returns Pair of parameters to format timetable time. */ -void SetTimetableParams(int param1, int param2, TimerGameTick::Ticks ticks) +std::pair GetTimetableParameters(TimerGameTick::Ticks ticks) { switch (_settings_client.gui.timetable_mode) { - case TimetableMode::Days: - SetDParam(param1, STR_UNITS_DAYS); - SetDParam(param2, ticks / Ticks::DAY_TICKS); - break; - case TimetableMode::Seconds: - SetDParam(param1, STR_UNITS_SECONDS); - SetDParam(param2, ticks / Ticks::TICKS_PER_SECOND); - break; - case TimetableMode::Ticks: - SetDParam(param1, STR_UNITS_TICKS); - SetDParam(param2, ticks); - break; + case TimetableMode::Days: return {STR_UNITS_DAYS, ticks / Ticks::DAY_TICKS}; + case TimetableMode::Seconds: return {STR_UNITS_SECONDS, ticks / Ticks::TICKS_PER_SECOND}; + case TimetableMode::Ticks: return {STR_UNITS_TICKS, ticks}; default: NOT_REACHED(); } @@ -255,11 +245,17 @@ struct TimetableWindow : Window { /* We handle this differently depending on the timetable mode. */ if (_settings_client.gui.timetable_mode == TimetableMode::Seconds) { /* A five-digit number would fit a timetable lasting 2.7 real-world hours, which should be plenty. */ - SetDParamMaxDigits(1, 4, FS_SMALL); - size.width = std::max(GetStringBoundingBox(STR_TIMETABLE_ARRIVAL_SECONDS_IN_FUTURE).width, GetStringBoundingBox(STR_TIMETABLE_DEPARTURE_SECONDS_IN_FUTURE).width) + WidgetDimensions::scaled.hsep_wide + padding.width; + uint64_t max_digits = GetParamMaxDigits(4, FS_SMALL); + size.width = std::max( + GetStringBoundingBox(GetString(STR_TIMETABLE_ARRIVAL_SECONDS_IN_FUTURE, TC_BLACK, max_digits)).width, + GetStringBoundingBox(GetString(STR_TIMETABLE_DEPARTURE_SECONDS_IN_FUTURE, TC_BLACK, max_digits)).width) + + WidgetDimensions::scaled.hsep_wide + padding.width; } else { - SetDParamMaxValue(1, TimerGameEconomy::DateAtStartOfYear(EconomyTime::MAX_YEAR), 0, FS_SMALL); - size.width = std::max(GetStringBoundingBox(STR_TIMETABLE_ARRIVAL_DATE).width, GetStringBoundingBox(STR_TIMETABLE_DEPARTURE_DATE).width) + WidgetDimensions::scaled.hsep_wide + padding.width; + uint64_t max_value = GetParamMaxValue(TimerGameEconomy::DateAtStartOfYear(EconomyTime::MAX_YEAR).base(), 0, FS_SMALL); + size.width = std::max( + GetStringBoundingBox(GetString(STR_TIMETABLE_ARRIVAL_DATE, TC_BLACK, max_value)).width, + GetStringBoundingBox(GetString(STR_TIMETABLE_DEPARTURE_DATE, TC_BLACK, max_value)).width) + + WidgetDimensions::scaled.hsep_wide + padding.width; } [[fallthrough]]; @@ -410,6 +406,38 @@ struct TimetableWindow : Window { } } + std::string GetTimetableTravelString(const Order &order, int i, TextColour &colour) const + { + colour = (i == this->sel_index) ? TC_WHITE : TC_BLACK; + + if (order.IsType(OT_CONDITIONAL)) { + return GetString(STR_TIMETABLE_NO_TRAVEL); + } + + if (order.IsType(OT_IMPLICIT)) { + colour = ((i == this->sel_index) ? TC_SILVER : TC_GREY) | TC_NO_SHADE; + return GetString(STR_TIMETABLE_NOT_TIMETABLEABLE); + } + + if (order.IsTravelTimetabled()) { + auto [str, value] = GetTimetableParameters(order.GetTimetabledTravel()); + return order.GetMaxSpeed() != UINT16_MAX + ? GetString(STR_TIMETABLE_TRAVEL_FOR_SPEED, str, value, PackVelocity(order.GetMaxSpeed(), this->vehicle->type)) + : GetString(STR_TIMETABLE_TRAVEL_FOR, str, value); + } + + if (order.GetTravelTime() > 0) { + auto [str, value] = GetTimetableParameters(order.GetTravelTime()); + return order.GetMaxSpeed() != UINT16_MAX + ? GetString(STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED, str, value, PackVelocity(order.GetMaxSpeed(), this->vehicle->type)) + : GetString(STR_TIMETABLE_TRAVEL_FOR_ESTIMATED, str, value); + } + + return order.GetMaxSpeed() != UINT16_MAX + ? GetString(STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED, PackVelocity(order.GetMaxSpeed(), this->vehicle->type)) + : GetString(STR_TIMETABLE_TRAVEL_NOT_TIMETABLED); + } + /** * Helper function to draw the timetable panel. * @param r The rect to draw within. @@ -424,8 +452,7 @@ struct TimetableWindow : Window { int selected = this->sel_index; bool rtl = _current_text_dir == TD_RTL; - SetDParamMaxValue(0, v->GetNumOrders(), 2); - int index_column_width = GetStringBoundingBox(STR_ORDER_INDEX).width + 2 * GetSpriteSize(rtl ? SPR_ARROW_RIGHT : SPR_ARROW_LEFT).width + WidgetDimensions::scaled.hsep_normal; + int index_column_width = GetStringBoundingBox(GetString(STR_ORDER_INDEX, GetParamMaxValue(v->GetNumOrders(), 2))).width + 2 * GetSpriteSize(rtl ? SPR_ARROW_RIGHT : SPR_ARROW_LEFT).width + WidgetDimensions::scaled.hsep_normal; int middle = rtl ? tr.right - index_column_width : tr.left + index_column_width; const Order *order = v->GetOrder(order_id); @@ -445,30 +472,8 @@ struct TimetableWindow : Window { order = order->next; } } else { - StringID string; - TextColour colour = (i == selected) ? TC_WHITE : TC_BLACK; - if (order->IsType(OT_CONDITIONAL)) { - string = STR_TIMETABLE_NO_TRAVEL; - } else if (order->IsType(OT_IMPLICIT)) { - string = STR_TIMETABLE_NOT_TIMETABLEABLE; - colour = ((i == selected) ? TC_SILVER : TC_GREY) | TC_NO_SHADE; - } else if (!order->IsTravelTimetabled()) { - if (order->GetTravelTime() > 0) { - SetTimetableParams(0, 1, order->GetTravelTime()); - string = order->GetMaxSpeed() != UINT16_MAX ? - STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED : - STR_TIMETABLE_TRAVEL_FOR_ESTIMATED; - } else { - string = order->GetMaxSpeed() != UINT16_MAX ? - STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED : - STR_TIMETABLE_TRAVEL_NOT_TIMETABLED; - } - } else { - SetTimetableParams(0, 1, order->GetTimetabledTravel()); - string = order->GetMaxSpeed() != UINT16_MAX ? - STR_TIMETABLE_TRAVEL_FOR_SPEED : STR_TIMETABLE_TRAVEL_FOR; - } - SetDParam(2, PackVelocity(order->GetMaxSpeed(), v->type)); + TextColour colour; + std::string string = GetTimetableTravelString(*order, i, colour); DrawString(rtl ? tr.left : middle, rtl ? middle : tr.right, tr.top, string, colour); @@ -509,7 +514,7 @@ struct TimetableWindow : Window { if (!this->vscroll->IsVisible(i)) break; /* TC_INVALID will skip the colour change. */ - SetDParam(0, show_late ? TC_RED : TC_INVALID); + TextColour tc = show_late ? TC_RED : TC_INVALID; if (i % 2 == 0) { /* Draw an arrival time. */ if (arr_dep[i / 2].arrival != Ticks::INVALID_TICKS) { @@ -518,7 +523,7 @@ struct TimetableWindow : Window { if (this->show_expected && i / 2 == earlyID) { /* Show expected arrival. */ this_offset = 0; - SetDParam(0, TC_GREEN); + tc = TC_GREEN; } else { /* Show scheduled arrival. */ this_offset = offset; @@ -527,12 +532,14 @@ struct TimetableWindow : Window { /* Now actually draw the arrival time. */ if (_settings_client.gui.timetable_mode == TimetableMode::Seconds) { /* Display seconds from now. */ - SetDParam(1, ((arr_dep[i / 2].arrival + offset) / Ticks::TICKS_PER_SECOND)); - DrawString(tr.left, tr.right, tr.top, STR_TIMETABLE_ARRIVAL_SECONDS_IN_FUTURE, i == selected ? TC_WHITE : TC_BLACK); + DrawString(tr.left, tr.right, tr.top, + GetString(STR_TIMETABLE_ARRIVAL_SECONDS_IN_FUTURE, tc, (arr_dep[i / 2].arrival + offset) / Ticks::TICKS_PER_SECOND), + i == selected ? TC_WHITE : TC_BLACK); } else { /* Show a date. */ - SetDParam(1, TimerGameEconomy::date + (arr_dep[i / 2].arrival + this_offset) / Ticks::DAY_TICKS); - DrawString(tr.left, tr.right, tr.top, STR_TIMETABLE_ARRIVAL_DATE, i == selected ? TC_WHITE : TC_BLACK); + DrawString(tr.left, tr.right, tr.top, + GetString(STR_TIMETABLE_ARRIVAL_DATE, tc, TimerGameEconomy::date + (arr_dep[i / 2].arrival + this_offset) / Ticks::DAY_TICKS), + i == selected ? TC_WHITE : TC_BLACK); } } } else { @@ -540,12 +547,14 @@ struct TimetableWindow : Window { if (arr_dep[i / 2].departure != Ticks::INVALID_TICKS) { if (_settings_client.gui.timetable_mode == TimetableMode::Seconds) { /* Display seconds from now. */ - SetDParam(1, ((arr_dep[i / 2].departure + offset) / Ticks::TICKS_PER_SECOND)); - DrawString(tr.left, tr.right, tr.top, STR_TIMETABLE_DEPARTURE_SECONDS_IN_FUTURE, i == selected ? TC_WHITE : TC_BLACK); + DrawString(tr.left, tr.right, tr.top, + GetString(STR_TIMETABLE_DEPARTURE_SECONDS_IN_FUTURE, tc, (arr_dep[i / 2].departure + offset) / Ticks::TICKS_PER_SECOND), + i == selected ? TC_WHITE : TC_BLACK); } else { /* Show a date. */ - SetDParam(1, TimerGameEconomy::date + (arr_dep[i / 2].departure + offset) / Ticks::DAY_TICKS); - DrawString(tr.left, tr.right, tr.top, STR_TIMETABLE_DEPARTURE_DATE, i == selected ? TC_WHITE : TC_BLACK); + DrawString(tr.left, tr.right, tr.top, + GetString(STR_TIMETABLE_DEPARTURE_DATE, tc, TimerGameEconomy::date + (arr_dep[i / 2].departure + offset) / Ticks::DAY_TICKS), + i == selected ? TC_WHITE : TC_BLACK); } } } @@ -553,6 +562,14 @@ struct TimetableWindow : Window { } } + std::string GetTimetableTotalTimeString(TimerGameTick::Ticks total_time) const + { + auto [str, value] = GetTimetableParameters(total_time); + if (!this->vehicle->orders->IsCompleteTimetable()) return GetString(STR_TIMETABLE_TOTAL_TIME_INCOMPLETE, str, value); + if (total_time % TicksPerTimetableUnit() == 0) return GetString(STR_TIMETABLE_TOTAL_TIME, str, value); + return GetString(STR_TIMETABLE_APPROX_TIME, str, value); + } + /** * Helper function to draw the summary panel. * @param r The rect to draw within. @@ -564,14 +581,7 @@ struct TimetableWindow : Window { TimerGameTick::Ticks total_time = v->orders != nullptr ? v->orders->GetTimetableDurationIncomplete() : 0; if (total_time != 0) { - SetTimetableParams(0, 1, total_time); - if (!v->orders->IsCompleteTimetable()) { - DrawString(tr, STR_TIMETABLE_TOTAL_TIME_INCOMPLETE); - } else if (total_time % TicksPerTimetableUnit() == 0) { - DrawString(tr, STR_TIMETABLE_TOTAL_TIME); - } else { - DrawString(tr, STR_TIMETABLE_APPROX_TIME); - } + DrawString(tr, GetTimetableTotalTimeString(total_time)); } tr.top += GetCharacterHeight(FS_NORMAL); @@ -581,13 +591,10 @@ struct TimetableWindow : Window { * timetable at the given time. */ if (_settings_client.gui.timetable_mode == TimetableMode::Seconds) { /* Real time units use seconds relative to now. */ - SetDParam(0, (static_cast(v->timetable_start - TimerGameTick::counter) / Ticks::TICKS_PER_SECOND)); - DrawString(tr, STR_TIMETABLE_STATUS_START_IN_SECONDS); + DrawString(tr, GetString(STR_TIMETABLE_STATUS_START_IN_SECONDS, static_cast(v->timetable_start - TimerGameTick::counter) / Ticks::TICKS_PER_SECOND)); } else { /* Other units use dates. */ - SetDParam(0, STR_JUST_DATE_TINY); - SetDParam(1, GetDateFromStartTick(v->timetable_start)); - DrawString(tr, STR_TIMETABLE_STATUS_START_AT_DATE); + DrawString(tr, GetString(STR_TIMETABLE_STATUS_START_AT_DATE, STR_JUST_DATE_TINY, GetDateFromStartTick(v->timetable_start))); } } else if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) { /* We aren't running on a timetable yet. */ @@ -597,8 +604,8 @@ struct TimetableWindow : Window { DrawString(tr, STR_TIMETABLE_STATUS_ON_TIME); } else { /* We are late. */ - SetTimetableParams(0, 1, abs(v->lateness_counter)); - DrawString(tr, v->lateness_counter < 0 ? STR_TIMETABLE_STATUS_EARLY : STR_TIMETABLE_STATUS_LATE); + auto [str, value] = GetTimetableParameters(abs(v->lateness_counter)); + DrawString(tr, GetString(v->lateness_counter < 0 ? STR_TIMETABLE_STATUS_EARLY : STR_TIMETABLE_STATUS_LATE, str, value)); } }