Allow adding multiple scheduled dispatch departure slots at once

pull/340/head
Jonathan G Rennison 3 years ago
parent 6f38769b73
commit 0aeafeaf3a

@ -265,7 +265,7 @@ CommandProc CmdRemoveSignalInstruction;
CommandProc CmdSignalProgramMgmt;
CommandProc CmdScheduledDispatch;
CommandProc CmdScheduledDispatchAdd;
CommandProcEx CmdScheduledDispatchAdd;
CommandProc CmdScheduledDispatchRemove;
CommandProc CmdScheduledDispatchSetDuration;
CommandProc CmdScheduledDispatchSetStartDate;

@ -7063,6 +7063,7 @@ STR_SCHDISPATCH_ENABLED :{BLACK}Enable
STR_SCHDISPATCH_ENABLED_TOOLTIP :{BLACK}Enable scheduled dispatching for this order. Requires automatic separation to be off.
STR_SCHDISPATCH_ADD :{BLACK}Add Departure Slot
STR_SCHDISPATCH_ADD_TOOLTIP :{BLACK}Add new departure slot for this schedule.
STR_SCHDISPATCH_ADD_TOOLTIP_EXTRA :{BLACK}{STRING} Ctrl+Click to add multiple departure slots at once.
STR_SCHDISPATCH_ADD_CAPTION :{BLACK}Departure slot
STR_SCHDISPATCH_DURATION :{BLACK}Duration
STR_SCHDISPATCH_DURATION_TOOLTIP :{BLACK}Set duration of this schedule.
@ -7091,6 +7092,12 @@ STR_SCHDISPATCH_SUMMARY_NOT_ENABLED :{BLACK}This sch
STR_SCHDISPATCH_SLOT_OUTSIDE_SCHEDULE :{BLACK}One or more departure slots are outside the schedule duration.
STR_SCHDISPATCH_ADD_DEPARTURE_SLOTS_START :{BLACK}Start:
STR_SCHDISPATCH_ADD_DEPARTURE_SLOTS_STEP :{BLACK}Period:
STR_SCHDISPATCH_ADD_DEPARTURE_SLOTS_END :{BLACK}End:
STR_ERROR_SCHDISPATCH_TRIED_TO_ADD_TOO_MANY_SLOTS :{WHITE}Tried to add too many departure slots at once
# Modifier key toggle window
STR_MODIFIER_KEY_TOGGLE_CAPTION :{WHITE}Modifier keys
STR_SHIFT_KEY_NAME :{BLACK}Shift

