# group_gui.cpp

Go to the documentation of this file.

    00001 /* $Id: group_gui.cpp 15724 2009-03-15 15:22:09Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "window_gui.h"
    00008 #include "textbuf_gui.h"
    00009 #include "command_func.h"
    00010 #include "vehicle_gui.h"
    00011 #include "vehicle_gui_base.h"
    00012 #include "vehicle_base.h"
    00013 #include "group.h"
    00014 #include "strings_func.h"
    00015 #include "window_func.h"
    00016 #include "vehicle_func.h"
    00017 #include "autoreplace_gui.h"
    00018 #include "gfx_func.h"
    00019 #include "company_func.h"
    00020 #include "widgets/dropdown_type.h"
    00021 #include "widgets/dropdown_func.h"
    00022 #include "tilehighlight_func.h"
    00023
    00024 #include "table/strings.h"
    00025 #include "table/sprites.h"
    00026
    00027 typedef GUIList<const Group*> GUIGroupList;
    00028
    00029 enum GroupListWidgets {
    00030   GRP_WIDGET_CLOSEBOX = 0,
    00031   GRP_WIDGET_CAPTION,
    00032   GRP_WIDGET_STICKY,
    00033   GRP_WIDGET_SORT_BY_ORDER,
    00034   GRP_WIDGET_SORT_BY_DROPDOWN,
    00035   GRP_WIDGET_EMPTY_TOP_RIGHT,
    00036   GRP_WIDGET_LIST_VEHICLE,
    00037   GRP_WIDGET_LIST_VEHICLE_SCROLLBAR,
    00038   GRP_WIDGET_EMPTY2,
    00039   GRP_WIDGET_AVAILABLE_VEHICLES,
    00040   GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN,
    00041   GRP_WIDGET_STOP_ALL,
    00042   GRP_WIDGET_START_ALL,
    00043   GRP_WIDGET_EMPTY_BOTTOM_RIGHT,
    00044   GRP_WIDGET_RESIZE,
    00045
    00046   GRP_WIDGET_EMPTY_TOP_LEFT,
    00047   GRP_WIDGET_ALL_VEHICLES,
    00048   GRP_WIDGET_DEFAULT_VEHICLES,
    00049   GRP_WIDGET_LIST_GROUP,
    00050   GRP_WIDGET_LIST_GROUP_SCROLLBAR,
    00051   GRP_WIDGET_CREATE_GROUP,
    00052   GRP_WIDGET_DELETE_GROUP,
    00053   GRP_WIDGET_RENAME_GROUP,
    00054   GRP_WIDGET_EMPTY1,
    00055   GRP_WIDGET_REPLACE_PROTECTION,
    00056 };
    00057
    00058 enum GroupActionListFunction {
    00059   GALF_REPLACE,
    00060   GALF_SERVICE,
    00061   GALF_DEPOT,
    00062   GALF_ADD_SHARED,
    00063   GALF_REMOVE_ALL,
    00064 };
    00065
    00071 static void ShowGroupActionDropdown(Window *w, GroupID gid)
    00072 {
    00073   DropDownList *list = new DropDownList();
    00074
    00075   list->push_back(new DropDownListStringItem(STR_REPLACE_VEHICLES,    GALF_REPLACE, false));
    00076   list->push_back(new DropDownListStringItem(STR_SEND_FOR_SERVICING,  GALF_SERVICE, false));
    00077   list->push_back(new DropDownListStringItem(STR_SEND_TRAIN_TO_DEPOT, GALF_DEPOT,   false));
    00078
    00079   if (IsValidGroupID(gid)) {
    00080     list->push_back(new DropDownListStringItem(STR_GROUP_ADD_SHARED_VEHICLE,  GALF_ADD_SHARED, false));
    00081     list->push_back(new DropDownListStringItem(STR_GROUP_REMOVE_ALL_VEHICLES, GALF_REMOVE_ALL, false));
    00082   }
    00083
    00084   ShowDropDownList(w, list, 0, GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN);
    00085 }
    00086
    00087
    00088 static const Widget _group_widgets[] = {
    00089 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,             STR_018B_CLOSE_WINDOW},             // GRP_WIDGET_CLOSEBOX
    00090 {    WWT_CAPTION,  RESIZE_RIGHT,  COLOUR_GREY,    11,   447,     0,    13, 0x0,                  STR_018C_WINDOW_TITLE_DRAG_THIS},   // GRP_WIDGET_CAPTION
    00091 {  WWT_STICKYBOX,     RESIZE_LR,  COLOUR_GREY,   448,   459,     0,    13, 0x0,                  STR_STICKY_BUTTON},                 // GRP_WIDGET_STICKY
    00092 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   200,   280,    14,    25, STR_SORT_BY,          STR_SORT_ORDER_TIP},                // GRP_WIDGET_SORT_BY_ORDER
    00093 {   WWT_DROPDOWN,   RESIZE_NONE,  COLOUR_GREY,   281,   447,    14,    25, 0x0,                  STR_SORT_CRITERIA_TIP},             // GRP_WIDGET_SORT_BY_DROPDOWN
    00094 {      WWT_PANEL,  RESIZE_RIGHT,  COLOUR_GREY,   448,   459,    14,    25, 0x0,                  STR_NULL},                          // GRP_WIDGET_EMPTY_TOP_RIGHT
    00095 {     WWT_MATRIX,     RESIZE_RB,  COLOUR_GREY,   200,   447,    26,   181, 0x701,                STR_NULL},                          // GRP_WIDGET_LIST_VEHICLE
    00096 {  WWT_SCROLLBAR,    RESIZE_LRB,  COLOUR_GREY,   448,   459,    26,   181, 0x0,                  STR_0190_SCROLL_BAR_SCROLLS_LIST},  // GRP_WIDGET_LIST_VEHICLE_SCROLLBAR
    00097 {      WWT_PANEL,     RESIZE_TB,  COLOUR_GREY,   188,   199,   169,   193, 0x0,                  STR_NULL},                          // GRP_WIDGET_EMPTY2
    00098 { WWT_PUSHTXTBTN,     RESIZE_TB,  COLOUR_GREY,   200,   305,   182,   193, 0x0,                  STR_AVAILABLE_ENGINES_TIP},         // GRP_WIDGET_AVAILABLE_VEHICLES
    00099 {   WWT_DROPDOWN,     RESIZE_TB,  COLOUR_GREY,   306,   423,   182,   193, STR_MANAGE_LIST,      STR_MANAGE_LIST_TIP},               // GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN
    00100 { WWT_PUSHIMGBTN,     RESIZE_TB,  COLOUR_GREY,   424,   435,   182,   193, SPR_FLAG_VEH_STOPPED, STR_MASS_STOP_LIST_TIP},            // GRP_WIDGET_STOP_ALL
    00101 { WWT_PUSHIMGBTN,     RESIZE_TB,  COLOUR_GREY,   436,   447,   182,   193, SPR_FLAG_VEH_RUNNING, STR_MASS_START_LIST_TIP},           // GRP_WIDGET_START_ALL
    00102 {      WWT_PANEL,    RESIZE_RTB,  COLOUR_GREY,   448,   447,   182,   193, 0x0,                  STR_NULL},                          // GRP_WIDGET_EMPTY_BOTTOM_RIGHT
    00103 {  WWT_RESIZEBOX,   RESIZE_LRTB,  COLOUR_GREY,   448,   459,   182,   193, 0x0,                  STR_RESIZE_BUTTON},                 // GRP_WIDGET_RESIZE
    00104
    00105 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   199,    14,    25, 0x0,                  STR_NULL},                          // GRP_WIDGET_EMPTY_TOP_LEFT
    00106 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   199,    26,    38, 0x0,                  STR_NULL},                          // GRP_WIDGET_ALL_VEHICLES
    00107 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   199,    39,    51, 0x0,                  STR_NULL},                          // GRP_WIDGET_DEFAULT_VEHICLES
    00108 {     WWT_MATRIX, RESIZE_BOTTOM,  COLOUR_GREY,     0,   187,    52,   168, 0x701,                STR_GROUPS_CLICK_ON_GROUP_FOR_TIP}, // GRP_WIDGET_LIST_GROUP
    00109 { WWT_SCROLL2BAR, RESIZE_BOTTOM,  COLOUR_GREY,   188,   199,    52,   168, 0x0,                  STR_0190_SCROLL_BAR_SCROLLS_LIST},  // GRP_WIDGET_LIST_GROUP_SCROLLBAR
    00110 { WWT_PUSHIMGBTN,     RESIZE_TB,  COLOUR_GREY,     0,    23,   169,   193, 0x0,                  STR_GROUP_CREATE_TIP},              // GRP_WIDGET_CREATE_GROUP
    00111 { WWT_PUSHIMGBTN,     RESIZE_TB,  COLOUR_GREY,    24,    47,   169,   193, 0x0,                  STR_GROUP_DELETE_TIP},              // GRP_WIDGET_DELETE_GROUP
    00112 { WWT_PUSHIMGBTN,     RESIZE_TB,  COLOUR_GREY,    48,    71,   169,   193, 0x0,                  STR_GROUP_RENAME_TIP},              // GRP_WIDGET_RENAME_GROUP
    00113 {      WWT_PANEL,     RESIZE_TB,  COLOUR_GREY,    72,   163,   169,   193, 0x0,                  STR_NULL},                          // GRP_WIDGET_EMPTY1
    00114 { WWT_PUSHIMGBTN,     RESIZE_TB,  COLOUR_GREY,   164,   187,   169,   193, 0x0,                  STR_GROUP_REPLACE_PROTECTION_TIP},  // GRP_WIDGET_REPLACE_PROTECTION
    00115 {   WIDGETS_END},
    00116 };
    00117
    00118
    00119 class VehicleGroupWindow : public BaseVehicleListWindow {
    00120 private:
    00121   GroupID group_sel;
    00122   VehicleID vehicle_sel;
    00123   GUIGroupList groups;
    00124
    00130   void BuildGroupList(Owner owner)
    00131   {
    00132     if (!this->groups.NeedRebuild()) return;
    00133
    00134     this->groups.Clear();
    00135
    00136     const Group *g;
    00137     FOR_ALL_GROUPS(g) {
    00138       if (g->owner == owner && g->vehicle_type == this->vehicle_type) {
    00139         *this->groups.Append() = g;
    00140       }
    00141     }
    00142
    00143     this->groups.Compact();
    00144     this->groups.RebuildDone();
    00145   }
    00146
    00148   static int CDECL GroupNameSorter(const Group * const *a, const Group * const *b)
    00149   {
    00150     static const Group *last_group[2] = { NULL, NULL };
    00151     static char         last_name[2][64] = { "", "" };
    00152
    00153     if (*a != last_group[0]) {
    00154       last_group[0] = *a;
    00155       SetDParam(0, (*a)->index);
    00156       GetString(last_name[0], STR_GROUP_NAME, lastof(last_name[0]));
    00157     }
    00158
    00159     if (*b != last_group[1]) {
    00160       last_group[1] = *b;
    00161       SetDParam(0, (*b)->index);
    00162       GetString(last_name[1], STR_GROUP_NAME, lastof(last_name[1]));
    00163     }
    00164
    00165     int r = strcmp(last_name[0], last_name[1]); // sort by name
    00166     if (r == 0) return (*a)->index - (*b)->index;
    00167     return r;
    00168   }
    00169
    00170 public:
    00171   VehicleGroupWindow(const WindowDesc *desc, WindowNumber window_number) : BaseVehicleListWindow(desc, window_number)
    00172   {
    00173     const Owner owner = (Owner)GB(this->window_number, 0, 8);
    00174     this->vehicle_type = (VehicleType)GB(this->window_number, 11, 5);
    00175
    00176     this->owner = owner;
    00177     this->resize.step_width = 1;
    00178
    00179     switch (this->vehicle_type) {
    00180       default: NOT_REACHED();
    00181       case VEH_TRAIN:
    00182       case VEH_ROAD:
    00183         this->vscroll2.cap = 9;
    00184         this->vscroll.cap = 6;
    00185         this->resize.step_height = PLY_WND_PRC__SIZE_OF_ROW_SMALL;
    00186         break;
    00187       case VEH_SHIP:
    00188       case VEH_AIRCRAFT:
    00189         this->vscroll2.cap = 9;
    00190         this->vscroll.cap = 4;
    00191         this->resize.step_height = PLY_WND_PRC__SIZE_OF_ROW_BIG;
    00192         break;
    00193     }
    00194
    00195     this->widget[GRP_WIDGET_LIST_GROUP].data = (this->vscroll2.cap << 8) + 1;
    00196     this->widget[GRP_WIDGET_LIST_VEHICLE].data = (this->vscroll.cap << 8) + 1;
    00197
    00198     switch (this->vehicle_type) {
    00199       default: NOT_REACHED();
    00200       case VEH_TRAIN:    this->sorting = &_sorting.train;    break;
    00201       case VEH_ROAD:     this->sorting = &_sorting.roadveh;  break;
    00202       case VEH_SHIP:     this->sorting = &_sorting.ship;     break;
    00203       case VEH_AIRCRAFT: this->sorting = &_sorting.aircraft; break;
    00204     }
    00205
    00206     this->vehicles.SetListing(*this->sorting);
    00207     this->vehicles.ForceRebuild();
    00208     this->vehicles.NeedResort();
    00209
    00210     this->groups.ForceRebuild();
    00211     this->groups.NeedResort();
    00212
    00213     this->group_sel = ALL_GROUP;
    00214     this->vehicle_sel = INVALID_VEHICLE;
    00215
    00216     switch (this->vehicle_type) {
    00217       case VEH_TRAIN:
    00218         this->widget[GRP_WIDGET_LIST_VEHICLE].tooltips = STR_883D_TRAINS_CLICK_ON_TRAIN_FOR;
    00219         this->widget[GRP_WIDGET_AVAILABLE_VEHICLES].data = STR_AVAILABLE_TRAINS;
    00220
    00221         this->widget[GRP_WIDGET_CREATE_GROUP].data = SPR_GROUP_CREATE_TRAIN;
    00222         this->widget[GRP_WIDGET_RENAME_GROUP].data = SPR_GROUP_RENAME_TRAIN;
    00223         this->widget[GRP_WIDGET_DELETE_GROUP].data = SPR_GROUP_DELETE_TRAIN;
    00224         break;
    00225
    00226       case VEH_ROAD:
    00227         this->widget[GRP_WIDGET_LIST_VEHICLE].tooltips = STR_901A_ROAD_VEHICLES_CLICK_ON;
    00228         this->widget[GRP_WIDGET_AVAILABLE_VEHICLES].data = STR_AVAILABLE_ROAD_VEHICLES;
    00229
    00230         this->widget[GRP_WIDGET_CREATE_GROUP].data = SPR_GROUP_CREATE_ROADVEH;
    00231         this->widget[GRP_WIDGET_RENAME_GROUP].data = SPR_GROUP_RENAME_ROADVEH;
    00232         this->widget[GRP_WIDGET_DELETE_GROUP].data = SPR_GROUP_DELETE_ROADVEH;
    00233         break;
    00234
    00235       case VEH_SHIP:
    00236         this->widget[GRP_WIDGET_LIST_VEHICLE].tooltips = STR_9823_SHIPS_CLICK_ON_SHIP_FOR;
    00237         this->widget[GRP_WIDGET_AVAILABLE_VEHICLES].data = STR_AVAILABLE_SHIPS;
    00238
    00239         this->widget[GRP_WIDGET_CREATE_GROUP].data = SPR_GROUP_CREATE_SHIP;
    00240         this->widget[GRP_WIDGET_RENAME_GROUP].data = SPR_GROUP_RENAME_SHIP;
    00241         this->widget[GRP_WIDGET_DELETE_GROUP].data = SPR_GROUP_DELETE_SHIP;
    00242         break;
    00243
    00244       case VEH_AIRCRAFT:
    00245         this->widget[GRP_WIDGET_LIST_VEHICLE].tooltips = STR_A01F_AIRCRAFT_CLICK_ON_AIRCRAFT;
    00246         this->widget[GRP_WIDGET_AVAILABLE_VEHICLES].data = STR_AVAILABLE_AIRCRAFT;
    00247
    00248         this->widget[GRP_WIDGET_CREATE_GROUP].data = SPR_GROUP_CREATE_AIRCRAFT;
    00249         this->widget[GRP_WIDGET_RENAME_GROUP].data = SPR_GROUP_RENAME_AIRCRAFT;
    00250         this->widget[GRP_WIDGET_DELETE_GROUP].data = SPR_GROUP_DELETE_AIRCRAFT;
    00251         break;
    00252
    00253       default: NOT_REACHED();
    00254     }
    00255
    00256     this->FindWindowPlacementAndResize(desc);
    00257     if (this->vehicle_type == VEH_TRAIN) ResizeWindow(this, 65, 0);
    00258   }
    00259
    00260   ~VehicleGroupWindow()
    00261   {
    00262     *this->sorting = this->vehicles.GetListing();
    00263   }
    00264
    00265   virtual void OnInvalidateData(int data)
    00266   {
    00267     if (data == 0) {
    00268       this->vehicles.ForceRebuild();
    00269       this->groups.ForceRebuild();
    00270     } else {
    00271       this->vehicles.ForceResort();
    00272       this->groups.ForceResort();
    00273     }
    00274
    00275     if (!(IsAllGroupID(this->group_sel) || IsDefaultGroupID(this->group_sel) || IsValidGroupID(this->group_sel))) {
    00276       this->group_sel = ALL_GROUP;
    00277       HideDropDownMenu(this);
    00278     }
    00279     this->SetDirty();
    00280   }
    00281
    00282   virtual void OnPaint()
    00283   {
    00284     const Owner owner = (Owner)GB(this->window_number, 0, 8);
    00285     int x = this->widget[GRP_WIDGET_LIST_VEHICLE].left + 2;
    00286     int y1 = PLY_WND_PRC__OFFSET_TOP_WIDGET + 2;
    00287     int max;
    00288     int i;
    00289
    00290     /* If we select the all vehicles, this->list will contain all vehicles of the owner
    00291      * else this->list will contain all vehicles which belong to the selected group */
    00292     this->BuildVehicleList(owner, this->group_sel, IsAllGroupID(this->group_sel) ? VLW_STANDARD : VLW_GROUP_LIST);
    00293     this->SortVehicleList();
    00294
    00295     this->BuildGroupList(owner);
    00296     this->groups.Sort(&GroupNameSorter);
    00297
    00298     SetVScroll2Count(this, this->groups.Length());
    00299     SetVScrollCount(this, this->vehicles.Length());
    00300
    00301     /* The drop down menu is out, *but* it may not be used, retract it. */
    00302     if (this->vehicles.Length() == 0 && this->IsWidgetLowered(GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN)) {
    00303       this->RaiseWidget(GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN);
    00304       HideDropDownMenu(this);
    00305     }
    00306
    00307     /* Disable all lists management button when the list is empty */
    00308     this->SetWidgetsDisabledState(this->vehicles.Length() == 0 || _local_company != owner,
    00309         GRP_WIDGET_STOP_ALL,
    00310         GRP_WIDGET_START_ALL,
    00311         GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN,
    00312         WIDGET_LIST_END);
    00313
    00314     /* Disable the group specific function when we select the default group or all vehicles */
    00315     this->SetWidgetsDisabledState(IsDefaultGroupID(this->group_sel) || IsAllGroupID(this->group_sel) || _local_company != owner,
    00316         GRP_WIDGET_DELETE_GROUP,
    00317         GRP_WIDGET_RENAME_GROUP,
    00318         GRP_WIDGET_REPLACE_PROTECTION,
    00319         WIDGET_LIST_END);
    00320
    00321     /* Disable remaining buttons for non-local companies
    00322      * Needed while changing _local_company, eg. by cheats
    00323      * All procedures (eg. move vehicle to another group)
    00324      *  verify, whether you are the owner of the vehicle,
    00325      *  so it doesn't have to be disabled
    00326      */
    00327     this->SetWidgetsDisabledState(_local_company != owner,
    00328         GRP_WIDGET_CREATE_GROUP,
    00329         GRP_WIDGET_AVAILABLE_VEHICLES,
    00330         WIDGET_LIST_END);
    00331
    00332
    00333     /* If selected_group == DEFAULT_GROUP || ALL_GROUP, draw the standard caption
    00334         We list all vehicles or ungrouped vehicles */
    00335     if (IsDefaultGroupID(this->group_sel) || IsAllGroupID(this->group_sel)) {
    00336       SetDParam(0, owner);
    00337       SetDParam(1, this->vehicles.Length());
    00338
    00339       switch (this->vehicle_type) {
    00340         case VEH_TRAIN:
    00341           this->widget[GRP_WIDGET_CAPTION].data = STR_881B_TRAINS;
    00342           this->widget[GRP_WIDGET_REPLACE_PROTECTION].data = SPR_GROUP_REPLACE_OFF_TRAIN;
    00343           break;
    00344         case VEH_ROAD:
    00345           this->widget[GRP_WIDGET_CAPTION].data = STR_9001_ROAD_VEHICLES;
    00346           this->widget[GRP_WIDGET_REPLACE_PROTECTION].data = SPR_GROUP_REPLACE_OFF_ROADVEH;
    00347           break;
    00348         case VEH_SHIP:
    00349           this->widget[GRP_WIDGET_CAPTION].data = STR_9805_SHIPS;
    00350           this->widget[GRP_WIDGET_REPLACE_PROTECTION].data = SPR_GROUP_REPLACE_OFF_SHIP;
    00351           break;
    00352         case VEH_AIRCRAFT:
    00353           this->widget[GRP_WIDGET_CAPTION].data =  STR_A009_AIRCRAFT;
    00354           this->widget[GRP_WIDGET_REPLACE_PROTECTION].data = SPR_GROUP_REPLACE_OFF_AIRCRAFT;
    00355           break;
    00356         default: NOT_REACHED();
    00357       }
    00358     } else {
    00359       const Group *g = GetGroup(this->group_sel);
    00360
    00361       SetDParam(0, g->index);
    00362       SetDParam(1, g->num_vehicle);
    00363
    00364       switch (this->vehicle_type) {
    00365         case VEH_TRAIN:
    00366           this->widget[GRP_WIDGET_CAPTION].data = STR_GROUP_TRAINS_CAPTION;
    00367           this->widget[GRP_WIDGET_REPLACE_PROTECTION].data = (g->replace_protection) ? SPR_GROUP_REPLACE_ON_TRAIN : SPR_GROUP_REPLACE_OFF_TRAIN;
    00368           break;
    00369         case VEH_ROAD:
    00370           this->widget[GRP_WIDGET_CAPTION].data = STR_GROUP_ROADVEH_CAPTION;
    00371           this->widget[GRP_WIDGET_REPLACE_PROTECTION].data = (g->replace_protection) ? SPR_GROUP_REPLACE_ON_ROADVEH : SPR_GROUP_REPLACE_OFF_ROADVEH;
    00372           break;
    00373         case VEH_SHIP:
    00374           this->widget[GRP_WIDGET_CAPTION].data = STR_GROUP_SHIPS_CAPTION;
    00375           this->widget[GRP_WIDGET_REPLACE_PROTECTION].data = (g->replace_protection) ? SPR_GROUP_REPLACE_ON_SHIP : SPR_GROUP_REPLACE_OFF_SHIP;
    00376           break;
    00377         case VEH_AIRCRAFT:
    00378           this->widget[GRP_WIDGET_CAPTION].data = STR_GROUP_AIRCRAFTS_CAPTION;
    00379           this->widget[GRP_WIDGET_REPLACE_PROTECTION].data = (g->replace_protection) ? SPR_GROUP_REPLACE_ON_AIRCRAFT : SPR_GROUP_REPLACE_OFF_AIRCRAFT;
    00380           break;
    00381         default: NOT_REACHED();
    00382       }
    00383     }
    00384
    00385     /* Set text of sort by dropdown */
    00386     this->widget[GRP_WIDGET_SORT_BY_DROPDOWN].data = this->vehicle_sorter_names[this->vehicles.SortType()];
    00387
    00388     this->DrawWidgets();
    00389
    00390     /* Draw Matrix Group
    00391      * The selected group is drawn in white */
    00392     StringID str_all_veh, str_no_group_veh;
    00393
    00394     switch (this->vehicle_type) {
    00395       case VEH_TRAIN:
    00396         str_all_veh = STR_GROUP_ALL_TRAINS;
    00397         str_no_group_veh = STR_GROUP_DEFAULT_TRAINS;
    00398         break;
    00399       case VEH_ROAD:
    00400         str_all_veh = STR_GROUP_ALL_ROADS;
    00401         str_no_group_veh = STR_GROUP_DEFAULT_ROADS;
    00402         break;
    00403       case VEH_SHIP:
    00404         str_all_veh = STR_GROUP_ALL_SHIPS;
    00405         str_no_group_veh = STR_GROUP_DEFAULT_SHIPS;
    00406         break;
    00407       case VEH_AIRCRAFT:
    00408         str_all_veh = STR_GROUP_ALL_AIRCRAFTS;
    00409         str_no_group_veh = STR_GROUP_DEFAULT_AIRCRAFTS;
    00410         break;
    00411       default: NOT_REACHED();
    00412     }
    00413     DrawString(10, y1, str_all_veh, IsAllGroupID(this->group_sel) ? TC_WHITE : TC_BLACK);
    00414
    00415     y1 += 13;
    00416
    00417     DrawString(10, y1, str_no_group_veh, IsDefaultGroupID(this->group_sel) ? TC_WHITE : TC_BLACK);
    00418
    00419     max = min(this->vscroll2.pos + this->vscroll2.cap, this->groups.Length());
    00420     for (i = this->vscroll2.pos ; i < max ; ++i) {
    00421       const Group *g = this->groups[i];
    00422
    00423       assert(g->owner == owner);
    00424
    00425       y1 += PLY_WND_PRC__SIZE_OF_ROW_TINY;
    00426
    00427       /* draw the selected group in white, else we draw it in black */
    00428       SetDParam(0, g->index);
    00429       DrawString(10, y1, STR_GROUP_NAME, (this->group_sel == g->index) ? TC_WHITE : TC_BLACK);
    00430
    00431       /* draw the number of vehicles of the group */
    00432       SetDParam(0, g->num_vehicle);
    00433       DrawStringRightAligned(187, y1 + 1, STR_GROUP_TINY_NUM, (this->group_sel == g->index) ? TC_WHITE : TC_BLACK);
    00434     }
    00435
    00436     this->DrawSortButtonState(GRP_WIDGET_SORT_BY_ORDER, this->vehicles.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
    00437
    00438     this->DrawVehicleListItems(x, this->vehicle_sel);
    00439   }
    00440
    00441   virtual void OnClick(Point pt, int widget)
    00442   {
    00443     switch(widget) {
    00444       case GRP_WIDGET_SORT_BY_ORDER: // Flip sorting method ascending/descending
    00445         this->vehicles.ToggleSortOrder();
    00446         this->SetDirty();
    00447         break;
    00448
    00449       case GRP_WIDGET_SORT_BY_DROPDOWN: // Select sorting criteria dropdown menu
    00450         ShowDropDownMenu(this, this->vehicle_sorter_names, this->vehicles.SortType(),  GRP_WIDGET_SORT_BY_DROPDOWN, 0, (this->vehicle_type == VEH_TRAIN || this->vehicle_type == VEH_ROAD) ? 0 : (1 << 10));
    00451         return;
    00452
    00453       case GRP_WIDGET_ALL_VEHICLES: // All vehicles button
    00454         if (!IsAllGroupID(this->group_sel)) {
    00455           this->group_sel = ALL_GROUP;
    00456           this->vehicles.ForceRebuild();
    00457           this->SetDirty();
    00458         }
    00459         break;
    00460
    00461       case GRP_WIDGET_DEFAULT_VEHICLES: // Ungrouped vehicles button
    00462         if (!IsDefaultGroupID(this->group_sel)) {
    00463           this->group_sel = DEFAULT_GROUP;
    00464           this->vehicles.ForceRebuild();
    00465           this->SetDirty();
    00466         }
    00467         break;
    00468
    00469       case GRP_WIDGET_LIST_GROUP: { // Matrix Group
    00470         uint16 id_g = (pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET - 26) / PLY_WND_PRC__SIZE_OF_ROW_TINY;
    00471
    00472         if (id_g >= this->vscroll2.cap) return;
    00473
    00474         id_g += this->vscroll2.pos;
    00475
    00476         if (id_g >= this->groups.Length()) return;
    00477
    00478         this->group_sel = this->groups[id_g]->index;;
    00479
    00480         this->vehicles.ForceRebuild();
    00481         this->SetDirty();
    00482         break;
    00483       }
    00484
    00485       case GRP_WIDGET_LIST_VEHICLE: { // Matrix Vehicle
    00486         uint32 id_v = (pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / (int)this->resize.step_height;
    00487         const Vehicle *v;
    00488
    00489         if (id_v >= this->vscroll.cap) return; // click out of bounds
    00490
    00491         id_v += this->vscroll.pos;
    00492
    00493         if (id_v >= this->vehicles.Length()) return; // click out of list bound
    00494
    00495         v = this->vehicles[id_v];
    00496
    00497         this->vehicle_sel = v->index;
    00498
    00499         if (v->IsValid()) {
    00500           SetObjectToPlaceWnd(v->GetImage(DIR_W), GetVehiclePalette(v), VHM_DRAG, this);
    00501           _cursor.vehchain = true;
    00502         }
    00503
    00504         this->SetDirty();
    00505         break;
    00506       }
    00507
    00508       case GRP_WIDGET_CREATE_GROUP: // Create a new group
    00509         DoCommandP(0, this->vehicle_type, 0, CMD_CREATE_GROUP | CMD_MSG(STR_GROUP_CAN_T_CREATE));
    00510         break;
    00511
    00512       case GRP_WIDGET_DELETE_GROUP: { // Delete the selected group
    00513         GroupID group = this->group_sel;
    00514         this->group_sel = ALL_GROUP;
    00515
    00516         DoCommandP(0, group, 0, CMD_DELETE_GROUP | CMD_MSG(STR_GROUP_CAN_T_DELETE));
    00517         break;
    00518       }
    00519
    00520       case GRP_WIDGET_RENAME_GROUP: { // Rename the selected roup
    00521         assert(IsValidGroupID(this->group_sel));
    00522
    00523         const Group *g = GetGroup(this->group_sel);
    00524
    00525         SetDParam(0, g->index);
    00526         ShowQueryString(STR_GROUP_NAME, STR_GROUP_RENAME_CAPTION, MAX_LENGTH_GROUP_NAME_BYTES, MAX_LENGTH_GROUP_NAME_PIXELS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT);
    00527       } break;
    00528
    00529
    00530       case GRP_WIDGET_AVAILABLE_VEHICLES:
    00531         ShowBuildVehicleWindow(INVALID_TILE, this->vehicle_type);
    00532         break;
    00533
    00534       case GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN:
    00535         ShowGroupActionDropdown(this, this->group_sel);
    00536         break;
    00537
    00538       case GRP_WIDGET_START_ALL:
    00539       case GRP_WIDGET_STOP_ALL: { // Start/stop all vehicles of the list
    00540         DoCommandP(0, this->group_sel, ((IsAllGroupID(this->group_sel) ? VLW_STANDARD : VLW_GROUP_LIST) & VLW_MASK)
    00541                           | (1 << 6)
    00542                           | (widget == GRP_WIDGET_START_ALL ? (1 << 5) : 0)
    00543                           | this->vehicle_type, CMD_MASS_START_STOP);
    00544
    00545         break;
    00546       }
    00547
    00548       case GRP_WIDGET_REPLACE_PROTECTION:
    00549         if (IsValidGroupID(this->group_sel)) {
    00550           const Group *g = GetGroup(this->group_sel);
    00551
    00552           DoCommandP(0, this->group_sel, !g->replace_protection, CMD_SET_GROUP_REPLACE_PROTECTION);
    00553         }
    00554         break;
    00555     }
    00556   }
    00557
    00558   virtual void OnDragDrop(Point pt, int widget)
    00559   {
    00560     switch (widget) {
    00561       case GRP_WIDGET_ALL_VEHICLES: // All vehicles
    00562       case GRP_WIDGET_DEFAULT_VEHICLES: // Ungrouped vehicles
    00563         DoCommandP(0, DEFAULT_GROUP, this->vehicle_sel, CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_GROUP_CAN_T_ADD_VEHICLE));
    00564
    00565         this->vehicle_sel = INVALID_VEHICLE;
    00566
    00567         this->SetDirty();
    00568
    00569         break;
    00570
    00571       case GRP_WIDGET_LIST_GROUP: { // Maxtrix group
    00572         uint16 id_g = (pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET - 26) / PLY_WND_PRC__SIZE_OF_ROW_TINY;
    00573         const VehicleID vindex = this->vehicle_sel;
    00574
    00575         this->vehicle_sel = INVALID_VEHICLE;
    00576
    00577         this->SetDirty();
    00578
    00579         if (id_g >= this->vscroll2.cap) return;
    00580
    00581         id_g += this->vscroll2.pos;
    00582
    00583         if (id_g >= this->groups.Length()) return;
    00584
    00585         DoCommandP(0, this->groups[id_g]->index, vindex, CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_GROUP_CAN_T_ADD_VEHICLE));
    00586
    00587         break;
    00588       }
    00589
    00590       case GRP_WIDGET_LIST_VEHICLE: { // Maxtrix vehicle
    00591         uint32 id_v = (pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / (int)this->resize.step_height;
    00592         const Vehicle *v;
    00593         const VehicleID vindex = this->vehicle_sel;
    00594
    00595         this->vehicle_sel = INVALID_VEHICLE;
    00596
    00597         this->SetDirty();
    00598
    00599         if (id_v >= this->vscroll.cap) return; // click out of bounds
    00600
    00601         id_v += this->vscroll.pos;
    00602
    00603         if (id_v >= this->vehicles.Length()) return; // click out of list bound
    00604
    00605         v = this->vehicles[id_v];
    00606
    00607         if (vindex == v->index) {
    00608           ShowVehicleViewWindow(v);
    00609         }
    00610
    00611         break;
    00612       }
    00613     }
    00614     _cursor.vehchain = false;
    00615   }
    00616
    00617   virtual void OnQueryTextFinished(char *str)
    00618   {
    00619     if (str == NULL) return;
    00620
    00621     DoCommandP(0, this->group_sel, 0, CMD_RENAME_GROUP | CMD_MSG(STR_GROUP_CAN_T_RENAME), NULL, str);
    00622   }
    00623
    00624   virtual void OnResize(Point new_size, Point delta)
    00625   {
    00626     this->vscroll2.cap += delta.y / PLY_WND_PRC__SIZE_OF_ROW_TINY;
    00627     this->vscroll.cap += delta.y / (int)this->resize.step_height;
    00628
    00629     this->widget[GRP_WIDGET_LIST_GROUP].data = (this->vscroll2.cap << 8) + 1;
    00630     this->widget[GRP_WIDGET_LIST_VEHICLE].data = (this->vscroll.cap << 8) + 1;
    00631   }
    00632
    00633   virtual void OnDropdownSelect(int widget, int index)
    00634   {
    00635     switch (widget) {
    00636       case GRP_WIDGET_SORT_BY_DROPDOWN:
    00637         this->vehicles.SetSortType(index);
    00638         break;
    00639
    00640       case GRP_WIDGET_MANAGE_VEHICLES_DROPDOWN:
    00641         assert(this->vehicles.Length() != 0);
    00642
    00643         switch (index) {
    00644           case GALF_REPLACE: // Replace window
    00645             ShowReplaceGroupVehicleWindow(this->group_sel, this->vehicle_type);
    00646             break;
    00647           case GALF_SERVICE: // Send for servicing
    00648             DoCommandP(0, this->group_sel, ((IsAllGroupID(this->group_sel) ? VLW_STANDARD : VLW_GROUP_LIST) & VLW_MASK)
    00649                   | DEPOT_MASS_SEND
    00650                   | DEPOT_SERVICE, GetCmdSendToDepot(this->vehicle_type));
    00651             break;
    00652           case GALF_DEPOT: // Send to Depots
    00653             DoCommandP(0, this->group_sel, ((IsAllGroupID(this->group_sel) ? VLW_STANDARD : VLW_GROUP_LIST) & VLW_MASK)
    00654                   | DEPOT_MASS_SEND, GetCmdSendToDepot(this->vehicle_type));
    00655             break;
    00656           case GALF_ADD_SHARED: // Add shared Vehicles
    00657             assert(IsValidGroupID(this->group_sel));
    00658
    00659             DoCommandP(0, this->group_sel, this->vehicle_type, CMD_ADD_SHARED_VEHICLE_GROUP | CMD_MSG(STR_GROUP_CAN_T_ADD_SHARED_VEHICLE));
    00660             break;
    00661           case GALF_REMOVE_ALL: // Remove all Vehicles from the selected group
    00662             assert(IsValidGroupID(this->group_sel));
    00663
    00664             DoCommandP(0, this->group_sel, this->vehicle_type, CMD_REMOVE_ALL_VEHICLES_GROUP | CMD_MSG(STR_GROUP_CAN_T_REMOVE_ALL_VEHICLES));
    00665             break;
    00666           default: NOT_REACHED();
    00667         }
    00668         break;
    00669
    00670       default: NOT_REACHED();
    00671     }
    00672
    00673     this->SetDirty();
    00674   }
    00675
    00676   virtual void OnTick()
    00677   {
    00678     if (_pause_game != 0) return;
    00679     if (this->groups.NeedResort() || this->vehicles.NeedResort()) {
    00680       this->SetDirty();
    00681     }
    00682   }
    00683
    00684   virtual void OnPlaceObjectAbort()
    00685   {
    00686     /* abort drag & drop */
    00687     this->vehicle_sel = INVALID_VEHICLE;
    00688     this->InvalidateWidget(GRP_WIDGET_LIST_VEHICLE);
    00689   }
    00690
    00696   void UnselectVehicle(VehicleID vehicle)
    00697   {
    00698     if (this->vehicle_sel == vehicle) ResetObjectToPlace();
    00699   }
    00700 };
    00701
    00702
    00703 static WindowDesc _group_desc(
    00704   WDP_AUTO, WDP_AUTO, 460, 194, 460, 246,
    00705   WC_INVALID, WC_NONE,
    00706   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
    00707   _group_widgets
    00708 );
    00709
    00710 void ShowCompanyGroup(CompanyID company, VehicleType vehicle_type)
    00711 {
    00712   if (!IsValidCompanyID(company)) return;
    00713
    00714   _group_desc.cls = GetWindowClassForVehicleType(vehicle_type);
    00715   WindowNumber num = (vehicle_type << 11) | VLW_GROUP_LIST | company;
    00716   AllocateWindowDescFront<VehicleGroupWindow>(&_group_desc, num);
    00717 }
    00718
    00723 void DeleteGroupHighlightOfVehicle(const Vehicle *v)
    00724 {
    00725   VehicleGroupWindow *w;
    00726
    00727   /* If we haven't got any vehicles on the mouse pointer, we haven't got any highlighted in any group windows either
    00728    * If that is the case, we can skip looping though the windows and save time
    00729    */
    00730   if (_special_mouse_mode != WSM_DRAGDROP) return;
    00731
    00732   VehicleType vehicle_type = v->type;
    00733   w = dynamic_cast<VehicleGroupWindow *>(FindWindowById(GetWindowClassForVehicleType(vehicle_type), (vehicle_type << 11) | VLW_GROUP_LIST | v->owner));
    00734   if (w != NULL) w->UnselectVehicle(v->index);
    00735 }
    00736