OpenTTD
timetable_gui.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
10 #include "stdafx.h"
11 #include "command_func.h"
12 #include "gui.h"
13 #include "window_gui.h"
14 #include "window_func.h"
15 #include "textbuf_gui.h"
16 #include "strings_func.h"
17 #include "vehicle_base.h"
18 #include "string_func.h"
19 #include "gfx_func.h"
20 #include "company_func.h"
21 #include "date_func.h"
22 #include "date_gui.h"
23 #include "vehicle_gui.h"
24 #include "settings_type.h"
25 
27 
28 #include "table/sprites.h"
29 #include "table/strings.h"
30 
31 #include "safeguards.h"
32 
37 };
38 
45 void SetTimetableParams(int param1, int param2, Ticks ticks)
46 {
48  SetDParam(param1, STR_TIMETABLE_TICKS);
49  SetDParam(param2, ticks);
50  } else {
51  SetDParam(param1, STR_TIMETABLE_DAYS);
52  SetDParam(param2, ticks / DAY_TICKS);
53  }
54 }
55 
62 static bool CanDetermineTimeTaken(const Order *order, bool travelling)
63 {
64  /* Current order is conditional */
65  if (order->IsType(OT_CONDITIONAL) || order->IsType(OT_IMPLICIT)) return false;
66  /* No travel time and we have not already finished travelling */
67  if (travelling && !order->IsTravelTimetabled()) return false;
68  /* No wait time but we are loading at this timetabled station */
69  if (!travelling && !order->IsWaitTimetabled() && order->IsType(OT_GOTO_STATION) &&
71  return false;
72  }
73 
74  return true;
75 }
76 
77 
86 static void FillTimetableArrivalDepartureTable(const Vehicle *v, VehicleOrderID start, bool travelling, TimetableArrivalDeparture *table, Ticks offset)
87 {
88  assert(table != nullptr);
89  assert(v->GetNumOrders() >= 2);
90  assert(start < v->GetNumOrders());
91 
92  Ticks sum = offset;
93  VehicleOrderID i = start;
94  const Order *order = v->GetOrder(i);
95 
96  /* Pre-initialize with unknown time */
97  for (int i = 0; i < v->GetNumOrders(); ++i) {
98  table[i].arrival = table[i].departure = INVALID_TICKS;
99  }
100 
101  /* Cyclically loop over all orders until we reach the current one again.
102  * As we may start at the current order, do a post-checking loop */
103  do {
104  /* Automatic orders don't influence the overall timetable;
105  * they just add some untimetabled entries, but the time till
106  * the next non-implicit order can still be known. */
107  if (!order->IsType(OT_IMPLICIT)) {
108  if (travelling || i != start) {
109  if (!CanDetermineTimeTaken(order, true)) return;
110  sum += order->GetTimetabledTravel();
111  table[i].arrival = sum;
112  }
113 
114  if (!CanDetermineTimeTaken(order, false)) return;
115  sum += order->GetTimetabledWait();
116  table[i].departure = sum;
117  }
118 
119  ++i;
120  order = order->next;
121  if (i >= v->GetNumOrders()) {
122  i = 0;
123  assert(order == nullptr);
124  order = v->orders.list->GetFirstOrder();
125  }
126  } while (i != start);
127 
128  /* When loading at a scheduled station we still have to treat the
129  * travelling part of the first order. */
130  if (!travelling) {
131  if (!CanDetermineTimeTaken(order, true)) return;
132  sum += order->GetTimetabledTravel();
133  table[i].arrival = sum;
134  }
135 }
136 
137 
143 static void ChangeTimetableStartCallback(const Window *w, Date date)
144 {
145  DoCommandP(0, w->window_number, date, CMD_SET_TIMETABLE_START | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
146 }
147 
148 
150  int sel_index;
151  const Vehicle *vehicle;
155  Scrollbar *vscroll;
157 
158  TimetableWindow(WindowDesc *desc, WindowNumber window_number) :
159  Window(desc),
160  sel_index(-1),
161  vehicle(Vehicle::Get(window_number)),
162  show_expected(true)
163  {
164  this->CreateNestedTree();
165  this->vscroll = this->GetScrollbar(WID_VT_SCROLLBAR);
166  this->UpdateSelectionStates();
167  this->FinishInitNested(window_number);
168 
169  this->owner = this->vehicle->owner;
170  }
171 
179  {
181 
182  bool travelling = (!v->current_order.IsType(OT_LOADING) || v->current_order.GetNonStopType() == ONSF_STOP_EVERYWHERE);
183  Ticks start_time = _date_fract - v->current_order_time;
184 
185  FillTimetableArrivalDepartureTable(v, v->cur_real_order_index % v->GetNumOrders(), travelling, table, start_time);
186 
187  return (travelling && v->lateness_counter < 0);
188  }
189 
190  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
191  {
192  switch (widget) {
195  this->deparr_time_width = GetStringBoundingBox(STR_JUST_DATE_TINY).width;
196  this->deparr_abbr_width = max(GetStringBoundingBox(STR_TIMETABLE_ARRIVAL_ABBREVIATION).width, GetStringBoundingBox(STR_TIMETABLE_DEPARTURE_ABBREVIATION).width);
197  size->width = WD_FRAMERECT_LEFT + this->deparr_abbr_width + 10 + this->deparr_time_width + WD_FRAMERECT_RIGHT;
198  FALLTHROUGH;
199 
202  resize->height = FONT_HEIGHT_NORMAL;
203  size->height = WD_FRAMERECT_TOP + 8 * resize->height + WD_FRAMERECT_BOTTOM;
204  break;
205 
208  break;
209  }
210  }
211 
212  int GetOrderFromTimetableWndPt(int y, const Vehicle *v)
213  {
214  int sel = (y - this->GetWidget<NWidgetBase>(WID_VT_TIMETABLE_PANEL)->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_NORMAL;
215 
216  if ((uint)sel >= this->vscroll->GetCapacity()) return INVALID_ORDER;
217 
218  sel += this->vscroll->GetPosition();
219 
220  return (sel < v->GetNumOrders() * 2 && sel >= 0) ? sel : INVALID_ORDER;
221  }
222 
228  void OnInvalidateData(int data = 0, bool gui_scope = true) override
229  {
230  switch (data) {
231  case VIWD_AUTOREPLACE:
232  /* Autoreplace replaced the vehicle */
233  this->vehicle = Vehicle::Get(this->window_number);
234  break;
235 
237  /* Removed / replaced all orders (after deleting / sharing) */
238  if (this->sel_index == -1) break;
239 
240  this->DeleteChildWindows();
241  this->sel_index = -1;
242  break;
243 
244  case VIWD_MODIFY_ORDERS:
245  if (!gui_scope) break;
246  this->UpdateSelectionStates();
247  this->ReInit();
248  break;
249 
250  default: {
251  if (gui_scope) break; // only do this once; from command scope
252 
253  /* Moving an order. If one of these is INVALID_VEH_ORDER_ID, then
254  * the order is being created / removed */
255  if (this->sel_index == -1) break;
256 
257  VehicleOrderID from = GB(data, 0, 8);
258  VehicleOrderID to = GB(data, 8, 8);
259 
260  if (from == to) break; // no need to change anything
261 
262  /* if from == INVALID_VEH_ORDER_ID, one order was added; if to == INVALID_VEH_ORDER_ID, one order was removed */
263  uint old_num_orders = this->vehicle->GetNumOrders() - (uint)(from == INVALID_VEH_ORDER_ID) + (uint)(to == INVALID_VEH_ORDER_ID);
264 
265  VehicleOrderID selected_order = (this->sel_index + 1) / 2;
266  if (selected_order == old_num_orders) selected_order = 0; // when last travel time is selected, it belongs to order 0
267 
268  bool travel = HasBit(this->sel_index, 0);
269 
270  if (from != selected_order) {
271  /* Moving from preceding order? */
272  selected_order -= (int)(from <= selected_order);
273  /* Moving to preceding order? */
274  selected_order += (int)(to <= selected_order);
275  } else {
276  /* Now we are modifying the selected order */
277  if (to == INVALID_VEH_ORDER_ID) {
278  /* Deleting selected order */
279  this->DeleteChildWindows();
280  this->sel_index = -1;
281  break;
282  } else {
283  /* Moving selected order */
284  selected_order = to;
285  }
286  }
287 
288  /* recompute new sel_index */
289  this->sel_index = 2 * selected_order - (int)travel;
290  /* travel time of first order needs special handling */
291  if (this->sel_index == -1) this->sel_index = this->vehicle->GetNumOrders() * 2 - 1;
292  break;
293  }
294  }
295  }
296 
297 
298  void OnPaint() override
299  {
300  const Vehicle *v = this->vehicle;
301  int selected = this->sel_index;
302 
303  this->vscroll->SetCount(v->GetNumOrders() * 2);
304 
305  if (v->owner == _local_company) {
306  bool disable = true;
307  if (selected != -1) {
308  const Order *order = v->GetOrder(((selected + 1) / 2) % v->GetNumOrders());
309  if (selected % 2 == 1) {
310  disable = order != nullptr && (order->IsType(OT_CONDITIONAL) || order->IsType(OT_IMPLICIT));
311  } else {
312  disable = order == nullptr || ((!order->IsType(OT_GOTO_STATION) || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) && !order->IsType(OT_CONDITIONAL));
313  }
314  }
315  bool disable_speed = disable || selected % 2 != 1 || v->type == VEH_AIRCRAFT;
316 
317  this->SetWidgetDisabledState(WID_VT_CHANGE_TIME, disable);
318  this->SetWidgetDisabledState(WID_VT_CLEAR_TIME, disable);
319  this->SetWidgetDisabledState(WID_VT_CHANGE_SPEED, disable_speed);
320  this->SetWidgetDisabledState(WID_VT_CLEAR_SPEED, disable_speed);
321  this->SetWidgetDisabledState(WID_VT_SHARED_ORDER_LIST, !v->IsOrderListShared());
322 
323  this->SetWidgetDisabledState(WID_VT_START_DATE, v->orders.list == nullptr);
324  this->SetWidgetDisabledState(WID_VT_RESET_LATENESS, v->orders.list == nullptr);
325  this->SetWidgetDisabledState(WID_VT_AUTOFILL, v->orders.list == nullptr);
326  } else {
327  this->DisableWidget(WID_VT_START_DATE);
328  this->DisableWidget(WID_VT_CHANGE_TIME);
329  this->DisableWidget(WID_VT_CLEAR_TIME);
330  this->DisableWidget(WID_VT_CHANGE_SPEED);
331  this->DisableWidget(WID_VT_CLEAR_SPEED);
332  this->DisableWidget(WID_VT_RESET_LATENESS);
333  this->DisableWidget(WID_VT_AUTOFILL);
334  this->DisableWidget(WID_VT_SHARED_ORDER_LIST);
335  }
336 
337  this->SetWidgetLoweredState(WID_VT_AUTOFILL, HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE));
338 
339  this->DrawWidgets();
340  }
341 
342  void SetStringParameters(int widget) const override
343  {
344  switch (widget) {
345  case WID_VT_CAPTION: SetDParam(0, this->vehicle->index); break;
346  case WID_VT_EXPECTED: SetDParam(0, this->show_expected ? STR_TIMETABLE_EXPECTED : STR_TIMETABLE_SCHEDULED); break;
347  }
348  }
349 
350  void DrawWidget(const Rect &r, int widget) const override
351  {
352  const Vehicle *v = this->vehicle;
353  int selected = this->sel_index;
354 
355  switch (widget) {
356  case WID_VT_TIMETABLE_PANEL: {
357  int y = r.top + WD_FRAMERECT_TOP;
358  int i = this->vscroll->GetPosition();
359  VehicleOrderID order_id = (i + 1) / 2;
360  bool final_order = false;
361 
362  bool rtl = _current_text_dir == TD_RTL;
363  SetDParamMaxValue(0, v->GetNumOrders(), 2);
364  int index_column_width = GetStringBoundingBox(STR_ORDER_INDEX).width + 2 * GetSpriteSize(rtl ? SPR_ARROW_RIGHT : SPR_ARROW_LEFT).width + 3;
365  int middle = rtl ? r.right - WD_FRAMERECT_RIGHT - index_column_width : r.left + WD_FRAMERECT_LEFT + index_column_width;
366 
367  const Order *order = v->GetOrder(order_id);
368  while (order != nullptr) {
369  /* Don't draw anything if it extends past the end of the window. */
370  if (!this->vscroll->IsVisible(i)) break;
371 
372  if (i % 2 == 0) {
373  DrawOrderString(v, order, order_id, y, i == selected, true, r.left + WD_FRAMERECT_LEFT, middle, r.right - WD_FRAMERECT_RIGHT);
374 
375  order_id++;
376 
377  if (order_id >= v->GetNumOrders()) {
378  order = v->GetOrder(0);
379  final_order = true;
380  } else {
381  order = order->next;
382  }
383  } else {
384  StringID string;
385  TextColour colour = (i == selected) ? TC_WHITE : TC_BLACK;
386  if (order->IsType(OT_CONDITIONAL)) {
387  string = STR_TIMETABLE_NO_TRAVEL;
388  } else if (order->IsType(OT_IMPLICIT)) {
389  string = STR_TIMETABLE_NOT_TIMETABLEABLE;
390  colour = ((i == selected) ? TC_SILVER : TC_GREY) | TC_NO_SHADE;
391  } else if (!order->IsTravelTimetabled()) {
392  if (order->GetTravelTime() > 0) {
393  SetTimetableParams(0, 1, order->GetTravelTime());
394  string = order->GetMaxSpeed() != UINT16_MAX ?
395  STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED :
396  STR_TIMETABLE_TRAVEL_FOR_ESTIMATED;
397  } else {
398  string = order->GetMaxSpeed() != UINT16_MAX ?
399  STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED :
400  STR_TIMETABLE_TRAVEL_NOT_TIMETABLED;
401  }
402  } else {
403  SetTimetableParams(0, 1, order->GetTimetabledTravel());
404  string = order->GetMaxSpeed() != UINT16_MAX ?
405  STR_TIMETABLE_TRAVEL_FOR_SPEED : STR_TIMETABLE_TRAVEL_FOR;
406  }
407  SetDParam(2, order->GetMaxSpeed());
408 
409  DrawString(rtl ? r.left + WD_FRAMERECT_LEFT : middle, rtl ? middle : r.right - WD_FRAMERECT_LEFT, y, string, colour);
410 
411  if (final_order) break;
412  }
413 
414  i++;
415  y += FONT_HEIGHT_NORMAL;
416  }
417  break;
418  }
419 
421  /* Arrival and departure times are handled in an all-or-nothing approach,
422  * i.e. are only shown if we can calculate all times.
423  * Excluding order lists with only one order makes some things easier.
424  */
425  Ticks total_time = v->orders.list != nullptr ? v->orders.list->GetTimetableDurationIncomplete() : 0;
426  if (total_time <= 0 || v->GetNumOrders() <= 1 || !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) break;
427 
429  const VehicleOrderID cur_order = v->cur_real_order_index % v->GetNumOrders();
430 
431  VehicleOrderID earlyID = BuildArrivalDepartureList(v, arr_dep) ? cur_order : (VehicleOrderID)INVALID_VEH_ORDER_ID;
432 
433  int y = r.top + WD_FRAMERECT_TOP;
434 
435  bool show_late = this->show_expected && v->lateness_counter > DAY_TICKS;
436  Ticks offset = show_late ? 0 : -v->lateness_counter;
437 
438  bool rtl = _current_text_dir == TD_RTL;
439  int abbr_left = rtl ? r.right - WD_FRAMERECT_RIGHT - this->deparr_abbr_width : r.left + WD_FRAMERECT_LEFT;
440  int abbr_right = rtl ? r.right - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT + this->deparr_abbr_width;
441  int time_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - WD_FRAMERECT_RIGHT - this->deparr_time_width;
442  int time_right = rtl ? r.left + WD_FRAMERECT_LEFT + this->deparr_time_width : r.right - WD_FRAMERECT_RIGHT;
443 
444  for (int i = this->vscroll->GetPosition(); i / 2 < v->GetNumOrders(); ++i) { // note: i is also incremented in the loop
445  /* Don't draw anything if it extends past the end of the window. */
446  if (!this->vscroll->IsVisible(i)) break;
447 
448  if (i % 2 == 0) {
449  if (arr_dep[i / 2].arrival != INVALID_TICKS) {
450  DrawString(abbr_left, abbr_right, y, STR_TIMETABLE_ARRIVAL_ABBREVIATION, i == selected ? TC_WHITE : TC_BLACK);
451  if (this->show_expected && i / 2 == earlyID) {
452  SetDParam(0, _date + arr_dep[i / 2].arrival / DAY_TICKS);
453  DrawString(time_left, time_right, y, STR_JUST_DATE_TINY, TC_GREEN);
454  } else {
455  SetDParam(0, _date + (arr_dep[i / 2].arrival + offset) / DAY_TICKS);
456  DrawString(time_left, time_right, y, STR_JUST_DATE_TINY,
457  show_late ? TC_RED : i == selected ? TC_WHITE : TC_BLACK);
458  }
459  }
460  } else {
461  if (arr_dep[i / 2].departure != INVALID_TICKS) {
462  DrawString(abbr_left, abbr_right, y, STR_TIMETABLE_DEPARTURE_ABBREVIATION, i == selected ? TC_WHITE : TC_BLACK);
463  SetDParam(0, _date + (arr_dep[i/2].departure + offset) / DAY_TICKS);
464  DrawString(time_left, time_right, y, STR_JUST_DATE_TINY,
465  show_late ? TC_RED : i == selected ? TC_WHITE : TC_BLACK);
466  }
467  }
468  y += FONT_HEIGHT_NORMAL;
469  }
470  break;
471  }
472 
473  case WID_VT_SUMMARY_PANEL: {
474  int y = r.top + WD_FRAMERECT_TOP;
475 
476  Ticks total_time = v->orders.list != nullptr ? v->orders.list->GetTimetableDurationIncomplete() : 0;
477  if (total_time != 0) {
478  SetTimetableParams(0, 1, total_time);
479  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, v->orders.list->IsCompleteTimetable() ? STR_TIMETABLE_TOTAL_TIME : STR_TIMETABLE_TOTAL_TIME_INCOMPLETE);
480  }
481  y += FONT_HEIGHT_NORMAL;
482 
483  if (v->timetable_start != 0) {
484  /* We are running towards the first station so we can start the
485  * timetable at the given time. */
486  SetDParam(0, STR_JUST_DATE_TINY);
487  SetDParam(1, v->timetable_start);
488  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TIMETABLE_STATUS_START_AT);
489  } else if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) {
490  /* We aren't running on a timetable yet, so how can we be "on time"
491  * when we aren't even "on service"/"on duty"? */
492  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TIMETABLE_STATUS_NOT_STARTED);
493  } else if (v->lateness_counter == 0 || (!_settings_client.gui.timetable_in_ticks && v->lateness_counter / DAY_TICKS == 0)) {
494  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TIMETABLE_STATUS_ON_TIME);
495  } else {
497  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, v->lateness_counter < 0 ? STR_TIMETABLE_STATUS_EARLY : STR_TIMETABLE_STATUS_LATE);
498  }
499  break;
500  }
501  }
502  }
503 
504  static inline uint32 PackTimetableArgs(const Vehicle *v, uint selected, bool speed)
505  {
506  uint order_number = (selected + 1) / 2;
507  ModifyTimetableFlags mtf = (selected % 2 == 1) ? (speed ? MTF_TRAVEL_SPEED : MTF_TRAVEL_TIME) : MTF_WAIT_TIME;
508 
509  if (order_number >= v->GetNumOrders()) order_number = 0;
510 
511  return v->index | (order_number << 20) | (mtf << 28);
512  }
513 
514  void OnClick(Point pt, int widget, int click_count) override
515  {
516  const Vehicle *v = this->vehicle;
517 
518  switch (widget) {
519  case WID_VT_ORDER_VIEW: // Order view button
520  ShowOrdersWindow(v);
521  break;
522 
523  case WID_VT_TIMETABLE_PANEL: { // Main panel.
524  int selected = GetOrderFromTimetableWndPt(pt.y, v);
525 
526  this->DeleteChildWindows();
527  this->sel_index = (selected == INVALID_ORDER || selected == this->sel_index) ? -1 : selected;
528  break;
529  }
530 
531  case WID_VT_START_DATE: // Change the date that the timetable starts.
533  break;
534 
535  case WID_VT_CHANGE_TIME: { // "Wait For" button.
536  int selected = this->sel_index;
537  VehicleOrderID real = (selected + 1) / 2;
538 
539  if (real >= v->GetNumOrders()) real = 0;
540 
541  const Order *order = v->GetOrder(real);
542  StringID current = STR_EMPTY;
543 
544  if (order != nullptr) {
545  uint time = (selected % 2 == 1) ? order->GetTravelTime() : order->GetWaitTime();
547 
548  if (time != 0) {
549  SetDParam(0, time);
550  current = STR_JUST_INT;
551  }
552  }
553 
554  this->query_is_speed_query = false;
555  ShowQueryString(current, STR_TIMETABLE_CHANGE_TIME, 31, this, CS_NUMERAL, QSF_ACCEPT_UNCHANGED);
556  break;
557  }
558 
559  case WID_VT_CHANGE_SPEED: { // Change max speed button.
560  int selected = this->sel_index;
561  VehicleOrderID real = (selected + 1) / 2;
562 
563  if (real >= v->GetNumOrders()) real = 0;
564 
565  StringID current = STR_EMPTY;
566  const Order *order = v->GetOrder(real);
567  if (order != nullptr) {
568  if (order->GetMaxSpeed() != UINT16_MAX) {
570  current = STR_JUST_INT;
571  }
572  }
573 
574  this->query_is_speed_query = true;
575  ShowQueryString(current, STR_TIMETABLE_CHANGE_SPEED, 31, this, CS_NUMERAL, QSF_NONE);
576  break;
577  }
578 
579  case WID_VT_CLEAR_TIME: { // Clear waiting time.
580  uint32 p1 = PackTimetableArgs(v, this->sel_index, false);
581  DoCommandP(0, p1, 0, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
582  break;
583  }
584 
585  case WID_VT_CLEAR_SPEED: { // Clear max speed button.
586  uint32 p1 = PackTimetableArgs(v, this->sel_index, true);
587  DoCommandP(0, p1, UINT16_MAX, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
588  break;
589  }
590 
591  case WID_VT_RESET_LATENESS: // Reset the vehicle's late counter.
592  DoCommandP(0, v->index, 0, CMD_SET_VEHICLE_ON_TIME | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
593  break;
594 
595  case WID_VT_AUTOFILL: { // Autofill the timetable.
596  uint32 p2 = 0;
598  if (_ctrl_pressed) SetBit(p2, 1);
599  DoCommandP(0, v->index, p2, CMD_AUTOFILL_TIMETABLE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
600  break;
601  }
602 
603  case WID_VT_EXPECTED:
604  this->show_expected = !this->show_expected;
605  break;
606 
608  ShowVehicleListWindow(v);
609  break;
610  }
611 
612  this->SetDirty();
613  }
614 
615  void OnQueryTextFinished(char *str) override
616  {
617  if (str == nullptr) return;
618 
619  const Vehicle *v = this->vehicle;
620 
621  uint32 p1 = PackTimetableArgs(v, this->sel_index, this->query_is_speed_query);
622 
623  uint64 val = StrEmpty(str) ? 0 : strtoul(str, nullptr, 10);
624  if (this->query_is_speed_query) {
626  } else {
628  }
629 
630  uint32 p2 = minu(val, UINT16_MAX);
631 
632  DoCommandP(0, p1, p2, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
633  }
634 
635  void OnResize() override
636  {
637  /* Update the scroll bar */
639  }
640 
645  {
646  this->GetWidget<NWidgetStacked>(WID_VT_ARRIVAL_DEPARTURE_SELECTION)->SetDisplayedPlane(_settings_client.gui.timetable_arrival_departure ? 0 : SZSP_NONE);
647  this->GetWidget<NWidgetStacked>(WID_VT_EXPECTED_SELECTION)->SetDisplayedPlane(_settings_client.gui.timetable_arrival_departure ? 0 : 1);
648  }
649 };
650 
651 static const NWidgetPart _nested_timetable_widgets[] = {
653  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
654  NWidget(WWT_CAPTION, COLOUR_GREY, WID_VT_CAPTION), SetDataTip(STR_TIMETABLE_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
655  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_ORDER_VIEW), SetMinimalSize(61, 14), SetDataTip( STR_TIMETABLE_ORDER_VIEW, STR_TIMETABLE_ORDER_VIEW_TOOLTIP),
656  NWidget(WWT_SHADEBOX, COLOUR_GREY),
657  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
658  NWidget(WWT_STICKYBOX, COLOUR_GREY),
659  EndContainer(),
661  NWidget(WWT_PANEL, COLOUR_GREY, WID_VT_TIMETABLE_PANEL), SetMinimalSize(388, 82), SetResize(1, 10), SetDataTip(STR_NULL, STR_TIMETABLE_TOOLTIP), SetScrollbar(WID_VT_SCROLLBAR), EndContainer(),
663  NWidget(WWT_PANEL, COLOUR_GREY, WID_VT_ARRIVAL_DEPARTURE_PANEL), SetMinimalSize(110, 0), SetFill(0, 1), SetDataTip(STR_NULL, STR_TIMETABLE_TOOLTIP), SetScrollbar(WID_VT_SCROLLBAR), EndContainer(),
664  EndContainer(),
666  EndContainer(),
667  NWidget(WWT_PANEL, COLOUR_GREY, WID_VT_SUMMARY_PANEL), SetMinimalSize(400, 22), SetResize(1, 0), EndContainer(),
671  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_CHANGE_TIME), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_CHANGE_TIME, STR_TIMETABLE_WAIT_TIME_TOOLTIP),
672  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_CLEAR_TIME), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_CLEAR_TIME, STR_TIMETABLE_CLEAR_TIME_TOOLTIP),
673  EndContainer(),
675  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_CHANGE_SPEED), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_CHANGE_SPEED, STR_TIMETABLE_CHANGE_SPEED_TOOLTIP),
676  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_CLEAR_SPEED), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_CLEAR_SPEED, STR_TIMETABLE_CLEAR_SPEED_TOOLTIP),
677  EndContainer(),
679  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_START_DATE), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_STARTING_DATE, STR_TIMETABLE_STARTING_DATE_TOOLTIP),
680  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_RESET_LATENESS), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_RESET_LATENESS, STR_TIMETABLE_RESET_LATENESS_TOOLTIP),
681  EndContainer(),
683  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_AUTOFILL), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_AUTOFILL, STR_TIMETABLE_AUTOFILL_TOOLTIP),
685  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_EXPECTED), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_BLACK_STRING, STR_TIMETABLE_EXPECTED_TOOLTIP),
686  NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), SetFill(1, 1), EndContainer(),
687  EndContainer(),
688  EndContainer(),
689  EndContainer(),
691  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VT_SHARED_ORDER_LIST), SetFill(0, 1), SetDataTip(SPR_SHARED_ORDERS_ICON, STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP),
692  NWidget(WWT_RESIZEBOX, COLOUR_GREY), SetFill(0, 1),
693  EndContainer(),
694  EndContainer(),
695 };
696 
697 static WindowDesc _timetable_desc(
698  WDP_AUTO, "view_vehicle_timetable", 400, 130,
701  _nested_timetable_widgets, lengthof(_nested_timetable_widgets)
702 );
703 
709 {
712  AllocateWindowDescFront<TimetableWindow>(&_timetable_desc, v->index);
713 }
Functions related to OTTD&#39;s strings.
change the timetable for a vehicle
Definition: command_type.h:327
Normal push-button (no toggle button) with image caption.
Definition: widget_type.h:103
Set max travel speed.
Definition: order_type.h:173
static uint minu(const uint a, const uint b)
Returns the minimum of two unsigned integers.
Definition: math_func.hpp:68
Set wait time.
Definition: order_type.h:171
static void ChangeTimetableStartCallback(const Window *w, Date date)
Callback for when a time has been chosen to start the time table.
static const int DAYS_IN_YEAR
days per year
Definition: date_type.h:29
uint16 GetTravelTime() const
Get the time in ticks a vehicle will probably take to reach the destination (timetabled or not)...
Definition: order_base.h:185
static NWidgetPart SetResize(int16 dx, int16 dy)
Widget part function for setting the resize step.
Definition: widget_type.h:928
void SetStringParameters(int widget) const override
Initialize string parameters for a widget.
set the vehicle on time feature (timetable)
Definition: command_type.h:328
static void FillTimetableArrivalDepartureTable(const Vehicle *v, VehicleOrderID start, bool travelling, TimetableArrivalDeparture *table, Ticks offset)
Fill the table with arrivals and departures.
High level window description.
Definition: window_gui.h:166
Scrollbar for the panel.
union Vehicle::@49 orders
The orders currently assigned to the vehicle.
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:291
bool show_expected
Whether we show expected arrival or scheduled.
Whether the vehicle has started running on the timetable yet.
Definition: vehicle_base.h:45
Functions related to dates.
Caption of the window.
bool timetable_arrival_departure
show arrivals and departures in vehicle timetables
Scrollbar data structure.
Definition: widget_type.h:587
static const VehicleOrderID INVALID_VEH_ORDER_ID
Invalid vehicle order index (sentinel)
Definition: order_type.h:21
Offset at top to draw the frame rectangular area.
Definition: window_gui.h:62
Other order modifications.
Definition: vehicle_gui.h:33
static T SetBit(T &x, const uint8 y)
Set a bit in a variable.
Horizontal container.
Definition: widget_type.h:73
static const Ticks INVALID_TICKS
Representation of an invalid number of ticks.
Definition: date_type.h:109
void ShowQueryString(StringID str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
Definition: misc_gui.cpp:1119
OrderList * list
Pointer to the order list for this vehicle.
Definition: vehicle_base.h:319
bool IsCompleteTimetable() const
Checks whether all orders of the list have a filled timetable.
Definition: order_cmd.cpp:590
bool IsTravelTimetabled() const
Does this order have an explicit travel time set?
Definition: order_base.h:176
Resize box (normally at bottom-right of a window)
Definition: widget_type.h:66
uint32 current_order_time
How many ticks have passed since this order started.
Definition: base_consist.h:21
autofill the timetable
Definition: command_type.h:329
Vehicle data structure.
Definition: vehicle_base.h:210
Tindex index
Index of this pool item.
Definition: pool_type.hpp:189
static const int DAY_TICKS
1 day is 74 ticks; _date_fract used to be uint16 and incremented by 885.
Definition: date_type.h:28
Close box (at top-left of a window)
Definition: widget_type.h:67
return success even when the text didn&#39;t change
Definition: textbuf_gui.h:20
Stuff related to the text buffer GUI.
ModifyTimetableFlags
Enumeration for the data to set in CmdChangeTimetable.
Definition: order_type.h:170
int32 lateness_counter
How many ticks late (or early if negative) this vehicle is.
Definition: base_consist.h:22
#define AllocaM(T, num_elements)
alloca() has to be called in the parent function, so define AllocaM() as a macro
Definition: alloc_func.hpp:132
Clear time button.
static T max(const T a, const T b)
Returns the maximum of two values.
Definition: math_func.hpp:24
Year _cur_year
Current year, starting at 0.
Definition: date.cpp:24
Functions related to the vehicle&#39;s GUIs.
const Vehicle * vehicle
Vehicle monitored by the window.
void OnResize() override
Called after the window got resized.
Functions, definitions and such used only by the GUI.
The vehicle will stop at any station it passes except the destination.
Definition: order_type.h:75
void ShowTimetableWindow(const Vehicle *v)
Show the timetable for a given vehicle.
void OnPaint() override
The window must be repainted.
Order * next
Pointer to next order. If nullptr, end of list.
Definition: order_base.h:49
void SetCount(int num)
Sets the number of elements in the list.
Definition: widget_type.h:668
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:908
Set travel time.
Definition: order_type.h:172
Data structure for an opened window.
Definition: window_gui.h:276
bool _ctrl_pressed
Is Ctrl pressed?
Definition: gfx.cpp:35
The vehicle will stop at any station it passes and the destination.
Definition: order_type.h:73
Autoreplace replaced the vehicle.
Definition: vehicle_gui.h:35
void SetTimetableParams(int param1, int param2, Ticks ticks)
Set the timetable parameters in the format as described by the setting.
Vehicle orders; Window numbers:
Definition: window_type.h:205
void OnQueryTextFinished(char *str) override
The query window opened from this window has closed.
Functions related to low-level strings.
Only numeric ones.
Definition: string_type.h:28
uint ConvertDisplaySpeedToKmhishSpeed(uint speed)
Convert the given display speed to the km/h-ish speed.
Definition: strings.cpp:757
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX) ...
Definition: widget_type.h:63
DateFract _date_fract
Fractional part of the day.
Definition: date.cpp:27
This window is used for construction; close it whenever changing company.
Definition: window_gui.h:208
Start date button.
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition: order_base.h:61
uint deparr_abbr_width
The width of the departure/arrival abbreviation.
#define FONT_HEIGHT_NORMAL
Height of characters in the normal (FS_NORMAL) font.
Definition: gfx_func.h:176
static NWidgetPart SetDataTip(uint32 data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1012
Functions related to the gfx engine.
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:78
Types related to global configuration settings.
static NWidgetPart SetMinimalSize(int16 x, int16 y)
Widget part function for setting the minimal size.
Definition: widget_type.h:945
Definition of base types and functions in a cross-platform compatible way.
Removed / replaced all orders (after deleting / sharing).
Definition: vehicle_gui.h:32
A number of safeguards to prevent using unsafe methods.
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition: gfx_type.h:245
Normal push-button (no toggle button) with text caption.
Definition: widget_type.h:102
Clear speed limit button.
Simple depressed panel.
Definition: widget_type.h:48
void ShowSetDateWindow(Window *parent, int window_number, Date initial_date, Year min_year, Year max_year, SetDateCallback *callback)
Create the new &#39;set date&#39; window.
Definition: date_gui.cpp:213
Autofill button.
Whether the vehicle should fill in the timetable automatically.
Definition: vehicle_base.h:46
Vehicle view; Window numbers:
Definition: window_type.h:332
set the date that a timetable should start
Definition: command_type.h:330
bool IsWaitTimetabled() const
Does this order have an explicit wait time set?
Definition: order_base.h:174
uint16 GetTimetabledTravel() const
Get the time in ticks a vehicle should take to reach the destination or 0 if it&#39;s not timetabled...
Definition: order_base.h:181
Ticks departure
The departure time.
Order * GetFirstOrder() const
Get the first order of the order chain.
Definition: order_base.h:288
static NWidgetPart NWidget(WidgetType tp, Colours col, int16 idx=-1)
Widget part function for starting a new &#39;real&#39; widget.
Definition: widget_type.h:1112
Vehicle timetable; Window numbers:
Definition: window_type.h:217
Offset at bottom to draw the frame rectangular area.
Definition: window_gui.h:63
int DrawString(int left, int right, int top, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition: gfx.cpp:498
uint deparr_time_width
The width of the departure/arrival time.
void OnClick(Point pt, int widget, int click_count) override
A click with the left mouse button has been made on the window.
static bool BuildArrivalDepartureList(const Vehicle *v, TimetableArrivalDeparture *table)
Build the arrival-departure list for a given vehicle.
Owner owner
Which company owns the vehicle?
Definition: vehicle_base.h:271
bool DoCommandP(const CommandContainer *container, bool my_cmd)
Shortcut for the long DoCommandP when having a container with the data.
Definition: command.cpp:532
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:40
Display plane with zero size in both directions (none filling and resizing).
Definition: widget_type.h:388
Change time button.
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
Date timetable_start
When the vehicle is supposed to start the timetable.
Definition: base_consist.h:23
bool query_is_speed_query
The currently open query window is a speed query and not a time query.
bool IsVisible(uint16 item) const
Checks whether given current item is visible in the list.
Definition: widget_type.h:639
Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:700
uint16 GetWaitTime() const
Get the time in ticks a vehicle will probably wait at the destination (timetabled or not)...
Definition: order_base.h:183
void DeleteWindowById(WindowClass cls, WindowNumber number, bool force)
Delete a window by its class and window number (if it is open).
Definition: window.cpp:1162
Disable/hide the arrival departure panel.
Toggle between expected and scheduled arrivals.
Functions related to companies.
uint16 GetTimetabledWait() const
Get the time in ticks a vehicle should wait at the destination or 0 if it&#39;s not timetabled.
Definition: order_base.h:179
Panel with the expected/scheduled arrivals.
Functions related to the graphical selection of a date.
bool timetable_in_ticks
whether to show the timetable in ticks rather than days
uint ConvertKmhishSpeedToDisplaySpeed(uint speed)
Convert the given km/h-ish speed to the display speed.
Definition: strings.cpp:747
Show the shared order list.
static const OrderID INVALID_ORDER
Invalid order (sentinel)
Definition: order_type.h:26
GUISettings gui
settings related to the GUI
Ticks GetTimetableDurationIncomplete() const
Gets the known duration of the vehicles timetable even if the timetable is not complete.
Definition: order_base.h:368
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:59
Base class for all vehicles.
static bool StrEmpty(const char *s)
Check if a string buffer is empty.
Definition: string_func.h:57
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:48
static bool CanDetermineTimeTaken(const Order *order, bool travelling)
Check whether it is possible to determine how long the order takes.
void SetDParamMaxValue(uint n, uint64 max_value, uint min_count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:104
int32 Ticks
The type to store ticks in.
Definition: date_type.h:16
Vertical container.
Definition: widget_type.h:75
static T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition: math_func.hpp:81
static NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME, WWT_INSET, or WWT_PANEL).
Definition: widget_type.h:997
static uint GB(const T x, const uint8 s, const uint8 n)
Fetch n bits from x, started at bit s.
Do not add shading to this text colour.
Definition: gfx_type.h:269
VehicleType type
Type of vehicle.
Definition: vehicle_type.h:52
Reset lateness button.
void UpdateSelectionStates()
Update the selection state of the arrival/departure data.
Timetable panel.
Vehicle details; Window numbers:
Definition: window_type.h:193
Functions related to commands.
Coordinates of a point in 2D.
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition: gfx.cpp:770
uint16 GetCapacity() const
Gets the number of visible elements of the scrollbar.
Definition: widget_type.h:620
Index of the small font in the font tables.
Definition: gfx_type.h:203
Order * GetOrder(int index) const
Returns order &#39;index&#39; of a vehicle or nullptr when it doesn&#39;t exists.
Definition: vehicle_base.h:858
VehicleOrderID GetNumOrders() const
Get the number of orders this vehicle has.
Definition: vehicle_base.h:685
int32 Date
The type to store our dates in.
Definition: date_type.h:14
Aircraft vehicle type.
Definition: vehicle_type.h:27
bool IsOrderListShared() const
Check if we share our orders with another vehicle.
Definition: vehicle_base.h:679
Offset at right to draw the frame rectangular area.
Definition: window_gui.h:61
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition: widget_type.h:64
Disable/hide the expected selection button.
uint16 vehicle_flags
Used for gradual loading and other miscellaneous things (.
Definition: base_consist.h:30
byte VehicleOrderID
The index of an order within its current vehicle (not pool related)
Definition: order_type.h:15
static NWidgetPart SetFill(uint fill_x, uint fill_y)
Widget part function for setting filling.
Definition: widget_type.h:981
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
#define CMD_MSG(x)
Used to combine a StringID with the command.
Definition: command_type.h:368
int32 WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:705
void SetCapacityFromWidget(Window *w, int widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget. ...
Definition: widget.cpp:1971
Specification of a rectangle with absolute coordinates of all edges.
Vertical scrollbar.
Definition: widget_type.h:82
uint16 GetMaxSpeed() const
Get the maxmimum speed in km-ish/h a vehicle is allowed to reach on the way to the destination...
Definition: order_base.h:192
Text is written right-to-left by default.
Definition: strings_type.h:24
WindowNumber window_number
Window number within the window class.
Definition: window_gui.h:312
Window functions not directly related to making/drawing windows.
Find a place automatically.
Definition: window_gui.h:154
void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int y, bool selected, bool timetable, int left, int middle, int right)
Draws an order in order or timetable GUI.
Definition: order_gui.cpp:213
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition: widget_type.h:78
GUI functions that shouldn&#39;t be here.
Container for the arrival/departure dates of a vehicle.
Ticks arrival
The arrival time.
Date _date
Current date in days (day counter)
Definition: date.cpp:26
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
Update size and resize step of a widget in the window.
static NWidgetPart SetScrollbar(int index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1093
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:44
void DrawWidget(const Rect &r, int widget) const override
Draw the contents of a nested widget.
VehicleOrderID cur_real_order_index
The index to the current real (non-implicit) order.
Definition: base_consist.h:27
Dimensions (a width and height) of a rectangle in 2D.
Value of the NCB_EQUALSIZE flag.
Definition: widget_type.h:427
Offset at left to draw the frame rectangular area.
Definition: window_gui.h:60
static const Year MAX_YEAR
MAX_YEAR, nicely rounded value of the number of years that can be encoded in a single 32 bits date...
Definition: date_type.h:92
Change speed limit button.
This file contains all sprite-related enums and defines.
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition: widget_type.h:62
OrderNonStopFlags GetNonStopType() const
At which stations must we stop?
Definition: order_base.h:131
Order current_order
The current order (+ status, like: loading)
Definition: vehicle_base.h:316
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Types related to the timetable widgets.
uint16 GetPosition() const
Gets the position of the first visible element in the list.
Definition: widget_type.h:629
static void SetDParam(uint n, uint64 v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings_func.h:199