Allow adding multiple scheduled dispatch departure slots at once

This commit is contained in:
Jonathan G Rennison
2021-11-28 02:25:42 +00:00
parent 6f38769b73
commit 0aeafeaf3a
4 changed files with 277 additions and 9 deletions

View File

@@ -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;
DoCommandP(0, v->index, (uint32)(date - start_tick), CMD_SCHEDULED_DISPATCH_ADD | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
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);
}
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);
}