00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "gui.h"
00008 #include "window_gui.h"
00009 #include "textbuf_gui.h"
00010 #include "command_func.h"
00011 #include "engine.h"
00012 #include "vehicle_gui.h"
00013 #include "depot.h"
00014 #include "train.h"
00015 #include "group.h"
00016 #include "debug.h"
00017 #include "strings_func.h"
00018 #include "core/alloc_func.hpp"
00019 #include "window_func.h"
00020 #include "vehicle_func.h"
00021 #include "autoreplace_gui.h"
00022 #include "string_func.h"
00023 #include "viewport_func.h"
00024 #include "gfx_func.h"
00025 #include "player_func.h"
00026 #include "widgets/dropdown_type.h"
00027 #include "widgets/dropdown_func.h"
00028
00029 #include "table/strings.h"
00030 #include "table/sprites.h"
00031
00032 struct Sorting {
00033 Listing aircraft;
00034 Listing roadveh;
00035 Listing ship;
00036 Listing train;
00037 };
00038
00039 static Sorting _sorting;
00040
00041
00042 static void BuildGroupList(grouplist_d* gl, PlayerID owner, VehicleType vehicle_type)
00043 {
00044 const Group** list;
00045 const Group *g;
00046 uint n = 0;
00047
00048 if (!(gl->l.flags & VL_REBUILD)) return;
00049
00050 list = MallocT<const Group*>(GetGroupArraySize());
00051
00052 FOR_ALL_GROUPS(g) {
00053 if (g->owner == owner && g->vehicle_type == vehicle_type) list[n++] = g;
00054 }
00055
00056 free((void*)gl->sort_list);
00057 gl->sort_list = MallocT<const Group *>(n);
00058 gl->l.list_length = n;
00059
00060 for (uint i = 0; i < n; ++i) gl->sort_list[i] = list[i];
00061 free((void*)list);
00062
00063 gl->l.flags &= ~VL_REBUILD;
00064 gl->l.flags |= VL_RESORT;
00065 }
00066
00067
00068 static int CDECL GroupNameSorter(const void *a, const void *b)
00069 {
00070 static const Group *last_group[2] = { NULL, NULL };
00071 static char last_name[2][64] = { "", "" };
00072
00073 const Group *ga = *(const Group**)a;
00074 const Group *gb = *(const Group**)b;
00075 int r;
00076
00077 if (ga != last_group[0]) {
00078 last_group[0] = ga;
00079 SetDParam(0, ga->index);
00080 GetString(last_name[0], STR_GROUP_NAME, lastof(last_name[0]));
00081 }
00082
00083 if (gb != last_group[1]) {
00084 last_group[1] = gb;
00085 SetDParam(0, gb->index);
00086 GetString(last_name[1], STR_GROUP_NAME, lastof(last_name[1]));
00087 }
00088
00089 r = strcmp(last_name[0], last_name[1]);
00090
00091 if (r == 0) return ga->index - gb->index;
00092
00093 return r;
00094 }
00095
00096
00097 static void SortGroupList(grouplist_d *gl)
00098 {
00099 if (!(gl->l.flags & VL_RESORT)) return;
00100
00101 qsort((void*)gl->sort_list, gl->l.list_length, sizeof(gl->sort_list[0]), GroupNameSorter);
00102
00103 gl->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
00104 gl->l.flags &= ~VL_RESORT;
00105 }
00106
00107
00108 enum GroupListWidgets {
00109 GRP_WIDGET_CLOSEBOX = 0,
00110 GRP_WIDGET_CAPTION,
00111 GRP_WIDGET_STICKY,
00112 GRP_WIDGET_EMPTY_TOP_LEFT,
00113 GRP_WIDGET_ALL_VEHICLES,
00114 GRP_WIDGET_DEFAULT_VEHICLES,
00115 GRP_WIDGET_LIST_GROUP,
00116 GRP_WIDGET_LIST_GROUP_SCROLLBAR,
00117 GRP_WIDGET_SORT_BY_ORDER,
00118 GRP_WIDGET_SORT_BY_DROPDOWN,
00119 GRP_WIDGET_EMPTY_TOP_RIGHT,
00120 GRP_WIDGET_LIST_VEHICLE,
00121 GRP_WIDGET_LIST_VEHICLE_SCROLLBAR,
00122 GRP_WIDGET_CREATE_GROUP,
00123 GRP_WIDGET_DELETE_GROUP,
00124 GRP_WIDGET_RENAME_GROUP,
00125 GRP_WIDGET_EMPTY1,
00126 GRP_WIDGET_REPLACE_PROTECTION,
00127 GRP_WIDGET_EMPTY2,
00128 GRP_WIDGET_AVAILABLE_VEHICLES,
00129 GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN,
00130 GRP_WIDGET_STOP_ALL,
00131 GRP_WIDGET_START_ALL,
00132 GRP_WIDGET_EMPTY_BOTTOM_RIGHT,
00133 GRP_WIDGET_RESIZE,
00134 };
00135
00136
00137 static const Widget _group_widgets[] = {
00138 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00139 { WWT_CAPTION, RESIZE_RIGHT, 14, 11, 447, 0, 13, 0x0, STR_018C_WINDOW_TITLE_DRAG_THIS},
00140 { WWT_STICKYBOX, RESIZE_LR, 14, 448, 459, 0, 13, 0x0, STR_STICKY_BUTTON},
00141 { WWT_PANEL, RESIZE_NONE, 14, 0, 200, 14, 25, 0x0, STR_NULL},
00142 { WWT_PANEL, RESIZE_NONE, 14, 0, 200, 26, 38, 0x0, STR_NULL},
00143 { WWT_PANEL, RESIZE_NONE, 14, 0, 200, 39, 51, 0x0, STR_NULL},
00144 { WWT_MATRIX, RESIZE_BOTTOM, 14, 0, 188, 52, 168, 0x701, STR_GROUPS_CLICK_ON_GROUP_FOR_TIP},
00145 { WWT_SCROLLBAR, RESIZE_BOTTOM, 14, 189, 200, 52, 168, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00146 { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 201, 281, 14, 25, STR_SORT_BY, STR_SORT_ORDER_TIP},
00147 { WWT_DROPDOWN, RESIZE_NONE, 14, 282, 447, 14, 25, 0x0, STR_SORT_CRITERIA_TIP},
00148 { WWT_PANEL, RESIZE_RIGHT, 14, 448, 459, 14, 25, 0x0, STR_NULL},
00149 { WWT_MATRIX, RESIZE_RB, 14, 201, 447, 26, 181, 0x701, STR_NULL},
00150 { WWT_SCROLL2BAR, RESIZE_LRB, 14, 448, 459, 26, 181, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00151 { WWT_PUSHIMGBTN, RESIZE_TB, 14, 0, 23, 169, 193, 0x0, STR_GROUP_CREATE_TIP},
00152 { WWT_PUSHIMGBTN, RESIZE_TB, 14, 24, 47, 169, 193, 0x0, STR_GROUP_DELETE_TIP},
00153 { WWT_PUSHIMGBTN, RESIZE_TB, 14, 48, 71, 169, 193, 0x0, STR_GROUP_RENAME_TIP},
00154 { WWT_PANEL, RESIZE_TB, 14, 72, 164, 169, 193, 0x0, STR_NULL},
00155 { WWT_PUSHIMGBTN, RESIZE_TB, 14, 165, 188, 169, 193, 0x0, STR_GROUP_REPLACE_PROTECTION_TIP},
00156 { WWT_PANEL, RESIZE_TB, 14, 189, 200, 169, 193, 0x0, STR_NULL},
00157 { WWT_PUSHTXTBTN, RESIZE_TB, 14, 201, 306, 182, 193, 0x0, STR_AVAILABLE_ENGINES_TIP},
00158 { WWT_DROPDOWN, RESIZE_TB, 14, 307, 423, 182, 193, STR_MANAGE_LIST, STR_MANAGE_LIST_TIP},
00159 { WWT_PUSHIMGBTN, RESIZE_TB, 14, 424, 435, 182, 193, SPR_FLAG_VEH_STOPPED, STR_MASS_STOP_LIST_TIP},
00160 { WWT_PUSHIMGBTN, RESIZE_TB, 14, 436, 447, 182, 193, SPR_FLAG_VEH_RUNNING, STR_MASS_START_LIST_TIP},
00161 { WWT_PANEL, RESIZE_RTB, 14, 448, 447, 182, 193, 0x0, STR_NULL},
00162 { WWT_RESIZEBOX, RESIZE_LRTB, 14, 448, 459, 182, 193, 0x0, STR_RESIZE_BUTTON},
00163 { WIDGETS_END},
00164 };
00165
00166
00167 static void CreateVehicleGroupWindow(Window *w)
00168 {
00169 const PlayerID owner = (PlayerID)GB(w->window_number, 0, 8);
00170 groupveh_d *gv = &WP(w, groupveh_d);
00171 grouplist_d *gl = &WP(w, groupveh_d).gl;
00172
00173 w->caption_color = owner;
00174 w->hscroll.cap = 224;
00175 w->resize.step_width = 1;
00176
00177 switch (gv->vehicle_type) {
00178 default: NOT_REACHED();
00179 case VEH_TRAIN:
00180 case VEH_ROAD:
00181 w->vscroll.cap = 9;
00182 w->vscroll2.cap = 6;
00183 w->resize.step_height = PLY_WND_PRC__SIZE_OF_ROW_SMALL;
00184 break;
00185 case VEH_SHIP:
00186 case VEH_AIRCRAFT:
00187 w->vscroll.cap = 9;
00188 w->vscroll2.cap = 4;
00189 w->resize.step_height = PLY_WND_PRC__SIZE_OF_ROW_BIG2;
00190 break;
00191 }
00192
00193 w->widget[GRP_WIDGET_LIST_GROUP].data = (w->vscroll.cap << 8) + 1;
00194 w->widget[GRP_WIDGET_LIST_VEHICLE].data = (w->vscroll2.cap << 8) + 1;
00195
00196 switch (gv->vehicle_type) {
00197 default: NOT_REACHED(); break;
00198 case VEH_TRAIN: gv->_sorting = &_sorting.train; break;
00199 case VEH_ROAD: gv->_sorting = &_sorting.roadveh; break;
00200 case VEH_SHIP: gv->_sorting = &_sorting.ship; break;
00201 case VEH_AIRCRAFT: gv->_sorting = &_sorting.aircraft; break;
00202 }
00203
00204 gv->sort_list = NULL;
00205 gv->vehicle_type = (VehicleType)GB(w->window_number, 11, 5);
00206 gv->l.sort_type = gv->_sorting->criteria;
00207 gv->l.flags = VL_REBUILD | (gv->_sorting->order ? VL_DESC : VL_NONE);
00208 gv->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
00209
00210 gl->sort_list = NULL;
00211 gl->l.flags = VL_REBUILD | VL_NONE;
00212 gl->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
00213
00214 gv->group_sel = ALL_GROUP;
00215 gv->vehicle_sel = INVALID_VEHICLE;
00216
00217 switch (gv->vehicle_type) {
00218 case VEH_TRAIN:
00219 w->widget[GRP_WIDGET_LIST_VEHICLE].tooltips = STR_883D_TRAINS_CLICK_ON_TRAIN_FOR;
00220 w->widget[GRP_WIDGET_AVAILABLE_VEHICLES].data = STR_AVAILABLE_TRAINS;
00221
00222 w->widget[GRP_WIDGET_CREATE_GROUP].data = SPR_GROUP_CREATE_TRAIN;
00223 w->widget[GRP_WIDGET_RENAME_GROUP].data = SPR_GROUP_RENAME_TRAIN;
00224 w->widget[GRP_WIDGET_DELETE_GROUP].data = SPR_GROUP_DELETE_TRAIN;
00225 break;
00226
00227 case VEH_ROAD:
00228 w->widget[GRP_WIDGET_LIST_VEHICLE].tooltips = STR_901A_ROAD_VEHICLES_CLICK_ON;
00229 w->widget[GRP_WIDGET_AVAILABLE_VEHICLES].data = STR_AVAILABLE_ROAD_VEHICLES;
00230
00231 w->widget[GRP_WIDGET_CREATE_GROUP].data = SPR_GROUP_CREATE_ROADVEH;
00232 w->widget[GRP_WIDGET_RENAME_GROUP].data = SPR_GROUP_RENAME_ROADVEH;
00233 w->widget[GRP_WIDGET_DELETE_GROUP].data = SPR_GROUP_DELETE_ROADVEH;
00234 break;
00235
00236 case VEH_SHIP:
00237 w->widget[GRP_WIDGET_LIST_VEHICLE].tooltips = STR_9823_SHIPS_CLICK_ON_SHIP_FOR;
00238 w->widget[GRP_WIDGET_AVAILABLE_VEHICLES].data = STR_AVAILABLE_SHIPS;
00239
00240 w->widget[GRP_WIDGET_CREATE_GROUP].data = SPR_GROUP_CREATE_SHIP;
00241 w->widget[GRP_WIDGET_RENAME_GROUP].data = SPR_GROUP_RENAME_SHIP;
00242 w->widget[GRP_WIDGET_DELETE_GROUP].data = SPR_GROUP_DELETE_SHIP;
00243 break;
00244
00245 case VEH_AIRCRAFT:
00246 w->widget[GRP_WIDGET_LIST_VEHICLE].tooltips = STR_A01F_AIRCRAFT_CLICK_ON_AIRCRAFT;
00247 w->widget[GRP_WIDGET_AVAILABLE_VEHICLES].data = STR_AVAILABLE_AIRCRAFT;
00248
00249 w->widget[GRP_WIDGET_CREATE_GROUP].data = SPR_GROUP_CREATE_AIRCRAFT;
00250 w->widget[GRP_WIDGET_RENAME_GROUP].data = SPR_GROUP_RENAME_AIRCRAFT;
00251 w->widget[GRP_WIDGET_DELETE_GROUP].data = SPR_GROUP_DELETE_AIRCRAFT;
00252 break;
00253
00254 default: NOT_REACHED();
00255 }
00256 }
00257
00258 enum GroupActionListFunction {
00259 GALF_REPLACE,
00260 GALF_SERVICE,
00261 GALF_DEPOT,
00262 GALF_ADD_SHARED,
00263 GALF_REMOVE_ALL,
00264 };
00265
00271 static void ShowGroupActionDropdown(Window *w, GroupID gid)
00272 {
00273 DropDownList *list = new DropDownList();
00274
00275 list->push_back(new DropDownListStringItem(STR_REPLACE_VEHICLES, GALF_REPLACE, false));
00276 list->push_back(new DropDownListStringItem(STR_SEND_FOR_SERVICING, GALF_SERVICE, false));
00277 list->push_back(new DropDownListStringItem(STR_SEND_TRAIN_TO_DEPOT, GALF_DEPOT, false));
00278
00279 if (IsValidGroupID(gid)) {
00280 list->push_back(new DropDownListStringItem(STR_GROUP_ADD_SHARED_VEHICLE, GALF_ADD_SHARED, false));
00281 list->push_back(new DropDownListStringItem(STR_GROUP_REMOVE_ALL_VEHICLES, GALF_REMOVE_ALL, false));
00282 }
00283
00284 ShowDropDownList(w, list, 0, GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN);
00285 }
00286
00292 static void GroupWndProc(Window *w, WindowEvent *e)
00293 {
00294 const PlayerID owner = (PlayerID)GB(w->window_number, 0, 8);
00295 groupveh_d *gv = &WP(w, groupveh_d);
00296 grouplist_d *gl = &WP(w, groupveh_d).gl;
00297
00298 gv->vehicle_type = (VehicleType)GB(w->window_number, 11, 5);
00299
00300 switch(e->event) {
00301 case WE_INVALIDATE_DATA:
00302 gv->l.flags |= VL_REBUILD;
00303 gl->l.flags |= VL_REBUILD;
00304 if (!(IsAllGroupID(gv->group_sel) || IsDefaultGroupID(gv->group_sel) || IsValidGroupID(gv->group_sel))) {
00305 gv->group_sel = ALL_GROUP;
00306 HideDropDownMenu(w);
00307 }
00308 SetWindowDirty(w);
00309 break;
00310
00311 case WE_CREATE:
00312 CreateVehicleGroupWindow(w);
00313 break;
00314
00315 case WE_PAINT: {
00316 int x = 203;
00317 int y2 = PLY_WND_PRC__OFFSET_TOP_WIDGET;
00318 int y1 = PLY_WND_PRC__OFFSET_TOP_WIDGET + 2;
00319 int max;
00320 int i;
00321
00322
00323
00324 BuildVehicleList(gv, owner, gv->group_sel, IsAllGroupID(gv->group_sel) ? VLW_STANDARD : VLW_GROUP_LIST);
00325 SortVehicleList(gv);
00326
00327
00328 BuildGroupList(gl, owner, gv->vehicle_type);
00329 SortGroupList(gl);
00330
00331 SetVScrollCount(w, gl->l.list_length);
00332 SetVScroll2Count(w, gv->l.list_length);
00333
00334
00335 if (gv->l.list_length == 0 && w->IsWidgetLowered(GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN)) {
00336 w->RaiseWidget(GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN);
00337 HideDropDownMenu(w);
00338 }
00339
00340
00341 w->SetWidgetsDisabledState(gv->l.list_length == 0 || _local_player != owner,
00342 GRP_WIDGET_STOP_ALL,
00343 GRP_WIDGET_START_ALL,
00344 GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN,
00345 WIDGET_LIST_END);
00346
00347
00348 w->SetWidgetsDisabledState(IsDefaultGroupID(gv->group_sel) || IsAllGroupID(gv->group_sel) || _local_player != owner,
00349 GRP_WIDGET_DELETE_GROUP,
00350 GRP_WIDGET_RENAME_GROUP,
00351 GRP_WIDGET_REPLACE_PROTECTION,
00352 WIDGET_LIST_END);
00353
00354
00355
00356
00357
00358
00359
00360 w->SetWidgetsDisabledState(_local_player != owner,
00361 GRP_WIDGET_CREATE_GROUP,
00362 GRP_WIDGET_AVAILABLE_VEHICLES,
00363 WIDGET_LIST_END);
00364
00365
00366
00367
00368 if (IsDefaultGroupID(gv->group_sel) || IsAllGroupID(gv->group_sel)) {
00369 SetDParam(0, owner);
00370 SetDParam(1, gv->l.list_length);
00371
00372 switch (gv->vehicle_type) {
00373 case VEH_TRAIN:
00374 w->widget[GRP_WIDGET_CAPTION].data = STR_881B_TRAINS;
00375 w->widget[GRP_WIDGET_REPLACE_PROTECTION].data = SPR_GROUP_REPLACE_OFF_TRAIN;
00376 break;
00377 case VEH_ROAD:
00378 w->widget[GRP_WIDGET_CAPTION].data = STR_9001_ROAD_VEHICLES;
00379 w->widget[GRP_WIDGET_REPLACE_PROTECTION].data = SPR_GROUP_REPLACE_OFF_ROADVEH;
00380 break;
00381 case VEH_SHIP:
00382 w->widget[GRP_WIDGET_CAPTION].data = STR_9805_SHIPS;
00383 w->widget[GRP_WIDGET_REPLACE_PROTECTION].data = SPR_GROUP_REPLACE_OFF_SHIP;
00384 break;
00385 case VEH_AIRCRAFT:
00386 w->widget[GRP_WIDGET_CAPTION].data = STR_A009_AIRCRAFT;
00387 w->widget[GRP_WIDGET_REPLACE_PROTECTION].data = SPR_GROUP_REPLACE_OFF_AIRCRAFT;
00388 break;
00389 default: NOT_REACHED(); break;
00390 }
00391 } else {
00392 const Group *g = GetGroup(gv->group_sel);
00393
00394 SetDParam(0, g->index);
00395 SetDParam(1, g->num_vehicle);
00396
00397 switch (gv->vehicle_type) {
00398 case VEH_TRAIN:
00399 w->widget[GRP_WIDGET_CAPTION].data = STR_GROUP_TRAINS_CAPTION;
00400 w->widget[GRP_WIDGET_REPLACE_PROTECTION].data = (g->replace_protection) ? SPR_GROUP_REPLACE_ON_TRAIN : SPR_GROUP_REPLACE_OFF_TRAIN;
00401 break;
00402 case VEH_ROAD:
00403 w->widget[GRP_WIDGET_CAPTION].data = STR_GROUP_ROADVEH_CAPTION;
00404 w->widget[GRP_WIDGET_REPLACE_PROTECTION].data = (g->replace_protection) ? SPR_GROUP_REPLACE_ON_ROADVEH : SPR_GROUP_REPLACE_OFF_ROADVEH;
00405 break;
00406 case VEH_SHIP:
00407 w->widget[GRP_WIDGET_CAPTION].data = STR_GROUP_SHIPS_CAPTION;
00408 w->widget[GRP_WIDGET_REPLACE_PROTECTION].data = (g->replace_protection) ? SPR_GROUP_REPLACE_ON_SHIP : SPR_GROUP_REPLACE_OFF_SHIP;
00409 break;
00410 case VEH_AIRCRAFT:
00411 w->widget[GRP_WIDGET_CAPTION].data = STR_GROUP_AIRCRAFTS_CAPTION;
00412 w->widget[GRP_WIDGET_REPLACE_PROTECTION].data = (g->replace_protection) ? SPR_GROUP_REPLACE_ON_AIRCRAFT : SPR_GROUP_REPLACE_OFF_AIRCRAFT;
00413 break;
00414 default: NOT_REACHED(); break;
00415 }
00416 }
00417
00418
00419 w->widget[GRP_WIDGET_SORT_BY_DROPDOWN].data = _vehicle_sort_listing[gv->l.sort_type];
00420
00421 DrawWindowWidgets(w);
00422
00423
00424
00425 StringID str_all_veh, str_no_group_veh;
00426
00427 switch (gv->vehicle_type) {
00428 case VEH_TRAIN:
00429 str_all_veh = STR_GROUP_ALL_TRAINS;
00430 str_no_group_veh = STR_GROUP_DEFAULT_TRAINS;
00431 break;
00432 case VEH_ROAD:
00433 str_all_veh = STR_GROUP_ALL_ROADS;
00434 str_no_group_veh = STR_GROUP_DEFAULT_ROADS;
00435 break;
00436 case VEH_SHIP:
00437 str_all_veh = STR_GROUP_ALL_SHIPS;
00438 str_no_group_veh = STR_GROUP_DEFAULT_SHIPS;
00439 break;
00440 case VEH_AIRCRAFT:
00441 str_all_veh = STR_GROUP_ALL_AIRCRAFTS;
00442 str_no_group_veh = STR_GROUP_DEFAULT_AIRCRAFTS;
00443 break;
00444 default: NOT_REACHED(); break;
00445 }
00446 DrawString(10, y1, str_all_veh, IsAllGroupID(gv->group_sel) ? TC_WHITE : TC_BLACK);
00447
00448 y1 += 13;
00449
00450 DrawString(10, y1, str_no_group_veh, IsDefaultGroupID(gv->group_sel) ? TC_WHITE : TC_BLACK);
00451
00452 max = min(w->vscroll.pos + w->vscroll.cap, gl->l.list_length);
00453 for (i = w->vscroll.pos ; i < max ; ++i) {
00454 const Group *g = gl->sort_list[i];
00455
00456 assert(g->owner == owner);
00457
00458 y1 += PLY_WND_PRC__SIZE_OF_ROW_TINY;
00459
00460
00461 SetDParam(0, g->index);
00462 DrawString(10, y1, STR_GROUP_NAME, (gv->group_sel == g->index) ? TC_WHITE : TC_BLACK);
00463
00464
00465 SetDParam(0, g->num_vehicle);
00466 DrawStringRightAligned(187, y1 + 1, STR_GROUP_TINY_NUM, (gv->group_sel == g->index) ? TC_WHITE : TC_BLACK);
00467 }
00468
00469 DrawSortButtonState(w, GRP_WIDGET_SORT_BY_ORDER, gv->l.flags & VL_DESC ? SBS_DOWN : SBS_UP);
00470
00471
00472 max = min(w->vscroll2.pos + w->vscroll2.cap, gv->l.list_length);
00473 for (i = w->vscroll2.pos ; i < max ; ++i) {
00474 const Vehicle* v = gv->sort_list[i];
00475
00476 assert(v->type == gv->vehicle_type && v->owner == owner);
00477
00478 DrawVehicleImage(v, x + 19, y2 + 6, gv->vehicle_sel, w->hscroll.cap, 0);
00479 DrawVehicleProfitButton(v, x, y2 + 13);
00480
00481 SetDParam(0, v->unitnumber);
00482 DrawString(x, y2 + 2, v->IsInDepot() ? STR_021F : (v->age > v->max_age - 366 ? STR_00E3 : STR_00E2), TC_FROMSTRING);
00483
00484 if (w->resize.step_height == PLY_WND_PRC__SIZE_OF_ROW_BIG2) DrawSmallOrderList(v, x + 138, y2);
00485
00486 SetDParam(0, v->GetDisplayProfitThisYear());
00487 SetDParam(1, v->GetDisplayProfitLastYear());
00488 DrawString(x + 19, y2 + w->resize.step_height - 8, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, TC_FROMSTRING);
00489
00490 if (IsValidGroupID(v->group_id)) {
00491 SetDParam(0, v->group_id);
00492 DrawString(x + 19, y2, STR_GROUP_TINY_NAME, TC_BLACK);
00493 }
00494
00495 y2 += w->resize.step_height;
00496 }
00497
00498 break;
00499 }
00500
00501 case WE_CLICK:
00502 if (e->we.click.widget != GRP_WIDGET_SORT_BY_DROPDOWN && e->we.click.widget != GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN) HideDropDownMenu(w);
00503
00504 switch(e->we.click.widget) {
00505 case GRP_WIDGET_SORT_BY_ORDER:
00506 gv->l.flags ^= VL_DESC;
00507 gv->l.flags |= VL_RESORT;
00508
00509 gv->_sorting->order = !!(gv->l.flags & VL_DESC);
00510 SetWindowDirty(w);
00511 break;
00512
00513 case GRP_WIDGET_SORT_BY_DROPDOWN:
00514 ShowDropDownMenu(w, _vehicle_sort_listing, gv->l.sort_type, GRP_WIDGET_SORT_BY_DROPDOWN, 0, 0);
00515 return;
00516
00517 case GRP_WIDGET_ALL_VEHICLES:
00518 if (!IsAllGroupID(gv->group_sel)) {
00519 gv->group_sel = ALL_GROUP;
00520 gv->l.flags |= VL_REBUILD;
00521 SetWindowDirty(w);
00522 }
00523 break;
00524
00525 case GRP_WIDGET_DEFAULT_VEHICLES:
00526 if (!IsDefaultGroupID(gv->group_sel)) {
00527 gv->group_sel = DEFAULT_GROUP;
00528 gv->l.flags |= VL_REBUILD;
00529 SetWindowDirty(w);
00530 }
00531 break;
00532
00533 case GRP_WIDGET_LIST_GROUP: {
00534 uint16 id_g = (e->we.click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET - 26) / PLY_WND_PRC__SIZE_OF_ROW_TINY;
00535
00536 if (id_g >= w->vscroll.cap) return;
00537
00538 id_g += w->vscroll.pos;
00539
00540 if (id_g >= gl->l.list_length) return;
00541
00542 gv->group_sel = gl->sort_list[id_g]->index;;
00543
00544 gv->l.flags |= VL_REBUILD;
00545 SetWindowDirty(w);
00546 break;
00547 }
00548
00549 case GRP_WIDGET_LIST_VEHICLE: {
00550 uint32 id_v = (e->we.click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / (int)w->resize.step_height;
00551 const Vehicle *v;
00552
00553 if (id_v >= w->vscroll2.cap) return;
00554
00555 id_v += w->vscroll2.pos;
00556
00557 if (id_v >= gv->l.list_length) return;
00558
00559 v = gv->sort_list[id_v];
00560
00561 gv->vehicle_sel = v->index;
00562
00563 if (v->IsValid()) {
00564 SetObjectToPlaceWnd(v->GetImage(DIR_W), GetVehiclePalette(v), VHM_DRAG, w);
00565 }
00566
00567 SetWindowDirty(w);
00568 break;
00569 }
00570
00571 case GRP_WIDGET_CREATE_GROUP:
00572 DoCommandP(0, gv->vehicle_type, 0, NULL, CMD_CREATE_GROUP | CMD_MSG(STR_GROUP_CAN_T_CREATE));
00573 break;
00574
00575 case GRP_WIDGET_DELETE_GROUP: {
00576 GroupID group = gv->group_sel;
00577 gv->group_sel = ALL_GROUP;
00578
00579 DoCommandP(0, group, 0, NULL, CMD_DELETE_GROUP | CMD_MSG(STR_GROUP_CAN_T_DELETE));
00580 break;
00581 }
00582
00583 case GRP_WIDGET_RENAME_GROUP: {
00584 assert(IsValidGroupID(gv->group_sel));
00585
00586 const Group *g = GetGroup(gv->group_sel);
00587
00588 SetDParam(0, g->index);
00589 ShowQueryString(STR_GROUP_NAME, STR_GROUP_RENAME_CAPTION, 31, 150, w, CS_ALPHANUMERAL);
00590 } break;
00591
00592
00593 case GRP_WIDGET_AVAILABLE_VEHICLES:
00594 ShowBuildVehicleWindow(0, gv->vehicle_type);
00595 break;
00596
00597 case GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN:
00598 ShowGroupActionDropdown(w, gv->group_sel);
00599 break;
00600
00601 case GRP_WIDGET_START_ALL:
00602 case GRP_WIDGET_STOP_ALL: {
00603 DoCommandP(0, gv->group_sel, ((IsAllGroupID(gv->group_sel) ? VLW_STANDARD : VLW_GROUP_LIST) & VLW_MASK)
00604 | (1 << 6)
00605 | (e->we.click.widget == GRP_WIDGET_START_ALL ? (1 << 5) : 0)
00606 | gv->vehicle_type, NULL, CMD_MASS_START_STOP);
00607
00608 break;
00609 }
00610
00611 case GRP_WIDGET_REPLACE_PROTECTION:
00612 if (IsValidGroupID(gv->group_sel)) {
00613 const Group *g = GetGroup(gv->group_sel);
00614
00615 DoCommandP(0, gv->group_sel, !g->replace_protection, NULL, CMD_SET_GROUP_REPLACE_PROTECTION);
00616 }
00617 break;
00618 }
00619
00620 break;
00621
00622 case WE_DRAGDROP: {
00623 switch (e->we.click.widget) {
00624 case GRP_WIDGET_ALL_VEHICLES:
00625 case GRP_WIDGET_DEFAULT_VEHICLES:
00626 DoCommandP(0, DEFAULT_GROUP, gv->vehicle_sel, NULL, CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_GROUP_CAN_T_ADD_VEHICLE));
00627
00628 gv->vehicle_sel = INVALID_VEHICLE;
00629
00630 SetWindowDirty(w);
00631
00632 break;
00633
00634 case GRP_WIDGET_LIST_GROUP: {
00635 uint16 id_g = (e->we.click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET - 26) / PLY_WND_PRC__SIZE_OF_ROW_TINY;
00636 const VehicleID vindex = gv->vehicle_sel;
00637
00638 gv->vehicle_sel = INVALID_VEHICLE;
00639
00640 SetWindowDirty(w);
00641
00642 if (id_g >= w->vscroll.cap) return;
00643
00644 id_g += w->vscroll.pos;
00645
00646 if (id_g >= gl->l.list_length) return;
00647
00648 DoCommandP(0, gl->sort_list[id_g]->index, vindex, NULL, CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_GROUP_CAN_T_ADD_VEHICLE));
00649
00650 break;
00651 }
00652
00653 case GRP_WIDGET_LIST_VEHICLE: {
00654 uint32 id_v = (e->we.click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / (int)w->resize.step_height;
00655 const Vehicle *v;
00656 const VehicleID vindex = gv->vehicle_sel;
00657
00658 gv->vehicle_sel = INVALID_VEHICLE;
00659
00660 SetWindowDirty(w);
00661
00662 if (id_v >= w->vscroll2.cap) return;
00663
00664 id_v += w->vscroll2.pos;
00665
00666 if (id_v >= gv->l.list_length) return;
00667
00668 v = gv->sort_list[id_v];
00669
00670 if (vindex == v->index) {
00671 ShowVehicleViewWindow(v);
00672 }
00673
00674 break;
00675 }
00676 }
00677 break;
00678 }
00679
00680 case WE_ON_EDIT_TEXT:
00681 if (!StrEmpty(e->we.edittext.str)) {
00682 _cmd_text = e->we.edittext.str;
00683
00684 DoCommandP(0, gv->group_sel, 0, NULL, CMD_RENAME_GROUP | CMD_MSG(STR_GROUP_CAN_T_RENAME));
00685 }
00686 break;
00687
00688 case WE_RESIZE:
00689 w->hscroll.cap += e->we.sizing.diff.x;
00690 w->vscroll.cap += e->we.sizing.diff.y / PLY_WND_PRC__SIZE_OF_ROW_TINY;
00691 w->vscroll2.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
00692
00693 w->widget[GRP_WIDGET_LIST_GROUP].data = (w->vscroll.cap << 8) + 1;
00694 w->widget[GRP_WIDGET_LIST_VEHICLE].data = (w->vscroll2.cap << 8) + 1;
00695 break;
00696
00697
00698 case WE_DROPDOWN_SELECT:
00699 switch (e->we.dropdown.button) {
00700 case GRP_WIDGET_SORT_BY_DROPDOWN:
00701 if (gv->l.sort_type != e->we.dropdown.index) {
00702 gv->l.flags |= VL_RESORT;
00703 gv->l.sort_type = e->we.dropdown.index;
00704 gv->_sorting->criteria = gv->l.sort_type;
00705 }
00706 break;
00707
00708 case GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN:
00709 assert(gv->l.list_length != 0);
00710
00711 switch (e->we.dropdown.index) {
00712 case GALF_REPLACE:
00713 ShowReplaceGroupVehicleWindow(gv->group_sel, gv->vehicle_type);
00714 break;
00715 case GALF_SERVICE:
00716 DoCommandP(0, gv->group_sel, ((IsAllGroupID(gv->group_sel) ? VLW_STANDARD : VLW_GROUP_LIST) & VLW_MASK)
00717 | DEPOT_MASS_SEND
00718 | DEPOT_SERVICE, NULL, GetCmdSendToDepot(gv->vehicle_type));
00719 break;
00720 case GALF_DEPOT:
00721 DoCommandP(0, gv->group_sel, ((IsAllGroupID(gv->group_sel) ? VLW_STANDARD : VLW_GROUP_LIST) & VLW_MASK)
00722 | DEPOT_MASS_SEND, NULL, GetCmdSendToDepot(gv->vehicle_type));
00723 break;
00724 case GALF_ADD_SHARED:
00725 assert(IsValidGroupID(gv->group_sel));
00726
00727 DoCommandP(0, gv->group_sel, gv->vehicle_type, NULL, CMD_ADD_SHARED_VEHICLE_GROUP | CMD_MSG(STR_GROUP_CAN_T_ADD_SHARED_VEHICLE));
00728 break;
00729 case GALF_REMOVE_ALL:
00730 assert(IsValidGroupID(gv->group_sel));
00731
00732 DoCommandP(0, gv->group_sel, gv->vehicle_type, NULL, CMD_REMOVE_ALL_VEHICLES_GROUP | CMD_MSG(STR_GROUP_CAN_T_REMOVE_ALL_VEHICLES));
00733 break;
00734 default: NOT_REACHED();
00735 }
00736 break;
00737
00738 default: NOT_REACHED();
00739 }
00740
00741 SetWindowDirty(w);
00742 break;
00743
00744
00745 case WE_DESTROY:
00746 free((void*)gv->sort_list);
00747 free((void*)gl->sort_list);
00748 break;
00749
00750
00751 case WE_TICK:
00752 if (_pause_game != 0) break;
00753 if (--gv->l.resort_timer == 0) {
00754 gv->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
00755 gv->l.flags |= VL_RESORT;
00756 SetWindowDirty(w);
00757 }
00758 if (--gl->l.resort_timer == 0) {
00759 gl->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
00760 gl->l.flags |= VL_RESORT;
00761 SetWindowDirty(w);
00762 }
00763 break;
00764
00765 case WE_ABORT_PLACE_OBJ:
00766
00767 gv->vehicle_sel = INVALID_VEHICLE;
00768 w->InvalidateWidget(GRP_WIDGET_LIST_VEHICLE);
00769 break;
00770
00771 }
00772 }
00773
00774
00775 static const WindowDesc _group_desc = {
00776 WDP_AUTO, WDP_AUTO, 460, 194, 526, 246,
00777 WC_TRAINS_LIST, WC_NONE,
00778 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
00779 _group_widgets,
00780 GroupWndProc
00781 };
00782
00783 void ShowPlayerGroup(PlayerID player, VehicleType vehicle_type)
00784 {
00785 if (!IsValidPlayer(player)) return;
00786
00787 WindowClass wc;
00788
00789 switch (vehicle_type) {
00790 default: NOT_REACHED();
00791 case VEH_TRAIN: wc = WC_TRAINS_LIST; break;
00792 case VEH_ROAD: wc = WC_ROADVEH_LIST; break;
00793 case VEH_SHIP: wc = WC_SHIPS_LIST; break;
00794 case VEH_AIRCRAFT: wc = WC_AIRCRAFT_LIST; break;
00795 }
00796
00797 WindowNumber num = (vehicle_type << 11) | VLW_GROUP_LIST | player;
00798 DeleteWindowById(wc, num);
00799 Window *w = AllocateWindowDescFront(&_group_desc, num);
00800 if (w == NULL) return;
00801
00802 w->window_class = wc;
00803 }