src/vehicle_gui.cpp
changeset 10576 3a8790d797ef
parent 10525 da5bc725cda4
child 10584 15d97b3d442d
equal deleted inserted replaced
10575:fab9a236c1f5 10576:3a8790d797ef
    38 #include "timetable.h"
    38 #include "timetable.h"
    39 
    39 
    40 #include "table/sprites.h"
    40 #include "table/sprites.h"
    41 #include "table/strings.h"
    41 #include "table/strings.h"
    42 
    42 
    43 struct vehicledetails_d {
       
    44 	byte tab;
       
    45 };
       
    46 assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(vehicledetails_d));
       
    47 
       
    48 struct refit_d {
    43 struct refit_d {
    49 	int sel;
    44 	int sel;
    50 	struct RefitOption *cargo;
    45 	struct RefitOption *cargo;
    51 	struct RefitList *list;
    46 	struct RefitList *list;
    52 	uint length;
    47 	uint length;
  1372 		STR_9815_RELIABILITY_BREAKDOWNS,
  1367 		STR_9815_RELIABILITY_BREAKDOWNS,
  1373 		STR_A010_RELIABILITY_BREAKDOWNS,
  1368 		STR_A010_RELIABILITY_BREAKDOWNS,
  1374 	},
  1369 	},
  1375 };
  1370 };
  1376 
  1371 
  1377 /** Initialize a newly created vehicle details window */
       
  1378 void CreateVehicleDetailsWindow(Window *w)
       
  1379 {
       
  1380 	const Vehicle *v = GetVehicle(w->window_number);
       
  1381 
       
  1382 	switch (v->type) {
       
  1383 		case VEH_TRAIN:
       
  1384 			ResizeWindow(w, 0, 39);
       
  1385 
       
  1386 			w->vscroll.cap = 6;
       
  1387 			w->height += 12;
       
  1388 			w->resize.step_height = 14;
       
  1389 			w->resize.height = w->height - 14 * 2; // Minimum of 4 wagons in the display
       
  1390 
       
  1391 			w->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_8867_NAME_TRAIN;
       
  1392 			w->widget[VLD_WIDGET_CAPTION].data = STR_8802_DETAILS;
       
  1393 			break;
       
  1394 
       
  1395 		case VEH_ROAD: {
       
  1396 			w->widget[VLD_WIDGET_CAPTION].data = STR_900C_DETAILS;
       
  1397 			w->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_902E_NAME_ROAD_VEHICLE;
       
  1398 
       
  1399 			if (!RoadVehHasArticPart(v)) break;
       
  1400 
       
  1401 			/* Draw the text under the vehicle instead of next to it, minus the
       
  1402 			* height already allocated for the cargo of the first vehicle. */
       
  1403 			uint height_extension = 15 - 11;
       
  1404 
       
  1405 			/* Add space for the cargo amount for each part. */
       
  1406 			for (const Vehicle *u = v; u != NULL; u = u->Next()) {
       
  1407 				height_extension += 11;
       
  1408 			}
       
  1409 
       
  1410 			ResizeWindow(w, 0, height_extension);
       
  1411 		} break;
       
  1412 
       
  1413 		case VEH_SHIP:
       
  1414 			w->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_982F_NAME_SHIP;
       
  1415 			w->widget[VLD_WIDGET_CAPTION].data = STR_9811_DETAILS;
       
  1416 			break;
       
  1417 
       
  1418 		case VEH_AIRCRAFT:
       
  1419 			ResizeWindow(w, 0, 11);
       
  1420 			w->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_A032_NAME_AIRCRAFT;
       
  1421 			w->widget[VLD_WIDGET_CAPTION].data = STR_A00C_DETAILS;
       
  1422 			break;
       
  1423 		default: NOT_REACHED();
       
  1424 	}
       
  1425 
       
  1426 	if (v->type != VEH_TRAIN) {
       
  1427 		w->vscroll.cap = 1;
       
  1428 		w->widget[VLD_WIDGET_MIDDLE_DETAILS].right += 12;
       
  1429 	}
       
  1430 
       
  1431 	w->widget[VLD_WIDGET_MIDDLE_DETAILS].data = (w->vscroll.cap << 8) + 1;
       
  1432 	w->caption_color = v->owner;
       
  1433 
       
  1434 	WP(w, vehicledetails_d).tab = 0;
       
  1435 }
       
  1436 
       
  1437 /** Checks whether service interval is enabled for the vehicle. */
       
  1438 static inline bool IsVehicleServiceIntervalEnabled(const VehicleType vehicle_type)
       
  1439 {
       
  1440 	switch (vehicle_type) {
       
  1441 		default: NOT_REACHED();
       
  1442 		case VEH_TRAIN:    return _patches.servint_trains   != 0; break;
       
  1443 		case VEH_ROAD:     return _patches.servint_roadveh  != 0; break;
       
  1444 		case VEH_SHIP:     return _patches.servint_ships    != 0; break;
       
  1445 		case VEH_AIRCRAFT: return _patches.servint_aircraft != 0; break;
       
  1446 	}
       
  1447 	return false; // kill a compiler warning
       
  1448 }
       
  1449 
  1372 
  1450 extern int GetTrainDetailsWndVScroll(VehicleID veh_id, byte det_tab);
  1373 extern int GetTrainDetailsWndVScroll(VehicleID veh_id, byte det_tab);
  1451 extern void DrawTrainDetails(const Vehicle *v, int x, int y, int vscroll_pos, uint16 vscroll_cap, byte det_tab);
  1374 extern void DrawTrainDetails(const Vehicle *v, int x, int y, int vscroll_pos, uint16 vscroll_cap, byte det_tab);
  1452 extern void DrawRoadVehDetails(const Vehicle *v, int x, int y);
  1375 extern void DrawRoadVehDetails(const Vehicle *v, int x, int y);
  1453 extern void DrawShipDetails(const Vehicle *v, int x, int y);
  1376 extern void DrawShipDetails(const Vehicle *v, int x, int y);
  1454 extern void DrawAircraftDetails(const Vehicle *v, int x, int y);
  1377 extern void DrawAircraftDetails(const Vehicle *v, int x, int y);
  1455 
  1378 
  1456 /**
  1379 struct VehicleDetailsWindow : Window {
  1457 * Draw the details for the given vehicle at the position (x, y) of the Details windows
  1380 	int tab;
  1458 *
  1381 
  1459 * @param v current vehicle
  1382 	/** Initialize a newly created vehicle details window */
  1460 * @param x The x coordinate
  1383 	VehicleDetailsWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
  1461 * @param y The y coordinate
  1384 	{
  1462 * @param vscroll_pos (train only)
  1385 		const Vehicle *v = GetVehicle(this->window_number);
  1463 * @param vscroll_cap (train only)
  1386 
  1464 * @param det_tab (train only)
  1387 		switch (v->type) {
  1465 */
  1388 			case VEH_TRAIN:
  1466 static inline void DrawVehicleDetails(const Vehicle *v, int x, int y, int vscroll_pos, uint vscroll_cap, byte det_tab)
  1389 				ResizeWindow(this, 0, 39);
  1467 {
  1390 
  1468 	switch (v->type) {
  1391 				this->vscroll.cap = 6;
  1469 		case VEH_TRAIN:    DrawTrainDetails(v, x, y, vscroll_pos, vscroll_cap, det_tab);  break;
  1392 				this->height += 12;
  1470 		case VEH_ROAD:     DrawRoadVehDetails(v, x, y);  break;
  1393 				this->resize.step_height = 14;
  1471 		case VEH_SHIP:     DrawShipDetails(v, x, y);     break;
  1394 				this->resize.height = this->height - 14 * 2; // Minimum of 4 wagons in the display
  1472 		case VEH_AIRCRAFT: DrawAircraftDetails(v, x, y); break;
  1395 
  1473 		default: NOT_REACHED();
  1396 				this->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_8867_NAME_TRAIN;
  1474 	}
  1397 				this->widget[VLD_WIDGET_CAPTION].data = STR_8802_DETAILS;
  1475 }
  1398 				break;
  1476 
  1399 
  1477 /** Repaint vehicle details window. */
  1400 			case VEH_ROAD: {
  1478 static void DrawVehicleDetailsWindow(Window *w)
  1401 				this->widget[VLD_WIDGET_CAPTION].data = STR_900C_DETAILS;
  1479 {
  1402 				this->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_902E_NAME_ROAD_VEHICLE;
  1480 	const Vehicle *v = GetVehicle(w->window_number);
  1403 
  1481 	byte det_tab = WP(w, vehicledetails_d).tab;
  1404 				if (!RoadVehHasArticPart(v)) break;
  1482 
  1405 
  1483 	w->SetWidgetDisabledState(VLD_WIDGET_RENAME_VEHICLE, v->owner != _local_player);
  1406 				/* Draw the text under the vehicle instead of next to it, minus the
  1484 
  1407 				 * height already allocated for the cargo of the first vehicle. */
  1485 	if (v->type == VEH_TRAIN) {
  1408 				uint height_extension = 15 - 11;
  1486 		w->DisableWidget(det_tab + VLD_WIDGET_DETAILS_CARGO_CARRIED);
  1409 
  1487 		SetVScrollCount(w, GetTrainDetailsWndVScroll(v->index, det_tab));
  1410 				/* Add space for the cargo amount for each part. */
  1488 	}
  1411 				for (const Vehicle *u = v; u != NULL; u = u->Next()) {
  1489 
  1412 					height_extension += 11;
  1490 	w->SetWidgetsHiddenState(v->type != VEH_TRAIN,
  1413 				}
  1491 		VLD_WIDGET_SCROLLBAR,
  1414 
  1492 		VLD_WIDGET_DETAILS_CARGO_CARRIED,
  1415 				ResizeWindow(this, 0, height_extension);
  1493 		VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
  1416 			} break;
  1494 		VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
  1417 
  1495 		VLD_WIDGET_DETAILS_TOTAL_CARGO,
  1418 			case VEH_SHIP:
  1496 		VLD_WIDGET_RESIZE,
  1419 				this->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_982F_NAME_SHIP;
  1497 		WIDGET_LIST_END);
  1420 				this->widget[VLD_WIDGET_CAPTION].data = STR_9811_DETAILS;
  1498 
  1421 				break;
  1499 	/* Disable service-scroller when interval is set to disabled */
  1422 
  1500 	w->SetWidgetsDisabledState(!IsVehicleServiceIntervalEnabled(v->type),
  1423 			case VEH_AIRCRAFT:
  1501 		VLD_WIDGET_INCREASE_SERVICING_INTERVAL,
  1424 				ResizeWindow(this, 0, 11);
  1502 		VLD_WIDGET_DECREASE_SERVICING_INTERVAL,
  1425 				this->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_A032_NAME_AIRCRAFT;
  1503 		WIDGET_LIST_END);
  1426 				this->widget[VLD_WIDGET_CAPTION].data = STR_A00C_DETAILS;
  1504 
  1427 				break;
  1505 
  1428 			default: NOT_REACHED();
  1506 	SetDParam(0, v->index);
  1429 		}
  1507 	DrawWindowWidgets(w);
  1430 
  1508 
  1431 		if (v->type != VEH_TRAIN) {
  1509 	/* Draw running cost */
  1432 			this->vscroll.cap = 1;
  1510 	SetDParam(1, v->age / 366);
  1433 			this->widget[VLD_WIDGET_MIDDLE_DETAILS].right += 12;
  1511 	SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
  1434 		}
  1512 	SetDParam(2, v->max_age / 366);
  1435 
  1513 	SetDParam(3, v->GetDisplayRunningCost());
  1436 		this->widget[VLD_WIDGET_MIDDLE_DETAILS].data = (this->vscroll.cap << 8) + 1;
  1514 	DrawString(2, 15, _vehicle_translation_table[VST_VEHICLE_AGE_RUNNING_COST_YR][v->type], TC_FROMSTRING);
  1437 		this->caption_color = v->owner;
  1515 
  1438 
  1516 	/* Draw max speed */
  1439 		this->tab = 0;
  1517 	switch (v->type) {
  1440 	}
  1518 		case VEH_TRAIN:
  1441 
  1519 			SetDParam(2, v->GetDisplayMaxSpeed());
  1442 	/** Checks whether service interval is enabled for the vehicle. */
  1520 			SetDParam(1, v->u.rail.cached_power);
  1443 	static bool IsVehicleServiceIntervalEnabled(const VehicleType vehicle_type)
  1521 			SetDParam(0, v->u.rail.cached_weight);
  1444 	{
  1522 			SetDParam(3, v->u.rail.cached_max_te / 1000);
  1445 		switch (vehicle_type) {
  1523 			DrawString(2, 25, (_patches.realistic_acceleration && v->u.rail.railtype != RAILTYPE_MAGLEV) ?
  1446 			default: NOT_REACHED();
  1524 				STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :
  1447 			case VEH_TRAIN:    return _patches.servint_trains   != 0; break;
  1525 				STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED, TC_FROMSTRING);
  1448 			case VEH_ROAD:     return _patches.servint_roadveh  != 0; break;
  1526 			break;
  1449 			case VEH_SHIP:     return _patches.servint_ships    != 0; break;
  1527 
  1450 			case VEH_AIRCRAFT: return _patches.servint_aircraft != 0; break;
  1528 		case VEH_ROAD:
  1451 		}
  1529 		case VEH_SHIP:
  1452 		return false; // kill a compiler warning
  1530 		case VEH_AIRCRAFT:
  1453 	}
  1531 			SetDParam(0, v->GetDisplayMaxSpeed());
  1454 
  1532 			DrawString(2, 25, _vehicle_translation_table[VST_VEHICLE_MAX_SPEED][v->type], TC_FROMSTRING);
  1455 	/**
  1533 			break;
  1456 	 * Draw the details for the given vehicle at the position (x, y) of the Details windows
  1534 
  1457 	 *
  1535 		default: NOT_REACHED();
  1458 	 * @param v current vehicle
  1536 	}
  1459 	 * @param x The x coordinate
  1537 
  1460 	 * @param y The y coordinate
  1538 	/* Draw profit */
  1461 	 * @param vscroll_pos (train only)
  1539 	SetDParam(0, v->GetDisplayProfitThisYear());
  1462 	 * @param vscroll_cap (train only)
  1540 	SetDParam(1, v->GetDisplayProfitLastYear());
  1463 	 * @param det_tab (train only)
  1541 	DrawString(2, 35, _vehicle_translation_table[VST_VEHICLE_PROFIT_THIS_YEAR_LAST_YEAR][v->type], TC_FROMSTRING);
  1464 	 */
  1542 
  1465 	static void DrawVehicleDetails(const Vehicle *v, int x, int y, int vscroll_pos, uint vscroll_cap, byte det_tab)
  1543 	/* Draw breakdown & reliability */
  1466 	{
  1544 	SetDParam(0, v->reliability * 100 >> 16);
  1467 		switch (v->type) {
  1545 	SetDParam(1, v->breakdowns_since_last_service);
  1468 			case VEH_TRAIN:    DrawTrainDetails(v, x, y, vscroll_pos, vscroll_cap, det_tab);  break;
  1546 	DrawString(2, 45, _vehicle_translation_table[VST_VEHICLE_RELIABILITY_BREAKDOWNS][v->type], TC_FROMSTRING);
  1469 			case VEH_ROAD:     DrawRoadVehDetails(v, x, y);  break;
  1547 
  1470 			case VEH_SHIP:     DrawShipDetails(v, x, y);     break;
  1548 	/* Draw service interval text */
  1471 			case VEH_AIRCRAFT: DrawAircraftDetails(v, x, y); break;
  1549 	SetDParam(0, v->service_interval);
  1472 			default: NOT_REACHED();
  1550 	SetDParam(1, v->date_of_last_service);
  1473 		}
  1551 	DrawString(13, w->height - (v->type != VEH_TRAIN ? 11 : 23), _patches.servint_ispercent ? STR_SERVICING_INTERVAL_PERCENT : STR_883C_SERVICING_INTERVAL_DAYS, TC_FROMSTRING);
  1474 	}
  1552 
  1475 
  1553 	switch (v->type) {
  1476 	/** Repaint vehicle details window. */
  1554 		case VEH_TRAIN:
  1477 	virtual void OnPaint()
  1555 			DrawVehicleDetails(v, 2, 57, w->vscroll.pos, w->vscroll.cap, det_tab);
  1478 	{
  1556 			break;
  1479 		const Vehicle *v = GetVehicle(this->window_number);
  1557 
  1480 		byte det_tab = this->tab;
  1558 		case VEH_ROAD:
  1481 
  1559 		case VEH_SHIP:
  1482 		this->SetWidgetDisabledState(VLD_WIDGET_RENAME_VEHICLE, v->owner != _local_player);
  1560 		case VEH_AIRCRAFT:
  1483 
  1561 			DrawVehicleImage(v, 3, 57, INVALID_VEHICLE, 0, 0);
  1484 		if (v->type == VEH_TRAIN) {
  1562 			DrawVehicleDetails(v, 75, 57, w->vscroll.pos, w->vscroll.cap, det_tab);
  1485 			this->DisableWidget(det_tab + VLD_WIDGET_DETAILS_CARGO_CARRIED);
  1563 			break;
  1486 			SetVScrollCount(this, GetTrainDetailsWndVScroll(v->index, det_tab));
  1564 
  1487 		}
  1565 		default: NOT_REACHED();
  1488 
  1566 	}
  1489 		this->SetWidgetsHiddenState(v->type != VEH_TRAIN,
  1567 }
  1490 			VLD_WIDGET_SCROLLBAR,
  1568 
  1491 			VLD_WIDGET_DETAILS_CARGO_CARRIED,
  1569 /** Message strings for renaming vehicles indexed by vehicle type. */
  1492 			VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
  1570 static const StringID _name_vehicle_title[] = {
  1493 			VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
  1571 	STR_8865_NAME_TRAIN,
  1494 			VLD_WIDGET_DETAILS_TOTAL_CARGO,
  1572 	STR_902C_NAME_ROAD_VEHICLE,
  1495 			VLD_WIDGET_RESIZE,
  1573 	STR_9831_NAME_SHIP,
  1496 			WIDGET_LIST_END);
  1574 	STR_A030_NAME_AIRCRAFT
  1497 
  1575 };
  1498 		/* Disable service-scroller when interval is set to disabled */
  1576 
  1499 		this->SetWidgetsDisabledState(!IsVehicleServiceIntervalEnabled(v->type),
  1577 /** Message strings for error while renaming indexed by vehicle type. */
  1500 			VLD_WIDGET_INCREASE_SERVICING_INTERVAL,
  1578 static const StringID _name_vehicle_error[] = {
  1501 			VLD_WIDGET_DECREASE_SERVICING_INTERVAL,
  1579 	STR_8866_CAN_T_NAME_TRAIN,
  1502 			WIDGET_LIST_END);
  1580 	STR_902D_CAN_T_NAME_ROAD_VEHICLE,
  1503 
  1581 	STR_9832_CAN_T_NAME_SHIP,
  1504 
  1582 	STR_A031_CAN_T_NAME_AIRCRAFT
  1505 		SetDParam(0, v->index);
  1583 };
  1506 		DrawWindowWidgets(this);
  1584 
  1507 
  1585 /** Window event hook for vehicle details. */
  1508 		/* Draw running cost */
  1586 static void VehicleDetailsWndProc(Window *w, WindowEvent *e)
  1509 		SetDParam(1, v->age / 366);
  1587 {
  1510 		SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
  1588 	switch (e->event) {
  1511 		SetDParam(2, v->max_age / 366);
  1589 		case WE_CREATE:
  1512 		SetDParam(3, v->GetDisplayRunningCost());
  1590 			CreateVehicleDetailsWindow(w);
  1513 		DrawString(2, 15, _vehicle_translation_table[VST_VEHICLE_AGE_RUNNING_COST_YR][v->type], TC_FROMSTRING);
  1591 			break;
  1514 
  1592 
  1515 		/* Draw max speed */
  1593 		case WE_PAINT:
  1516 		switch (v->type) {
  1594 			DrawVehicleDetailsWindow(w);
  1517 			case VEH_TRAIN:
  1595 			break;
  1518 				SetDParam(2, v->GetDisplayMaxSpeed());
  1596 
  1519 				SetDParam(1, v->u.rail.cached_power);
  1597 		case WE_CLICK: {
  1520 				SetDParam(0, v->u.rail.cached_weight);
  1598 			switch (e->we.click.widget) {
  1521 				SetDParam(3, v->u.rail.cached_max_te / 1000);
  1599 				case VLD_WIDGET_RENAME_VEHICLE: {// rename
  1522 				DrawString(2, 25, (_patches.realistic_acceleration && v->u.rail.railtype != RAILTYPE_MAGLEV) ?
  1600 					const Vehicle *v = GetVehicle(w->window_number);
  1523 					STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :
  1601 					SetDParam(0, v->index);
  1524 					STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED, TC_FROMSTRING);
  1602 					ShowQueryString(STR_VEHICLE_NAME, _name_vehicle_title[v->type], 31, 150, w, CS_ALPHANUMERAL);
  1525 				break;
  1603 				} break;
  1526 
  1604 
  1527 			case VEH_ROAD:
  1605 				case VLD_WIDGET_INCREASE_SERVICING_INTERVAL:   // increase int
  1528 			case VEH_SHIP:
  1606 				case VLD_WIDGET_DECREASE_SERVICING_INTERVAL: { // decrease int
  1529 			case VEH_AIRCRAFT:
  1607 					int mod = _ctrl_pressed ? 5 : 10;
  1530 				SetDParam(0, v->GetDisplayMaxSpeed());
  1608 					const Vehicle *v = GetVehicle(w->window_number);
  1531 				DrawString(2, 25, _vehicle_translation_table[VST_VEHICLE_MAX_SPEED][v->type], TC_FROMSTRING);
  1609 
  1532 				break;
  1610 					mod = (e->we.click.widget == VLD_WIDGET_DECREASE_SERVICING_INTERVAL) ? -mod : mod;
  1533 
  1611 					mod = GetServiceIntervalClamped(mod + v->service_interval);
  1534 			default: NOT_REACHED();
  1612 					if (mod == v->service_interval) return;
  1535 		}
  1613 
  1536 
  1614 					DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
  1537 		/* Draw profit */
  1615 				} break;
  1538 		SetDParam(0, v->GetDisplayProfitThisYear());
  1616 
  1539 		SetDParam(1, v->GetDisplayProfitLastYear());
  1617 				case VLD_WIDGET_DETAILS_CARGO_CARRIED:
  1540 		DrawString(2, 35, _vehicle_translation_table[VST_VEHICLE_PROFIT_THIS_YEAR_LAST_YEAR][v->type], TC_FROMSTRING);
  1618 				case VLD_WIDGET_DETAILS_TRAIN_VEHICLES:
  1541 
  1619 				case VLD_WIDGET_DETAILS_CAPACITY_OF_EACH:
  1542 		/* Draw breakdown & reliability */
  1620 				case VLD_WIDGET_DETAILS_TOTAL_CARGO:
  1543 		SetDParam(0, v->reliability * 100 >> 16);
  1621 					w->SetWidgetsDisabledState(false,
  1544 		SetDParam(1, v->breakdowns_since_last_service);
  1622 						VLD_WIDGET_DETAILS_CARGO_CARRIED,
  1545 		DrawString(2, 45, _vehicle_translation_table[VST_VEHICLE_RELIABILITY_BREAKDOWNS][v->type], TC_FROMSTRING);
  1623 						VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
  1546 
  1624 						VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
  1547 		/* Draw service interval text */
  1625 						VLD_WIDGET_DETAILS_TOTAL_CARGO,
  1548 		SetDParam(0, v->service_interval);
  1626 						e->we.click.widget,
  1549 		SetDParam(1, v->date_of_last_service);
  1627 						WIDGET_LIST_END);
  1550 		DrawString(13, this->height - (v->type != VEH_TRAIN ? 11 : 23), _patches.servint_ispercent ? STR_SERVICING_INTERVAL_PERCENT : STR_883C_SERVICING_INTERVAL_DAYS, TC_FROMSTRING);
  1628 
  1551 
  1629 					WP(w, vehicledetails_d).tab = e->we.click.widget - VLD_WIDGET_DETAILS_CARGO_CARRIED;
  1552 		switch (v->type) {
  1630 					w->SetDirty();
  1553 			case VEH_TRAIN:
  1631 					break;
  1554 				DrawVehicleDetails(v, 2, 57, this->vscroll.pos, this->vscroll.cap, det_tab);
  1632 			}
  1555 				break;
  1633 		} break;
  1556 
  1634 
  1557 			case VEH_ROAD:
  1635 		case WE_ON_EDIT_TEXT:
  1558 			case VEH_SHIP:
  1636 			if (!StrEmpty(e->we.edittext.str)) {
  1559 			case VEH_AIRCRAFT:
  1637 				_cmd_text = e->we.edittext.str;
  1560 				DrawVehicleImage(v, 3, 57, INVALID_VEHICLE, 0, 0);
  1638 				DoCommandP(0, w->window_number, 0, NULL, CMD_NAME_VEHICLE | CMD_MSG(_name_vehicle_error[GetVehicle(w->window_number)->type]));
  1561 				DrawVehicleDetails(v, 75, 57, this->vscroll.pos, this->vscroll.cap, det_tab);
  1639 			}
  1562 				break;
  1640 			break;
  1563 
  1641 
  1564 			default: NOT_REACHED();
  1642 		case WE_RESIZE:
  1565 		}
  1643 			if (e->we.sizing.diff.x != 0) ResizeButtons(w, VLD_WIDGET_DETAILS_CARGO_CARRIED, VLD_WIDGET_DETAILS_TOTAL_CARGO);
  1566 	}
  1644 			if (e->we.sizing.diff.y == 0) break;
  1567 
  1645 
  1568 	virtual void OnClick(Point pt, int widget)
  1646 			w->vscroll.cap += e->we.sizing.diff.y / 14;
  1569 	{
  1647 			w->widget[VLD_WIDGET_MIDDLE_DETAILS].data = (w->vscroll.cap << 8) + 1;
  1570 		/** Message strings for renaming vehicles indexed by vehicle type. */
  1648 			break;
  1571 		static const StringID _name_vehicle_title[] = {
  1649 	}
  1572 			STR_8865_NAME_TRAIN,
  1650 }
  1573 			STR_902C_NAME_ROAD_VEHICLE,
       
  1574 			STR_9831_NAME_SHIP,
       
  1575 			STR_A030_NAME_AIRCRAFT
       
  1576 		};
       
  1577 
       
  1578 		switch (widget) {
       
  1579 			case VLD_WIDGET_RENAME_VEHICLE: {// rename
       
  1580 				const Vehicle *v = GetVehicle(this->window_number);
       
  1581 				SetDParam(0, v->index);
       
  1582 				ShowQueryString(STR_VEHICLE_NAME, _name_vehicle_title[v->type], 31, 150, this, CS_ALPHANUMERAL);
       
  1583 			} break;
       
  1584 
       
  1585 			case VLD_WIDGET_INCREASE_SERVICING_INTERVAL:   // increase int
       
  1586 			case VLD_WIDGET_DECREASE_SERVICING_INTERVAL: { // decrease int
       
  1587 				int mod = _ctrl_pressed ? 5 : 10;
       
  1588 				const Vehicle *v = GetVehicle(this->window_number);
       
  1589 
       
  1590 				mod = (widget == VLD_WIDGET_DECREASE_SERVICING_INTERVAL) ? -mod : mod;
       
  1591 				mod = GetServiceIntervalClamped(mod + v->service_interval);
       
  1592 				if (mod == v->service_interval) return;
       
  1593 
       
  1594 				DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
       
  1595 			} break;
       
  1596 
       
  1597 			case VLD_WIDGET_DETAILS_CARGO_CARRIED:
       
  1598 			case VLD_WIDGET_DETAILS_TRAIN_VEHICLES:
       
  1599 			case VLD_WIDGET_DETAILS_CAPACITY_OF_EACH:
       
  1600 			case VLD_WIDGET_DETAILS_TOTAL_CARGO:
       
  1601 				this->SetWidgetsDisabledState(false,
       
  1602 					VLD_WIDGET_DETAILS_CARGO_CARRIED,
       
  1603 					VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
       
  1604 					VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
       
  1605 					VLD_WIDGET_DETAILS_TOTAL_CARGO,
       
  1606 					widget,
       
  1607 					WIDGET_LIST_END);
       
  1608 
       
  1609 				this->tab = widget - VLD_WIDGET_DETAILS_CARGO_CARRIED;
       
  1610 				this->SetDirty();
       
  1611 				break;
       
  1612 		}
       
  1613 	}
       
  1614 
       
  1615 	virtual void OnQueryTextFinished(char *str)
       
  1616 	{
       
  1617 		/** Message strings for error while renaming indexed by vehicle type. */
       
  1618 		static const StringID _name_vehicle_error[] = {
       
  1619 			STR_8866_CAN_T_NAME_TRAIN,
       
  1620 			STR_902D_CAN_T_NAME_ROAD_VEHICLE,
       
  1621 			STR_9832_CAN_T_NAME_SHIP,
       
  1622 			STR_A031_CAN_T_NAME_AIRCRAFT
       
  1623 		};
       
  1624 
       
  1625 		if (!StrEmpty(str)) {
       
  1626 			_cmd_text = str;
       
  1627 			DoCommandP(0, this->window_number, 0, NULL, CMD_NAME_VEHICLE | CMD_MSG(_name_vehicle_error[GetVehicle(this->window_number)->type]));
       
  1628 		}
       
  1629 	}
       
  1630 
       
  1631 	virtual void OnResize(Point new_size, Point delta)
       
  1632 	{
       
  1633 		if (delta.x != 0) ResizeButtons(this, VLD_WIDGET_DETAILS_CARGO_CARRIED, VLD_WIDGET_DETAILS_TOTAL_CARGO);
       
  1634 		if (delta.y == 0) return;
       
  1635 
       
  1636 		this->vscroll.cap += delta.y / 14;
       
  1637 		this->widget[VLD_WIDGET_MIDDLE_DETAILS].data = (this->vscroll.cap << 8) + 1;
       
  1638 	}
       
  1639 };
  1651 
  1640 
  1652 /** Vehicle details window descriptor. */
  1641 /** Vehicle details window descriptor. */
  1653 static const WindowDesc _vehicle_details_desc = {
  1642 static const WindowDesc _vehicle_details_desc = {
  1654 	WDP_AUTO, WDP_AUTO, 405, 113, 405, 113,
  1643 	WDP_AUTO, WDP_AUTO, 405, 113, 405, 113,
  1655 	WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW,
  1644 	WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW,
  1656 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
  1645 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
  1657 	_vehicle_details_widgets,
  1646 	_vehicle_details_widgets,
  1658 	VehicleDetailsWndProc
  1647 	NULL
  1659 };
  1648 };
  1660 
  1649 
  1661 /** Shows the vehicle details window of the given vehicle. */
  1650 /** Shows the vehicle details window of the given vehicle. */
  1662 static void ShowVehicleDetailsWindow(const Vehicle *v)
  1651 static void ShowVehicleDetailsWindow(const Vehicle *v)
  1663 {
  1652 {
  1664 	DeleteWindowById(WC_VEHICLE_ORDERS, v->index);
  1653 	DeleteWindowById(WC_VEHICLE_ORDERS, v->index);
  1665 	DeleteWindowById(WC_VEHICLE_DETAILS, v->index);
  1654 	DeleteWindowById(WC_VEHICLE_DETAILS, v->index);
  1666 	AllocateWindowDescFront<Window>(&_vehicle_details_desc, v->index);
  1655 	AllocateWindowDescFront<VehicleDetailsWindow>(&_vehicle_details_desc, v->index);
  1667 }
  1656 }
  1668 
  1657 
  1669 
  1658 
  1670 /* Unified vehicle GUI - Vehicle View Window */
  1659 /* Unified vehicle GUI - Vehicle View Window */
  1671 
  1660