@ -73,12 +73,17 @@ CommandCost CmdScheduledDispatch(TileIndex tile, DoCommandFlag flags, uint32 p1,
* @param flags Operation to perform.
* @param p1 Vehicle index.
* @param p2 Offset time to add.
* @param p3 various bitstuffed elements
* - p3 = (bit 0 - 31) - the offset for additional slots
* - p3 = (bit 32 - 47) - the number of additional slots to add
* @param text unused
* @return the cost of this operation or an error
*/
CommandCost CmdScheduledDispatchAdd(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
CommandCost CmdScheduledDispatchAdd(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length)
{
VehicleID veh = GB(p1, 0, 20);
uint32 offset = GB(p3, 0, 32);
uint32 extra_slots = GB(p3, 32, 16);
Vehicle *v = Vehicle::GetIfValid(veh);
if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
@ -88,8 +93,15 @@ CommandCost CmdScheduledDispatchAdd(TileIndex tile, DoCommandFlag flags, uint32
if (v->orders.list == nullptr) return CMD_ERROR;
if (extra_slots > 512) return_cmd_error(STR_ERROR_SCHDISPATCH_TRIED_TO_ADD_TOO_MANY_SLOTS);
if (extra_slots > 0 && offset == 0) return CMD_ERROR;
if (flags & DC_EXEC) {
v->orders.list->AddScheduledDispatch(p2);
for (uint i = 0; i < extra_slots; i++) {
p2 += offset;
v->orders.list->AddScheduledDispatch(p2);
}
SetWindowDirty(WC_SCHDISPATCH_SLOTS, v->index);
}

@ -25,6 +25,7 @@
#include "settings_type.h"
#include "viewport_func.h"
#include "zoom_func.h"
#include "core/geometry_func.hpp"
#include <vector>
#include <algorithm>
@ -84,7 +85,7 @@ static void SetScheduleStartDateCallback(const Window *w, DateTicksScaled date)
* @param p1 The p1 parameter to send to CmdScheduledDispatchAdd
* @param date the actually chosen date
*/
static void ScheduleAddIntl(uint32 p1, DateTicksScaled date)
static void ScheduleAddIntl(uint32 p1, DateTicksScaled date, uint extra_slots, uint offset)
{
VehicleID veh = GB(p1, 0, 20);
Vehicle *v = Vehicle::GetIfValid(veh);
@ -92,10 +93,18 @@ static void ScheduleAddIntl(uint32 p1, DateTicksScaled date)
/* Make sure the time is the closest future to the timetable start */
DateTicksScaled start_tick = v->orders.list->GetScheduledDispatchStartTick();
while (date > start_tick) date -= v->orders.list->GetScheduledDispatchDuration();
while (date < start_tick) date += v->orders.list->GetScheduledDispatchDuration();
uint32 duration = v->orders.list->GetScheduledDispatchDuration();
while (date > start_tick) date -= duration;
while (date < start_tick) date += duration;
if (extra_slots > 0 && offset > 0) {
DateTicksScaled end_tick = start_tick + duration;
DateTicksScaled max_extra_slots = (end_tick - 1 - date) / offset;
if (max_extra_slots < extra_slots) extra_slots = static_cast<uint>(std::max<DateTicksScaled>(0, max_extra_slots));
extra_slots = std::min<uint>(extra_slots, UINT16_MAX);
}
DoCommandP(0, v->index, (uint32)(date - start_tick), CMD_SCHEDULED_DISPATCH_ADD | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
DoCommandPEx(0, v->index, (uint32)(date - start_tick), (((uint64)extra_slots) << 32) | offset, CMD_SCHEDULED_DISPATCH_ADD | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE), nullptr, nullptr, 0);
}
/**
@ -105,7 +114,7 @@ static void ScheduleAddIntl(uint32 p1, DateTicksScaled date)
*/
static void ScheduleAddCallback(const Window *w, DateTicksScaled date)
{
ScheduleAddIntl(w->window_number, date);
ScheduleAddIntl(w->window_number, date, 0, 0);
}
/**
@ -265,6 +274,26 @@ struct SchdispatchWindow : Window {
}
}
virtual bool OnTooltip(Point pt, int widget, TooltipCloseCondition close_cond) override
{
switch (widget) {
case WID_SCHDISPATCH_ADD: {
if (_settings_time.time_in_minutes) {
uint64 params[1];
params[0] = STR_SCHDISPATCH_ADD_TOOLTIP;
GuiShowTooltips(this, STR_SCHDISPATCH_ADD_TOOLTIP_EXTRA, 1, params, close_cond);
return true;
}
break;
}
default:
break;
}
return false;
}
/**
* Draw a time in the box with the top left corner at x,y.
* @param time Time to draw.
@ -486,7 +515,10 @@ struct SchdispatchWindow : Window {
}
case WID_SCHDISPATCH_ADD: {
if (_settings_time.time_in_minutes && _settings_client.gui.timetable_start_text_entry) {
if (_settings_time.time_in_minutes && _ctrl_pressed) {
void ShowScheduledDispatchAddSlotsWindow(SchdispatchWindow *parent, int window_number);
ShowScheduledDispatchAddSlotsWindow(this, v->index);
} else if (_settings_time.time_in_minutes && _settings_client.gui.timetable_start_text_entry) {
ShowQueryString(STR_EMPTY, STR_SCHDISPATCH_ADD_CAPTION, 31, this, CS_NUMERAL, QSF_NONE);
} else {
ShowSetDateWindow(this, v->index, _scaled_date_ticks, _cur_year, _cur_year + 15, ScheduleAddCallback, STR_SCHDISPATCH_ADD, STR_SCHDISPATCH_ADD_TOOLTIP);
@ -548,7 +580,7 @@ struct SchdispatchWindow : Window {
DateTicksScaled slot = MINUTES_DATE(MINUTES_DAY(CURRENT_MINUTE), hours, minutes);
slot -= _settings_time.clock_offset;
slot *= _settings_time.ticks_per_minute;
ScheduleAddIntl(v->index, slot);
ScheduleAddIntl(v->index, slot, 0, 0);
}
break;
}
@ -614,6 +646,16 @@ struct SchdispatchWindow : Window {
{
return this->vehicle;
}
void AddMultipleDepartureSlots(uint start, uint step, uint end)
{
if (end < start || step == 0) return;
DateTicksScaled slot = MINUTES_DATE(MINUTES_DAY(CURRENT_MINUTE), 0, start);
slot -= _settings_time.clock_offset;
slot *= _settings_time.ticks_per_minute;
ScheduleAddIntl(this->vehicle->index, slot, (end - start) / step, step * _settings_time.ticks_per_minute);
}
};
static const NWidgetPart _nested_schdispatch_widgets[] = {
@ -661,3 +703,210 @@ void ShowSchdispatchWindow(const Vehicle *v)
{
AllocateWindowDescFront<SchdispatchWindow>(&_schdispatch_desc, v->index);
}
enum ScheduledDispatchAddSlotsWindowWidgets {
WID_SCHDISPATCH_ADD_SLOT_START_HOUR,
WID_SCHDISPATCH_ADD_SLOT_START_MINUTE,
WID_SCHDISPATCH_ADD_SLOT_STEP_HOUR,
WID_SCHDISPATCH_ADD_SLOT_STEP_MINUTE,
WID_SCHDISPATCH_ADD_SLOT_END_HOUR,
WID_SCHDISPATCH_ADD_SLOT_END_MINUTE,
WID_SCHDISPATCH_ADD_SLOT_ADD_BUTTON,
WID_SCHDISPATCH_ADD_SLOT_START_TEXT,
WID_SCHDISPATCH_ADD_SLOT_STEP_TEXT,
WID_SCHDISPATCH_ADD_SLOT_END_TEXT,
};
struct ScheduledDispatchAddSlotsWindow : Window {
uint start;
uint step;
uint end;
ScheduledDispatchAddSlotsWindow(WindowDesc *desc, WindowNumber window_number, SchdispatchWindow *parent) :
Window(desc)
{
this->start = (_scaled_date_ticks / _settings_time.ticks_per_minute) % (60 * 24);
this->step = 30;
this->end = this->start + 60;
this->parent = parent;
this->CreateNestedTree();
this->FinishInitNested(window_number);
}
Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override
{
Point pt = { this->parent->left + this->parent->width / 2 - sm_width / 2, this->parent->top + this->parent->height / 2 - sm_height / 2 };
return pt;
}
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
{
Dimension d = {0, 0};
switch (widget) {
default: return;
case WID_SCHDISPATCH_ADD_SLOT_START_TEXT:
case WID_SCHDISPATCH_ADD_SLOT_STEP_TEXT:
case WID_SCHDISPATCH_ADD_SLOT_END_TEXT:
d = maxdim(d, GetStringBoundingBox(STR_SCHDISPATCH_ADD_DEPARTURE_SLOTS_START));
d = maxdim(d, GetStringBoundingBox(STR_SCHDISPATCH_ADD_DEPARTURE_SLOTS_STEP));
d = maxdim(d, GetStringBoundingBox(STR_SCHDISPATCH_ADD_DEPARTURE_SLOTS_END));
break;
case WID_SCHDISPATCH_ADD_SLOT_START_HOUR:
case WID_SCHDISPATCH_ADD_SLOT_STEP_HOUR:
case WID_SCHDISPATCH_ADD_SLOT_END_HOUR:
for (uint i = 0; i < 24; i++) {
SetDParam(0, i);
d = maxdim(d, GetStringBoundingBox(STR_JUST_INT));
}
break;
case WID_SCHDISPATCH_ADD_SLOT_START_MINUTE:
case WID_SCHDISPATCH_ADD_SLOT_STEP_MINUTE:
case WID_SCHDISPATCH_ADD_SLOT_END_MINUTE:
for (uint i = 0; i < 60; i++) {
SetDParam(0, i);
d = maxdim(d, GetStringBoundingBox(STR_JUST_INT));
}
break;
}
d.width += padding.width;
d.height += padding.height;
*size = d;
}
virtual void SetStringParameters(int widget) const override
{
switch (widget) {
case WID_SCHDISPATCH_ADD_SLOT_START_HOUR: SetDParam(0, MINUTES_HOUR(start)); break;
case WID_SCHDISPATCH_ADD_SLOT_START_MINUTE: SetDParam(0, MINUTES_MINUTE(start)); break;
case WID_SCHDISPATCH_ADD_SLOT_STEP_HOUR: SetDParam(0, MINUTES_HOUR(step)); break;
case WID_SCHDISPATCH_ADD_SLOT_STEP_MINUTE: SetDParam(0, MINUTES_MINUTE(step)); break;
case WID_SCHDISPATCH_ADD_SLOT_END_HOUR: SetDParam(0, MINUTES_HOUR(end)); break;
case WID_SCHDISPATCH_ADD_SLOT_END_MINUTE: SetDParam(0, MINUTES_MINUTE(end)); break;
}
}
virtual void OnClick(Point pt, int widget, int click_count) override
{
auto handle_hours_dropdown = [&](uint current) {
DropDownList list;
for (uint i = 0; i < 24; i++) {
DropDownListParamStringItem *item = new DropDownListParamStringItem(STR_JUST_INT, i, false);
item->SetParam(0, i);
list.emplace_back(item);
}
ShowDropDownList(this, std::move(list), MINUTES_HOUR(current), widget);
};
auto handle_minutes_dropdown = [&](uint current) {
DropDownList list;
for (uint i = 0; i < 60; i++) {
DropDownListParamStringItem *item = new DropDownListParamStringItem(STR_JUST_INT, i, false);
item->SetParam(0, i);
list.emplace_back(item);
}
ShowDropDownList(this, std::move(list), MINUTES_MINUTE(current), widget);
};
switch (widget) {
case WID_SCHDISPATCH_ADD_SLOT_START_HOUR:
handle_hours_dropdown(this->start);
break;
case WID_SCHDISPATCH_ADD_SLOT_START_MINUTE:
handle_minutes_dropdown(this->start);
break;
case WID_SCHDISPATCH_ADD_SLOT_STEP_HOUR:
handle_hours_dropdown(this->step);
break;
case WID_SCHDISPATCH_ADD_SLOT_STEP_MINUTE:
handle_minutes_dropdown(this->step);
break;
case WID_SCHDISPATCH_ADD_SLOT_END_HOUR:
handle_hours_dropdown(this->end);
break;
case WID_SCHDISPATCH_ADD_SLOT_END_MINUTE:
handle_minutes_dropdown(this->end);
break;
case WID_SCHDISPATCH_ADD_SLOT_ADD_BUTTON:
static_cast<SchdispatchWindow *>(this->parent)->AddMultipleDepartureSlots(this->start, this->step, this->end);
delete this;
break;
}
}
virtual void OnDropdownSelect(int widget, int index) override
{
switch (widget) {
case WID_SCHDISPATCH_ADD_SLOT_START_HOUR:
this->start = MINUTES_DATE(0, index, MINUTES_MINUTE(this->start));
break;
case WID_SCHDISPATCH_ADD_SLOT_START_MINUTE:
this->start = MINUTES_DATE(0, MINUTES_HOUR(this->start), index);
break;
case WID_SCHDISPATCH_ADD_SLOT_STEP_HOUR:
this->step = MINUTES_DATE(0, index, MINUTES_MINUTE(this->step));
break;
case WID_SCHDISPATCH_ADD_SLOT_STEP_MINUTE:
this->step = MINUTES_DATE(0, MINUTES_HOUR(this->step), index);
break;
case WID_SCHDISPATCH_ADD_SLOT_END_HOUR:
this->end = MINUTES_DATE(0, index, MINUTES_MINUTE(this->end));
break;
case WID_SCHDISPATCH_ADD_SLOT_END_MINUTE:
this->end = MINUTES_DATE(0, MINUTES_HOUR(this->end), index);
break;
}
this->SetWidgetDirty(widget);
}
};
static const NWidgetPart _nested_scheduled_dispatch_add_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_TIME_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_BROWN),
NWidget(NWID_VERTICAL), SetPIP(6, 6, 6),
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(6, 6, 6),
NWidget(WWT_TEXT, COLOUR_BROWN, WID_SCHDISPATCH_ADD_SLOT_START_TEXT), SetDataTip(STR_SCHDISPATCH_ADD_DEPARTURE_SLOTS_START, STR_NULL),
NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_SCHDISPATCH_ADD_SLOT_START_HOUR), SetFill(1, 0), SetDataTip(STR_JUST_INT, STR_DATE_MINUTES_HOUR_TOOLTIP),
NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_SCHDISPATCH_ADD_SLOT_START_MINUTE), SetFill(1, 0), SetDataTip(STR_JUST_INT, STR_DATE_MINUTES_MINUTE_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(6, 6, 6),
NWidget(WWT_TEXT, COLOUR_BROWN, WID_SCHDISPATCH_ADD_SLOT_STEP_TEXT), SetDataTip(STR_SCHDISPATCH_ADD_DEPARTURE_SLOTS_STEP, STR_NULL),
NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_SCHDISPATCH_ADD_SLOT_STEP_HOUR), SetFill(1, 0), SetDataTip(STR_JUST_INT, STR_DATE_MINUTES_HOUR_TOOLTIP),
NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_SCHDISPATCH_ADD_SLOT_STEP_MINUTE), SetFill(1, 0), SetDataTip(STR_JUST_INT, STR_DATE_MINUTES_MINUTE_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(6, 6, 6),
NWidget(WWT_TEXT, COLOUR_BROWN, WID_SCHDISPATCH_ADD_SLOT_END_TEXT), SetDataTip(STR_SCHDISPATCH_ADD_DEPARTURE_SLOTS_END, STR_NULL),
NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_SCHDISPATCH_ADD_SLOT_END_HOUR), SetFill(1, 0), SetDataTip(STR_JUST_INT, STR_DATE_MINUTES_HOUR_TOOLTIP),
NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_SCHDISPATCH_ADD_SLOT_END_MINUTE), SetFill(1, 0), SetDataTip(STR_JUST_INT, STR_DATE_MINUTES_MINUTE_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(NWID_SPACER), SetFill(1, 0),
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SCHDISPATCH_ADD_SLOT_ADD_BUTTON), SetMinimalSize(100, 12), SetDataTip(STR_SCHDISPATCH_ADD, STR_SCHDISPATCH_ADD_TOOLTIP),
NWidget(NWID_SPACER), SetFill(1, 0),
EndContainer(),
EndContainer(),
EndContainer()
};
static WindowDesc _scheduled_dispatch_add_desc(
WDP_CENTER, nullptr, 0, 0,
WC_SET_DATE, WC_NONE,
0,
_nested_scheduled_dispatch_add_widgets, lengthof(_nested_scheduled_dispatch_add_widgets)
);
void ShowScheduledDispatchAddSlotsWindow(SchdispatchWindow *parent, int window_number)
{
DeleteWindowByClass(WC_SET_DATE);
new ScheduledDispatchAddSlotsWindow(&_scheduled_dispatch_add_desc, window_number, parent);
}

Loading…
Cancel
Save