(svn r6513) -Codechange: unified the code to draw depot windows

This change is intended to make it easier to make depot behaviour consistent
   and faster to code when adding more features in the future
   The user interface should hopefully not be affected by this
This commit is contained in:
bjarni
2006-09-26 16:47:51 +00:00
parent 65a3777a40
commit f7769e885e
15 changed files with 827 additions and 1264 deletions

View File

@@ -349,7 +349,7 @@ void ShowBuildTrainWindow(TileIndex tile)
* @param len Length measured in 1/8ths of a standard wagon.
* @return Number of pixels across.
*/
static int WagonLengthToPixels(int len) {
int WagonLengthToPixels(int len) {
return (len * _traininfo_vehicle_width) / 8;
}
@@ -396,416 +396,6 @@ void DrawTrainImage(const Vehicle *v, int x, int y, int count, int skip, Vehicle
_cur_dpi = old_dpi;
}
static void DrawTrainDepotWindow(Window *w)
{
Vehicle **vl = WP(w, traindepot_d).vehicle_list;
TileIndex tile;
int x, y, i, hnum, max;
Depot *depot;
uint16 num;
tile = w->window_number;
/* setup disabled buttons */
w->disabled_state =
IsTileOwner(tile, _local_player) ? 0 : ((1 << 4) | (1 << 5) | (1 << 8) | (1<<9));
/* determine amount of items for scroller */
hnum = 8;
for (num = 0; num < WP(w, traindepot_d).engine_count; num++) {
const Vehicle *v = vl[num];
hnum = maxu(hnum, v->u.rail.cached_total_length);
}
/* Always have 1 empty row, so people can change the setting of the train */
SetVScrollCount(w, WP(w, traindepot_d).engine_count + WP(w, traindepot_d).wagon_count + 1);
SetHScrollCount(w, WagonLengthToPixels(hnum));
/* locate the depot struct */
depot = GetDepotByTile(tile);
assert(depot != NULL);
SetDParam(0, depot->town_index);
DrawWindowWidgets(w);
x = 2;
y = 15;
num = w->vscroll.pos;
max = min(WP(w, traindepot_d).engine_count, w->vscroll.pos + w->vscroll.cap);
/* draw all trains */
for (; num < max; num++) {
const Vehicle *v = vl[num];
DrawTrainImage(v, x + 21, y, w->hscroll.cap + 4, w->hscroll.pos, WP(w,traindepot_d).sel);
/* Draw the train number */
SetDParam(0, v->unitnumber);
DrawString(x, y, (v->max_age - 366 < v->age) ? STR_00E3 : STR_00E2, 0);
/* Number of wagons relative to a standard length wagon (rounded up) */
SetDParam(0, (v->u.rail.cached_total_length + 7) / 8);
DrawStringRightAligned(w->widget[6].right - 1, y + 4, STR_TINY_BLACK, 0); // Draw the counter
/* Draw the pretty flag */
DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, x + 15, y);
y += 14;
}
max = min(WP(w, traindepot_d).engine_count + WP(w, traindepot_d).wagon_count, w->vscroll.pos + w->vscroll.cap);
/* draw all remaining vehicles */
for (; num < max; num++) {
const Vehicle *v = WP(w, traindepot_d).wagon_list[num - WP(w, traindepot_d).engine_count];
const Vehicle *u;
DrawTrainImage(v, x + 50, y, w->hscroll.cap - 29, 0, WP(w,traindepot_d).sel);
DrawString(x, y + 2, STR_8816, 0);
/*Draw the train counter */
i = 0;
u = v;
do i++; while ( (u=u->next) != NULL); // Determine length of train
SetDParam(0, i); // Set the counter
DrawStringRightAligned(w->widget[6].right - 1, y + 4, STR_TINY_BLACK, 0); // Draw the counter
y += 14;
}
}
typedef struct GetDepotVehiclePtData {
Vehicle *head;
Vehicle *wagon;
} GetDepotVehiclePtData;
static int GetVehicleFromTrainDepotWndPt(const Window *w, int x, int y, GetDepotVehiclePtData *d)
{
Vehicle **vl = WP(w, traindepot_d).vehicle_list;
int row;
int skip = 0;
Vehicle *v;
x = x - 23;
row = (y - 14) / 14;
if ((uint)row >= w->vscroll.cap) return 1; /* means err */
row += w->vscroll.pos;
if (WP(w, traindepot_d).engine_count + WP(w, traindepot_d).wagon_count <= row) {
/* empty row, so no vehicle is selected */
d->head = NULL;
d->wagon = NULL;
return 0;
}
if (WP(w, traindepot_d).engine_count > row) {
v = vl[row];
skip = w->hscroll.pos;
} else {
vl = WP(w, traindepot_d).wagon_list;
v = vl[row - WP(w, traindepot_d).engine_count];
/* free wagons don't have an initial loco. */
x -= _traininfo_vehicle_width;
}
d->head = d->wagon = v;
/* either pressed the flag or the number, but only when it's a loco */
if (x < 0 && IsFrontEngine(v)) return (x >= -10) ? -2 : -1;
skip = (skip * 8) / _traininfo_vehicle_width;
x = (x * 8) / _traininfo_vehicle_width;
/* Skip vehicles that are scrolled off the list */
x += skip;
/* find the vehicle in this row that was clicked */
while (v != NULL && (x -= v->u.rail.cached_veh_length) >= 0) v = v->next;
// if an articulated part was selected, find its parent
while (v != NULL && IsArticulatedPart(v)) v = GetPrevVehicleInChain(v);
d->wagon = v;
return 0;
}
static void TrainDepotMoveVehicle(Vehicle *wagon, VehicleID sel, Vehicle *head)
{
Vehicle *v;
v = GetVehicle(sel);
if (v == wagon) return;
if (wagon == NULL) {
if (head != NULL) wagon = GetLastVehicleInChain(head);
} else {
wagon = GetPrevVehicleInChain(wagon);
if (wagon == NULL) return;
}
if (wagon == v) return;
DoCommandP(v->tile, v->index + ((wagon == NULL ? INVALID_VEHICLE : wagon->index) << 16), _ctrl_pressed ? 1 : 0, NULL, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_8837_CAN_T_MOVE_VEHICLE));
}
static void TrainDepotClickTrain(Window *w, int x, int y)
{
GetDepotVehiclePtData gdvp;
int mode;
Vehicle *v;
mode = GetVehicleFromTrainDepotWndPt(w, x, y, &gdvp);
// share / copy orders
if (_thd.place_mode && mode <= 0) {
_place_clicked_vehicle = gdvp.head;
return;
}
v = gdvp.wagon;
switch (mode) {
case 0: { // start dragging of vehicle
VehicleID sel = WP(w, traindepot_d).sel;
if (sel != INVALID_VEHICLE) {
WP(w,traindepot_d).sel = INVALID_VEHICLE;
TrainDepotMoveVehicle(v, sel, gdvp.head);
} else if (v != NULL) {
WP(w,traindepot_d).sel = v->index;
SetObjectToPlaceWnd(GetVehiclePalette(v) | GetTrainImage(v, DIR_W), 4, w);
SetWindowDirty(w);
}
break;
}
case -1: // show info window
ShowTrainViewWindow(v);
break;
case -2: // click start/stop flag
DoCommandP(v->tile, v->index, 0, NULL, CMD_START_STOP_TRAIN | CMD_MSG(STR_883B_CAN_T_STOP_START_TRAIN));
break;
}
}
/**
* Clones a train
* @param *v is the original vehicle to clone
* @param *w is the window of the depot where the clone is build
*/
static void HandleCloneVehClick(const Vehicle *v, const Window *w)
{
if (v == NULL || v->type != VEH_Train) return;
// for train vehicles: subtype 0 for locs and not zero for others
if (!IsFrontEngine(v)) {
v = GetFirstVehicleInChain(v);
// Do nothing when clicking on a train in depot with no loc attached
if (!IsFrontEngine(v)) return;
}
DoCommandP(w->window_number, v->index, _ctrl_pressed ? 1 : 0, CcCloneTrain,
CMD_CLONE_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE)
);
ResetObjectToPlace();
}
static void ClonePlaceObj(const Window *w)
{
Vehicle *v = CheckMouseOverVehicle();
if (v != NULL) HandleCloneVehClick(v, w);
}
static void TrainDepotWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_CREATE:
WP(w, traindepot_d).vehicle_list = NULL;
WP(w, traindepot_d).wagon_list = NULL;
WP(w, traindepot_d).engine_count = 0;
WP(w, traindepot_d).wagon_count = 0;
break;
case WE_PAINT:
BuildDepotVehicleList(VEH_Train, w->window_number, &WP(w, traindepot_d).vehicle_list, &WP(w, traindepot_d).engine_list_length, &WP(w, traindepot_d).engine_count,
&WP(w, traindepot_d).wagon_list, &WP(w, traindepot_d).wagon_list_length, &WP(w, traindepot_d).wagon_count);
DrawTrainDepotWindow(w);
break;
case WE_CLICK: {
switch (e->we.click.widget) {
case 8:
ResetObjectToPlace();
ShowBuildTrainWindow(w->window_number);
break;
case 10: ScrollMainWindowToTile(w->window_number); break;
case 6:
TrainDepotClickTrain(w, e->we.click.pt.x, e->we.click.pt.y);
break;
case 9: /* clone button */
InvalidateWidget(w, 9);
TOGGLEBIT(w->click_state, 9);
if (HASBIT(w->click_state, 9)) {
_place_clicked_vehicle = NULL;
SetObjectToPlaceWnd(SPR_CURSOR_CLONE, VHM_RECT, w);
} else {
ResetObjectToPlace();
}
break;
}
} break;
case WE_PLACE_OBJ:
ClonePlaceObj(w);
break;
case WE_ABORT_PLACE_OBJ:
CLRBIT(w->click_state, 9);
InvalidateWidget(w, 9);
break;
// check if a vehicle in a depot was clicked..
case WE_MOUSELOOP: {
const Vehicle *v = _place_clicked_vehicle;
// since OTTD checks all open depot windows, we will make sure that it triggers the one with a clicked clone button
if (v != NULL && HASBIT(w->click_state, 9)) {
_place_clicked_vehicle = NULL;
HandleCloneVehClick(v, w);
}
} break;
case WE_DESTROY:
DeleteWindowById(WC_BUILD_VEHICLE, w->window_number);
free((void*)WP(w, traindepot_d).vehicle_list);
free((void*)WP(w, traindepot_d).wagon_list);
break;
case WE_DRAGDROP: {
switch (e->we.click.widget) {
case 4: case 5: {
Vehicle *v;
int sell_cmd;
/* sell vehicle */
if (w->disabled_state & (1 << e->we.click.widget))
return;
if (WP(w,traindepot_d).sel == INVALID_VEHICLE)
return;
v = GetVehicle(WP(w,traindepot_d).sel);
WP(w,traindepot_d).sel = INVALID_VEHICLE;
SetWindowDirty(w);
HandleButtonClick(w, e->we.click.widget);
sell_cmd = (e->we.click.widget == 5 || _ctrl_pressed) ? 1 : 0;
if (!IsFrontEngine(v)) {
DoCommandP(v->tile, v->index, sell_cmd, NULL, CMD_SELL_RAIL_WAGON | CMD_MSG(STR_8839_CAN_T_SELL_RAILROAD_VEHICLE));
} else {
_backup_orders_tile = v->tile;
BackupVehicleOrders(v, _backup_orders_data);
if (!DoCommandP(v->tile, v->index, sell_cmd, NULL, CMD_SELL_RAIL_WAGON | CMD_MSG(STR_8839_CAN_T_SELL_RAILROAD_VEHICLE)))
_backup_orders_tile = 0;
}
} break;
case 6: {
GetDepotVehiclePtData gdvp;
VehicleID sel = WP(w,traindepot_d).sel;
WP(w,traindepot_d).sel = INVALID_VEHICLE;
SetWindowDirty(w);
if (GetVehicleFromTrainDepotWndPt(w, e->we.dragdrop.pt.x, e->we.dragdrop.pt.y, &gdvp) == 0 &&
sel != INVALID_VEHICLE) {
if (gdvp.wagon != NULL && gdvp.wagon->index == sel && _ctrl_pressed) {
DoCommandP(GetVehicle(sel)->tile, GetVehicle(sel)->index, true, NULL, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_9033_CAN_T_MAKE_VEHICLE_TURN));
} else if (gdvp.wagon == NULL || gdvp.wagon->index != sel) {
TrainDepotMoveVehicle(gdvp.wagon, sel, gdvp.head);
} else if (gdvp.head != NULL && IsFrontEngine(gdvp.head)) {
ShowTrainViewWindow(gdvp.head);
}
}
} break;
default:
WP(w,traindepot_d).sel = INVALID_VEHICLE;
SetWindowDirty(w);
break;
}
} break;
case WE_RESIZE: {
/* Update the scroll + matrix */
w->vscroll.cap += e->we.sizing.diff.y / 14;
w->hscroll.cap += e->we.sizing.diff.x;
w->widget[6].data = (w->vscroll.cap << 8) + 1;
} break;
}
}
static const Widget _train_depot_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_RIGHT, 14, 11, 348, 0, 13, STR_8800_TRAIN_DEPOT, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_STICKYBOX, RESIZE_LR, 14, 349, 360, 0, 13, 0x0, STR_STICKY_BUTTON},
{ WWT_PANEL, RESIZE_LRB, 14, 326, 348, 14, 13, 0x0, STR_NULL},
{ WWT_PANEL, RESIZE_LRTB, 14, 326, 348, 14, 54, 0x2A9, STR_8841_DRAG_TRAIN_VEHICLE_TO_HERE},
{ WWT_PANEL, RESIZE_LRTB, 14, 326, 348, 55, 109, 0x2BF, STR_DRAG_WHOLE_TRAIN_TO_SELL_TIP},
{ WWT_MATRIX, RESIZE_RB, 14, 0, 325, 14, 97, 0x601, STR_883F_TRAINS_CLICK_ON_TRAIN_FOR},
{ WWT_SCROLLBAR, RESIZE_LRB, 14, 349, 360, 14, 109, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 116, 110, 121, STR_8815_NEW_VEHICLES, STR_8840_BUILD_NEW_TRAIN_VEHICLE},
{WWT_NODISTXTBTN, RESIZE_TB, 14, 117, 232, 110, 121, STR_CLONE_TRAIN, STR_CLONE_TRAIN_DEPOT_INFO},
{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 233, 348, 110, 121, STR_00E4_LOCATION, STR_8842_CENTER_MAIN_VIEW_ON_TRAIN},
{ WWT_HSCROLLBAR, RESIZE_RTB, 14, 0, 325, 98, 109, 0x0, STR_HSCROLL_BAR_SCROLLS_LIST},
{ WWT_PANEL, RESIZE_RTB, 14, 349, 348, 110, 121, 0x0, STR_NULL},
{ WWT_RESIZEBOX, RESIZE_LRTB, 14, 349, 360, 110, 121, 0x0, STR_RESIZE_BUTTON},
{ WIDGETS_END},
};
static const WindowDesc _train_depot_desc = {
-1, -1, 361, 122,
WC_VEHICLE_DEPOT,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_train_depot_widgets,
TrainDepotWndProc
};
void ShowTrainDepotWindow(TileIndex tile)
{
Window *w;
w = AllocateWindowDescFront(&_train_depot_desc, tile);
if (w) {
w->caption_color = GetTileOwner(w->window_number);
w->vscroll.cap = 6;
w->hscroll.cap = 10 * 29;
w->resize.step_width = 1;
w->resize.step_height = 14;
WP(w,traindepot_d).sel = INVALID_VEHICLE;
_backup_orders_tile = 0;
}
}
static void RailVehicleRefitWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {