src/timetable_gui.cpp
branchnoai
changeset 9629 66dde6412125
child 6725 23339968083f
equal deleted inserted replaced
9628:b5c2449616b5 9629:66dde6412125
       
     1 /* $Id$ */
       
     2 
       
     3 /** @file timetable_gui.cpp */
       
     4 
       
     5 #include "stdafx.h"
       
     6 #include "openttd.h"
       
     7 #include "functions.h"
       
     8 #include "variables.h"
       
     9 #include "table/strings.h"
       
    10 #include "command.h"
       
    11 #include "date.h"
       
    12 #include "engine.h"
       
    13 #include "gui.h"
       
    14 #include "string.h"
       
    15 #include "window.h"
       
    16 #include "vehicle.h"
       
    17 #include "cargotype.h"
       
    18 #include "depot.h"
       
    19 
       
    20 static int GetOrderFromTimetableWndPt(Window *w, int y, const Vehicle *v)
       
    21 {
       
    22 	/*
       
    23 	 * Calculation description:
       
    24 	 * 15 = 14 (w->widget[ORDER_WIDGET_ORDER_LIST].top) + 1 (frame-line)
       
    25 	 * 10 = order text hight
       
    26 	 */
       
    27 	int sel = (y - 15) / 10;
       
    28 
       
    29 	if ((uint)sel >= w->vscroll.cap) return INVALID_ORDER;
       
    30 
       
    31 	sel += w->vscroll.pos;
       
    32 
       
    33 	return (sel <= v->num_orders * 2 && sel >= 0) ? sel : INVALID_ORDER;
       
    34 }
       
    35 
       
    36 static inline void SetTimetableParams(int param1, int param2, uint32 time)
       
    37 {
       
    38 	if (_patches.timetable_in_ticks) {
       
    39 		SetDParam(param1, STR_TIMETABLE_TICKS);
       
    40 		SetDParam(param2, time);
       
    41 	} else {
       
    42 		SetDParam(param1, STR_TIMETABLE_DAYS);
       
    43 		SetDParam(param2, time / DAY_TICKS);
       
    44 	}
       
    45 }
       
    46 
       
    47 static void DrawTimetableWindow(Window *w)
       
    48 {
       
    49 	const Vehicle *v = GetVehicle(w->window_number);
       
    50 	int selected = WP(w,order_d).sel;
       
    51 
       
    52 	SetVScrollCount(w, v->num_orders * 2);
       
    53 
       
    54 	if (v->owner == _local_player) {
       
    55 		if (selected == -1) {
       
    56 			DisableWindowWidget(w, 6);
       
    57 			DisableWindowWidget(w, 7);
       
    58 		} else if (selected % 2 == 1) {
       
    59 			EnableWindowWidget(w, 6);
       
    60 			EnableWindowWidget(w, 7);
       
    61 		} else {
       
    62 			const Order *order = GetVehicleOrder(v, (selected + 1) / 2);
       
    63 			bool disable = order == NULL || order->type != OT_GOTO_STATION || (_patches.new_nonstop && (order->flags & OF_NON_STOP));
       
    64 
       
    65 			SetWindowWidgetDisabledState(w, 6, disable);
       
    66 			SetWindowWidgetDisabledState(w, 7, disable);
       
    67 		}
       
    68 
       
    69 		EnableWindowWidget(w, 8);
       
    70 		EnableWindowWidget(w, 9);
       
    71 	} else {
       
    72 		DisableWindowWidget(w, 6);
       
    73 		DisableWindowWidget(w, 7);
       
    74 		DisableWindowWidget(w, 8);
       
    75 		DisableWindowWidget(w, 9);
       
    76 	}
       
    77 
       
    78 	SetWindowWidgetLoweredState(w, 9, HASBIT(v->vehicle_flags, VF_AUTOFILL_TIMETABLE));
       
    79 
       
    80 	SetDParam(0, v->index);
       
    81 	DrawWindowWidgets(w);
       
    82 
       
    83 	int y = 15;
       
    84 	int i = w->vscroll.pos;
       
    85 	VehicleOrderID order_id = (i + 1) / 2;
       
    86 	bool final_order = false;
       
    87 
       
    88 	const Order *order = GetVehicleOrder(v, order_id);
       
    89 
       
    90 	while (order != NULL) {
       
    91 		/* Don't draw anything if it extends past the end of the window. */
       
    92 		if (i - w->vscroll.pos >= w->vscroll.cap) break;
       
    93 
       
    94 		if (i % 2 == 0) {
       
    95 			SetDParam(2, STR_EMPTY);
       
    96 
       
    97 			switch (order->type) {
       
    98 				case OT_GOTO_STATION:
       
    99 					SetDParam(0, (order->flags & OF_NON_STOP) ? STR_880C_GO_NON_STOP_TO : STR_8806_GO_TO);
       
   100 					SetDParam(1, order->dest);
       
   101 
       
   102 					if (order->wait_time > 0) {
       
   103 						SetDParam(2, STR_TIMETABLE_STAY_FOR);
       
   104 						SetTimetableParams(3, 4, order->wait_time);
       
   105 					}
       
   106 
       
   107 					break;
       
   108 
       
   109 				case OT_GOTO_DEPOT: {
       
   110 					StringID string = STR_EMPTY;
       
   111 
       
   112 					if (v->type == VEH_AIRCRAFT) {
       
   113 						string = STR_GO_TO_AIRPORT_HANGAR;
       
   114 						SetDParam(1, order->dest);
       
   115 					} else {
       
   116 						SetDParam(1, GetDepot(order->dest)->town_index);
       
   117 
       
   118 						switch (v->type) {
       
   119 							case VEH_TRAIN: string = (order->flags & OF_NON_STOP) ? STR_880F_GO_NON_STOP_TO_TRAIN_DEPOT : STR_GO_TO_TRAIN_DEPOT; break;
       
   120 							case VEH_ROAD:  string = STR_9038_GO_TO_ROADVEH_DEPOT; break;
       
   121 							case VEH_SHIP:  string = STR_GO_TO_SHIP_DEPOT; break;
       
   122 							default: break;
       
   123 						}
       
   124 					}
       
   125 
       
   126 					if (order->flags & OF_FULL_LOAD) string++; // Service at orders
       
   127 
       
   128 					SetDParam(0, string);
       
   129 				} break;
       
   130 
       
   131 				case OT_GOTO_WAYPOINT:
       
   132 					SetDParam(0, (order->flags & OF_NON_STOP) ? STR_GO_NON_STOP_TO_WAYPOINT : STR_GO_TO_WAYPOINT);
       
   133 					SetDParam(1, order->dest);
       
   134 					break;
       
   135 
       
   136 				default: break;
       
   137 			}
       
   138 
       
   139 			byte colour = (i == selected) ? 0xC : 0x10;
       
   140 
       
   141 			if (order->type != OT_DUMMY) {
       
   142 				DrawString(2, y, STR_TIMETABLE_GO_TO, colour);
       
   143 			} else {
       
   144 				SetDParam(0, STR_INVALID_ORDER);
       
   145 				DrawString(2, y, STR_TIMETABLE_GO_TO, colour);
       
   146 			}
       
   147 
       
   148 			order_id++;
       
   149 
       
   150 			if (order_id >= v->num_orders) {
       
   151 				order = GetVehicleOrder(v, 0);
       
   152 				final_order = true;
       
   153 			} else {
       
   154 				order = order->next;
       
   155 			}
       
   156 		} else {
       
   157 			StringID string;
       
   158 
       
   159 			if (order->travel_time == 0) {
       
   160 				string = STR_TIMETABLE_TRAVEL_NOT_TIMETABLED;
       
   161 			} else {
       
   162 				SetTimetableParams(0, 1, order->travel_time);
       
   163 				string = STR_TIMETABLE_TRAVEL_FOR;
       
   164 			}
       
   165 
       
   166 			byte colour = (i == selected) ? 0xC : 0x10;
       
   167 			DrawString(12, y, string, colour);
       
   168 
       
   169 			if (final_order) break;
       
   170 		}
       
   171 
       
   172 		i++;
       
   173 		y += 10;
       
   174 	}
       
   175 
       
   176 	y = w->widget[5].top + 1;
       
   177 
       
   178 	{
       
   179 		uint total_time = 0;
       
   180 		bool complete = true;
       
   181 
       
   182 		for (const Order *order = GetVehicleOrder(v, 0); order != NULL; order = order->next) {
       
   183 			total_time += order->travel_time + order->wait_time;
       
   184 			if (order->travel_time == 0) complete = false;
       
   185 			if (order->wait_time == 0 && order->type == OT_GOTO_STATION && !(_patches.new_nonstop && (order->flags & OF_NON_STOP))) complete = false;
       
   186 		}
       
   187 
       
   188 		if (total_time != 0) {
       
   189 			SetTimetableParams(0, 1, total_time);
       
   190 			DrawString(2, y, complete ? STR_TIMETABLE_TOTAL_TIME : STR_TIMETABLE_TOTAL_TIME_INCOMPLETE, 0x10);
       
   191 		}
       
   192 	}
       
   193 	y += 10;
       
   194 
       
   195 	if (v->lateness_counter == 0 || (!_patches.timetable_in_ticks && v->lateness_counter / DAY_TICKS == 0)) {
       
   196 		DrawString(2, y, STR_TIMETABLE_STATUS_ON_TIME, 0x10);
       
   197 	} else {
       
   198 		SetTimetableParams(0, 1, abs(v->lateness_counter));
       
   199 		DrawString(2, y, v->lateness_counter < 0 ? STR_TIMETABLE_STATUS_EARLY : STR_TIMETABLE_STATUS_LATE, 0x10);
       
   200 	}
       
   201 }
       
   202 
       
   203 static inline uint32 PackTimetableArgs(const Vehicle *v, uint selected)
       
   204 {
       
   205 	uint order_number = (selected + 1) / 2;
       
   206 	uint is_journey   = (selected % 2 == 1) ? 1 : 0;
       
   207 
       
   208 	if (order_number >= v->num_orders) order_number = 0;
       
   209 
       
   210 	return v->index | (order_number << 16) | (is_journey << 24);
       
   211 }
       
   212 
       
   213 static void TimetableWndProc(Window *w, WindowEvent *we)
       
   214 {
       
   215 	switch (we->event) {
       
   216 		case WE_PAINT:
       
   217 			DrawTimetableWindow(w);
       
   218 			break;
       
   219 
       
   220 		case WE_CLICK: {
       
   221 			const Vehicle *v = GetVehicle(w->window_number);
       
   222 
       
   223 			switch (we->we.click.widget) {
       
   224 				case 3: { /* Main panel. */
       
   225 					int selected = GetOrderFromTimetableWndPt(w, we->we.click.pt.y, v);
       
   226 
       
   227 					if (selected == INVALID_ORDER || selected == WP(w,order_d).sel) {
       
   228 						/* Deselect clicked order */
       
   229 						WP(w,order_d).sel = -1;
       
   230 					} else {
       
   231 						/* Select clicked order */
       
   232 						WP(w,order_d).sel = selected;
       
   233 					}
       
   234 				} break;
       
   235 
       
   236 				case 6: { /* "Wait For" button. */
       
   237 					int selected = WP(w,order_d).sel;
       
   238 					VehicleOrderID real = (selected + 1) / 2;
       
   239 
       
   240 					if (real >= v->num_orders) real = 0;
       
   241 
       
   242 					const Order *order = GetVehicleOrder(v, real);
       
   243 					StringID current = STR_EMPTY;
       
   244 
       
   245 					if (order != NULL) {
       
   246 						uint time = (selected % 2 == 1) ? order->travel_time : order->wait_time;
       
   247 						if (!_patches.timetable_in_ticks) time /= DAY_TICKS;
       
   248 
       
   249 						if (time != 0) {
       
   250 							SetDParam(0, time);
       
   251 							current = STR_CONFIG_PATCHES_INT32;
       
   252 						}
       
   253 					}
       
   254 
       
   255 					ShowQueryString(current, STR_TIMETABLE_CHANGE_TIME, 31, 150, w, CS_NUMERAL);
       
   256 				} break;
       
   257 
       
   258 				case 7: { /* Clear waiting time button. */
       
   259 					uint32 p1 = PackTimetableArgs(v, WP(w,order_d).sel);
       
   260 					DoCommandP(0, p1, 0, NULL, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
       
   261 				} break;
       
   262 
       
   263 				case 8: /* Reset the vehicle's late counter. */
       
   264 					DoCommandP(0, v->index, 0, NULL, CMD_SET_VEHICLE_ON_TIME | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
       
   265 					break;
       
   266 
       
   267 				case 9: /* Autofill the timetable. */
       
   268 					DoCommandP(0, v->index, HASBIT(v->vehicle_flags, VF_AUTOFILL_TIMETABLE) ? 0 : 1, NULL, CMD_AUTOFILL_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
       
   269 					break;
       
   270 			}
       
   271 
       
   272 			SetWindowDirty(w);
       
   273 		} break;
       
   274 
       
   275 		case WE_ON_EDIT_TEXT: {
       
   276 			const Vehicle *v = GetVehicle(w->window_number);
       
   277 
       
   278 			uint32 p1 = PackTimetableArgs(v, WP(w,order_d).sel);
       
   279 
       
   280 			uint64 time = StrEmpty(we->we.edittext.str) ? 0 : strtoul(we->we.edittext.str, NULL, 10);
       
   281 			if (!_patches.timetable_in_ticks) time *= DAY_TICKS;
       
   282 
       
   283 			uint32 p2 = minu(time, MAX_UVALUE(uint16));
       
   284 
       
   285 			DoCommandP(0, p1, p2, NULL, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
       
   286 		} break;
       
   287 
       
   288 		case WE_RESIZE:
       
   289 			/* Update the scroll + matrix */
       
   290 			w->vscroll.cap = (w->widget[3].bottom - w->widget[3].top) / 10;
       
   291 			break;
       
   292 
       
   293 	}
       
   294 }
       
   295 
       
   296 static const Widget _timetable_widgets[] = {
       
   297 	{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                   STR_018B_CLOSE_WINDOW},
       
   298 	{    WWT_CAPTION,   RESIZE_RIGHT,   14,    11,   387,     0,    13, STR_TIMETABLE_TITLE,        STR_018C_WINDOW_TITLE_DRAG_THIS},
       
   299 	{  WWT_STICKYBOX,   RESIZE_LR,      14,   388,   399,     0,    13, STR_NULL,                   STR_STICKY_BUTTON},
       
   300 
       
   301 	{      WWT_PANEL,   RESIZE_RB,      14,     0,   387,    14,    95, STR_NULL,                   STR_TIMETABLE_TOOLTIP},
       
   302 	{  WWT_SCROLLBAR,   RESIZE_LRB,     14,   388,   399,    14,    95, STR_NULL,                   STR_0190_SCROLL_BAR_SCROLLS_LIST},
       
   303 
       
   304 	{      WWT_PANEL,   RESIZE_RTB,     14,     0,   399,    96,   117, STR_NULL,                   STR_NULL},
       
   305 
       
   306 	{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,     0,   109,   118,   129, STR_TIMETABLE_CHANGE_TIME,  STR_TIMETABLE_WAIT_TIME_TOOLTIP},
       
   307 	{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   110,   219,   118,   129, STR_CLEAR_TIME,             STR_TIMETABLE_CLEAR_TIME_TOOLTIP},
       
   308 	{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   220,   337,   118,   129, STR_RESET_LATENESS,         STR_TIMETABLE_RESET_LATENESS_TOOLTIP},
       
   309 	{ WWT_PUSHTXTBTN,   RESIZE_TB,      14,   338,   387,   118,   129, STR_TIMETABLE_AUTOFILL,     STR_TIMETABLE_AUTOFILL_TOOLTIP},
       
   310 
       
   311 	{      WWT_PANEL,   RESIZE_RTB,     14,   388,   387,   118,   129, STR_NULL,                   STR_NULL},
       
   312 	{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   388,   399,   118,   129, STR_NULL,                   STR_RESIZE_BUTTON},
       
   313 
       
   314 	{    WIDGETS_END }
       
   315 };
       
   316 
       
   317 static const WindowDesc _timetable_desc = {
       
   318 	WDP_AUTO, WDP_AUTO, 400, 130,
       
   319 	WC_VEHICLE_TIMETABLE, WC_VEHICLE_VIEW,
       
   320 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
       
   321 	_timetable_widgets,
       
   322 	TimetableWndProc
       
   323 };
       
   324 
       
   325 void ShowTimetableWindow(const Vehicle *v)
       
   326 {
       
   327 	Window *w = AllocateWindowDescFront(&_timetable_desc, v->index);
       
   328 
       
   329 	if (w != NULL) {
       
   330 		w->caption_color = v->owner;
       
   331 		w->vscroll.cap = 8;
       
   332 		w->resize.step_height = 10;
       
   333 		WP(w,order_d).sel = -1;
       
   334 	}
       
   335 }