1
0
Fork 0

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.
pull/13654/head
Peter Nelson 2025-02-23 09:18:14 +00:00 committed by Peter Nelson
parent 23ba18ada7
commit 7fd0e6c27d
4 changed files with 185 additions and 187 deletions

View File

@ -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}

View File

@ -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;

View File

@ -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<StringParameter, StringParameter> GetTimetableParameters(TimerGameTick::Ticks ticks);
#endif /* TIMETABLE_H */

View File

@ -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<StringParameter, StringParameter> 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<TimerGameTick::Ticks>(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<TimerGameTick::Ticks>(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));
}
}