src/vehicle_gui.cpp
changeset 9182 412cb6c0caf1
parent 9161 fda175383e87
child 9183 6e749ab7d680
equal deleted inserted replaced
9181:8a343ab40a96 9182:412cb6c0caf1
    52 	uint length;
    52 	uint length;
    53 	VehicleOrderID order;
    53 	VehicleOrderID order;
    54 };
    54 };
    55 assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(refit_d));
    55 assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(refit_d));
    56 
    56 
    57 struct Sorting {
    57 Sorting _sorting;
    58 	Listing aircraft;
       
    59 	Listing roadveh;
       
    60 	Listing ship;
       
    61 	Listing train;
       
    62 };
       
    63 
       
    64 static Sorting _sorting;
       
    65 
       
    66 static bool   _internal_sort_order;     // descending/ascending
    58 static bool   _internal_sort_order;     // descending/ascending
    67 
    59 
    68 typedef int CDECL VehicleSortListingTypeFunction(const void*, const void*);
    60 typedef int CDECL VehicleSortListingTypeFunction(const void*, const void*);
    69 
    61 
    70 static VehicleSortListingTypeFunction VehicleNumberSorter;
    62 static VehicleSortListingTypeFunction VehicleNumberSorter;
   122 		switch (w->window_class) {
   114 		switch (w->window_class) {
   123 			case WC_TRAINS_LIST:
   115 			case WC_TRAINS_LIST:
   124 			case WC_ROADVEH_LIST:
   116 			case WC_ROADVEH_LIST:
   125 			case WC_SHIPS_LIST:
   117 			case WC_SHIPS_LIST:
   126 			case WC_AIRCRAFT_LIST:
   118 			case WC_AIRCRAFT_LIST:
   127 				WP(w, vehiclelist_d).l.flags |= sl_flag;
   119 				WP(w, vehiclelist_d).vehicles.flags |= sl_flag;
   128 				w->SetDirty();
   120 				w->SetDirty();
   129 				break;
   121 				break;
   130 
   122 
   131 			default: break;
   123 			default: break;
   132 		}
   124 		}
   149 	SetVehicleListsFlag(VL_RESORT);
   141 	SetVehicleListsFlag(VL_RESORT);
   150 }
   142 }
   151 
   143 
   152 void BuildVehicleList(vehiclelist_d *vl, PlayerID owner, uint16 index, uint16 window_type)
   144 void BuildVehicleList(vehiclelist_d *vl, PlayerID owner, uint16 index, uint16 window_type)
   153 {
   145 {
   154 	if (!(vl->l.flags & VL_REBUILD)) return;
   146 	if (!(vl->vehicles.flags & VL_REBUILD)) return;
   155 
   147 
   156 	DEBUG(misc, 3, "Building vehicle list for player %d at station %d", owner, index);
   148 	DEBUG(misc, 3, "Building vehicle list for player %d at station %d", owner, index);
   157 
   149 
   158 	vl->l.list_length = GenerateVehicleSortList(&vl->sort_list, &vl->length_of_sort_list, vl->vehicle_type, owner, index, window_type);
   150 	vl->vehicles.list_length = GenerateVehicleSortList(&vl->vehicles.sort_list, &vl->vehicles.list_length, vl->vehicle_type, owner, index, window_type);
   159 
   151 
   160 	vl->l.flags &= ~VL_REBUILD;
   152 	vl->vehicles.flags &= ~VL_REBUILD;
   161 	vl->l.flags |= VL_RESORT;
   153 	vl->vehicles.flags |= VL_RESORT;
   162 }
   154 }
   163 
   155 
   164 /* cached values for VehicleNameSorter to spare many GetString() calls */
   156 /* cached values for VehicleNameSorter to spare many GetString() calls */
   165 static const Vehicle *_last_vehicle[2] = { NULL, NULL };
   157 static const Vehicle *_last_vehicle[2] = { NULL, NULL };
   166 static char           _last_name[2][64] = { "", "" };
   158 static char           _last_name[2][64] = { "", "" };
   167 
   159 
   168 void SortVehicleList(vehiclelist_d *vl)
   160 void SortVehicleList(vehiclelist_d *vl)
   169 {
   161 {
   170 	if (!(vl->l.flags & VL_RESORT)) return;
   162 	if (!(vl->vehicles.flags & VL_RESORT)) return;
   171 
   163 
   172 	/* invalidate cached values for name sorter - vehicle names could change */
   164 	/* invalidate cached values for name sorter - vehicle names could change */
   173 	_last_vehicle[0] = _last_vehicle[1] = NULL;
   165 	_last_vehicle[0] = _last_vehicle[1] = NULL;
   174 
   166 
   175 	_internal_sort_order = (vl->l.flags & VL_DESC) != 0;
   167 	_internal_sort_order = (vl->vehicles.flags & VL_DESC) != 0;
   176 	qsort((void*)vl->sort_list, vl->l.list_length, sizeof(vl->sort_list[0]),
   168 	qsort((void*)vl->vehicles.sort_list, vl->vehicles.list_length, sizeof(vl->vehicles.sort_list[0]),
   177 		_vehicle_sorter[vl->l.sort_type]);
   169 		_vehicle_sorter[vl->vehicles.sort_type]);
   178 
   170 
   179 	vl->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
   171 	vl->vehicles.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
   180 	vl->l.flags &= ~VL_RESORT;
   172 	vl->vehicles.flags &= ~VL_RESORT;
   181 }
   173 }
   182 
   174 
   183 void DepotSortList(Vehicle **v, uint16 length)
   175 void DepotSortList(Vehicle **v, uint16 length)
   184 {
   176 {
   185 	_internal_sort_order = 0;
   177 	_internal_sort_order = 0;
   820 	vehiclelist_d *vl = &WP(w, vehiclelist_d);
   812 	vehiclelist_d *vl = &WP(w, vehiclelist_d);
   821 	uint16 window_type = w->window_number & VLW_MASK;
   813 	uint16 window_type = w->window_number & VLW_MASK;
   822 	PlayerID player = (PlayerID)GB(w->window_number, 0, 8);
   814 	PlayerID player = (PlayerID)GB(w->window_number, 0, 8);
   823 
   815 
   824 	vl->vehicle_type = (VehicleType)GB(w->window_number, 11, 5);
   816 	vl->vehicle_type = (VehicleType)GB(w->window_number, 11, 5);
   825 	vl->length_of_sort_list = 0;
   817 	vl->vehicles.list_length = 0;
   826 	vl->sort_list = NULL;
   818 	vl->vehicles.sort_list = NULL;
   827 	w->caption_color = player;
   819 	w->caption_color = player;
   828 
   820 
   829 	/* Hide the widgets that we will not use in this window
   821 	/* Hide the widgets that we will not use in this window
   830 	 * Some windows contains actions only fit for the owner */
   822 	 * Some windows contains actions only fit for the owner */
   831 	if (player == _local_player) {
   823 	if (player == _local_player) {
   922 
   914 
   923 	/* Set up sorting. Make the window-specific _sorting variable
   915 	/* Set up sorting. Make the window-specific _sorting variable
   924 		* point to the correct global _sorting struct so we are freed
   916 		* point to the correct global _sorting struct so we are freed
   925 		* from having conditionals during window operation */
   917 		* from having conditionals during window operation */
   926 	switch (vl->vehicle_type) {
   918 	switch (vl->vehicle_type) {
   927 		case VEH_TRAIN:    vl->_sorting = &_sorting.train; break;
   919 		case VEH_TRAIN:    vl->sorting = &_sorting.train; break;
   928 		case VEH_ROAD:     vl->_sorting = &_sorting.roadveh; break;
   920 		case VEH_ROAD:     vl->sorting = &_sorting.roadveh; break;
   929 		case VEH_SHIP:     vl->_sorting = &_sorting.ship; break;
   921 		case VEH_SHIP:     vl->sorting = &_sorting.ship; break;
   930 		case VEH_AIRCRAFT: vl->_sorting = &_sorting.aircraft; break;
   922 		case VEH_AIRCRAFT: vl->sorting = &_sorting.aircraft; break;
   931 		default: NOT_REACHED(); break;
   923 		default: NOT_REACHED(); break;
   932 	}
   924 	}
   933 
   925 
   934 	vl->l.flags = VL_REBUILD | (vl->_sorting->order ? VL_DESC : VL_NONE);
   926 	vl->vehicles.flags = VL_REBUILD | (vl->sorting->order ? VL_DESC : VL_NONE);
   935 	vl->l.sort_type = vl->_sorting->criteria;
   927 	vl->vehicles.sort_type = vl->sorting->criteria;
   936 	vl->sort_list = NULL;
   928 	vl->vehicles.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS; // Set up resort timer
   937 	vl->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS; // Set up resort timer
       
   938 }
   929 }
   939 
   930 
   940 void DrawSmallOrderList(const Vehicle *v, int x, int y)
   931 void DrawSmallOrderList(const Vehicle *v, int x, int y)
   941 {
   932 {
   942 	const Order *order;
   933 	const Order *order;
   971 	const uint16 window_type = w->window_number & VLW_MASK;
   962 	const uint16 window_type = w->window_number & VLW_MASK;
   972 	const uint16 index = GB(w->window_number, 16, 16);
   963 	const uint16 index = GB(w->window_number, 16, 16);
   973 
   964 
   974 	BuildVehicleList(vl, owner, index, window_type);
   965 	BuildVehicleList(vl, owner, index, window_type);
   975 	SortVehicleList(vl);
   966 	SortVehicleList(vl);
   976 	SetVScrollCount(w, vl->l.list_length);
   967 	SetVScrollCount(w, vl->vehicles.list_length);
   977 
   968 
   978 	/* draw the widgets */
   969 	/* draw the widgets */
   979 	switch (window_type) {
   970 	switch (window_type) {
   980 		case VLW_SHARED_ORDERS: /* Shared Orders */
   971 		case VLW_SHARED_ORDERS: /* Shared Orders */
   981 			if (vl->l.list_length == 0) {
   972 			if (vl->vehicles.list_length == 0) {
   982 				/* We can't open this window without vehicles using this order
   973 				/* We can't open this window without vehicles using this order
   983 				 * and we should close the window when deleting the order      */
   974 				 * and we should close the window when deleting the order      */
   984 				NOT_REACHED();
   975 				NOT_REACHED();
   985 			}
   976 			}
   986 			SetDParam(0, w->vscroll.count);
   977 			SetDParam(0, w->vscroll.count);
  1012 			SetDParam(2, w->vscroll.count);
  1003 			SetDParam(2, w->vscroll.count);
  1013 			break;
  1004 			break;
  1014 		default: NOT_REACHED(); break;
  1005 		default: NOT_REACHED(); break;
  1015 	}
  1006 	}
  1016 
  1007 
  1017 	w->SetWidgetsDisabledState(vl->l.list_length == 0,
  1008 	w->SetWidgetsDisabledState(vl->vehicles.list_length == 0,
  1018 		VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN,
  1009 		VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN,
  1019 		VLW_WIDGET_STOP_ALL,
  1010 		VLW_WIDGET_STOP_ALL,
  1020 		VLW_WIDGET_START_ALL,
  1011 		VLW_WIDGET_START_ALL,
  1021 		WIDGET_LIST_END);
  1012 		WIDGET_LIST_END);
  1022 
  1013 
  1023 	DrawWindowWidgets(w);
  1014 	DrawWindowWidgets(w);
  1024 
  1015 
  1025 	/* draw sorting criteria string */
  1016 	/* draw sorting criteria string */
  1026 	DrawString(85, 15, _vehicle_sort_listing[vl->l.sort_type], TC_BLACK);
  1017 	DrawString(85, 15, _vehicle_sort_listing[vl->vehicles.sort_type], TC_BLACK);
  1027 	/* draw arrow pointing up/down for ascending/descending sorting */
  1018 	/* draw arrow pointing up/down for ascending/descending sorting */
  1028 	DrawSortButtonState(w, VLW_WIDGET_SORT_ORDER, vl->l.flags & VL_DESC ? SBS_DOWN : SBS_UP);
  1019 	DrawSortButtonState(w, VLW_WIDGET_SORT_ORDER, vl->vehicles.flags & VL_DESC ? SBS_DOWN : SBS_UP);
  1029 
  1020 
  1030 	max = min(w->vscroll.pos + w->vscroll.cap, vl->l.list_length);
  1021 	max = min(w->vscroll.pos + w->vscroll.cap, vl->vehicles.list_length);
  1031 	for (i = w->vscroll.pos; i < max; ++i) {
  1022 	for (i = w->vscroll.pos; i < max; ++i) {
  1032 		const Vehicle *v = vl->sort_list[i];
  1023 		const Vehicle *v = vl->vehicles.sort_list[i];
  1033 		StringID str;
  1024 		StringID str;
  1034 
  1025 
  1035 		SetDParam(0, v->GetDisplayProfitThisYear());
  1026 		SetDParam(0, v->GetDisplayProfitThisYear());
  1036 		SetDParam(1, v->GetDisplayProfitLastYear());
  1027 		SetDParam(1, v->GetDisplayProfitLastYear());
  1037 
  1028 
  1082 			break;
  1073 			break;
  1083 
  1074 
  1084 		case WE_CLICK: {
  1075 		case WE_CLICK: {
  1085 			switch (e->we.click.widget) {
  1076 			switch (e->we.click.widget) {
  1086 				case VLW_WIDGET_SORT_ORDER: /* Flip sorting method ascending/descending */
  1077 				case VLW_WIDGET_SORT_ORDER: /* Flip sorting method ascending/descending */
  1087 					vl->l.flags ^= VL_DESC;
  1078 					vl->vehicles.flags ^= VL_DESC;
  1088 					vl->l.flags |= VL_RESORT;
  1079 					vl->vehicles.flags |= VL_RESORT;
  1089 
  1080 
  1090 					vl->_sorting->order = !!(vl->l.flags & VL_DESC);
  1081 					vl->sorting->order = !!(vl->vehicles.flags & VL_DESC);
  1091 					w->SetDirty();
  1082 					w->SetDirty();
  1092 					break;
  1083 					break;
  1093 				case VLW_WIDGET_SORT_BY_PULLDOWN:/* Select sorting criteria dropdown menu */
  1084 				case VLW_WIDGET_SORT_BY_PULLDOWN:/* Select sorting criteria dropdown menu */
  1094 					ShowDropDownMenu(w, _vehicle_sort_listing, vl->l.sort_type, VLW_WIDGET_SORT_BY_PULLDOWN, 0, (vl->vehicle_type == VEH_TRAIN || vl->vehicle_type == VEH_ROAD) ? 0 : (1 << 10));
  1085 					ShowDropDownMenu(w, _vehicle_sort_listing, vl->vehicles.sort_type, VLW_WIDGET_SORT_BY_PULLDOWN, 0, (vl->vehicle_type == VEH_TRAIN || vl->vehicle_type == VEH_ROAD) ? 0 : (1 << 10));
  1095 					return;
  1086 					return;
  1096 				case VLW_WIDGET_LIST: { /* Matrix to show vehicles */
  1087 				case VLW_WIDGET_LIST: { /* Matrix to show vehicles */
  1097 					uint32 id_v = (e->we.click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / w->resize.step_height;
  1088 					uint32 id_v = (e->we.click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / w->resize.step_height;
  1098 					const Vehicle *v;
  1089 					const Vehicle *v;
  1099 
  1090 
  1100 					if (id_v >= w->vscroll.cap) return; // click out of bounds
  1091 					if (id_v >= w->vscroll.cap) return; // click out of bounds
  1101 
  1092 
  1102 					id_v += w->vscroll.pos;
  1093 					id_v += w->vscroll.pos;
  1103 
  1094 
  1104 					if (id_v >= vl->l.list_length) return; // click out of list bound
  1095 					if (id_v >= vl->vehicles.list_length) return; // click out of list bound
  1105 
  1096 
  1106 					v = vl->sort_list[id_v];
  1097 					v = vl->vehicles.sort_list[id_v];
  1107 
  1098 
  1108 					ShowVehicleViewWindow(v);
  1099 					ShowVehicleViewWindow(v);
  1109 				} break;
  1100 				} break;
  1110 
  1101 
  1111 				case VLW_WIDGET_AVAILABLE_VEHICLES:
  1102 				case VLW_WIDGET_AVAILABLE_VEHICLES:
  1141 		} break;
  1132 		} break;
  1142 
  1133 
  1143 		case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
  1134 		case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
  1144 			switch (e->we.dropdown.button) {
  1135 			switch (e->we.dropdown.button) {
  1145 				case VLW_WIDGET_SORT_BY_PULLDOWN:
  1136 				case VLW_WIDGET_SORT_BY_PULLDOWN:
  1146 					if (vl->l.sort_type != e->we.dropdown.index) {
  1137 					if (vl->vehicles.sort_type != e->we.dropdown.index) {
  1147 						/* value has changed -> resort */
  1138 						/* value has changed -> resort */
  1148 						vl->l.flags |= VL_RESORT;
  1139 						vl->vehicles.flags |= VL_RESORT;
  1149 						vl->l.sort_type = e->we.dropdown.index;
  1140 						vl->vehicles.sort_type = e->we.dropdown.index;
  1150 						vl->_sorting->criteria = vl->l.sort_type;
  1141 						vl->sorting->criteria = vl->vehicles.sort_type;
  1151 					}
  1142 					}
  1152 					break;
  1143 					break;
  1153 				case VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN:
  1144 				case VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN:
  1154 					assert(vl->l.list_length != 0);
  1145 					assert(vl->vehicles.list_length != 0);
  1155 
  1146 
  1156 					switch (e->we.dropdown.index) {
  1147 					switch (e->we.dropdown.index) {
  1157 						case 0: /* Replace window */
  1148 						case 0: /* Replace window */
  1158 							ShowReplaceGroupVehicleWindow(DEFAULT_GROUP, vl->vehicle_type);
  1149 							ShowReplaceGroupVehicleWindow(DEFAULT_GROUP, vl->vehicle_type);
  1159 							break;
  1150 							break;
  1177 			}
  1168 			}
  1178 			w->SetDirty();
  1169 			w->SetDirty();
  1179 			break;
  1170 			break;
  1180 
  1171 
  1181 		case WE_DESTROY:
  1172 		case WE_DESTROY:
  1182 			free((void*)vl->sort_list);
  1173 			free((void*)vl->vehicles.sort_list);
  1183 			break;
  1174 			break;
  1184 
  1175 
  1185 		case WE_TICK: /* resort the list every 20 seconds orso (10 days) */
  1176 		case WE_TICK: /* resort the list every 20 seconds orso (10 days) */
  1186 			if (_pause_game != 0) break;
  1177 			if (_pause_game != 0) break;
  1187 			if (--vl->l.resort_timer == 0) {
  1178 			if (--vl->vehicles.resort_timer == 0) {
  1188 				StationID station = ((w->window_number & VLW_MASK) == VLW_STATION_LIST) ? GB(w->window_number, 16, 16) : INVALID_STATION;
  1179 				StationID station = ((w->window_number & VLW_MASK) == VLW_STATION_LIST) ? GB(w->window_number, 16, 16) : INVALID_STATION;
  1189 				PlayerID owner = (PlayerID)w->caption_color;
  1180 				PlayerID owner = (PlayerID)w->caption_color;
  1190 
  1181 
  1191 				DEBUG(misc, 3, "Periodic resort %d list player %d at station %d", vl->vehicle_type, owner, station);
  1182 				DEBUG(misc, 3, "Periodic resort %d list player %d at station %d", vl->vehicle_type, owner, station);
  1192 				vl->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
  1183 				vl->vehicles.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
  1193 				vl->l.flags |= VL_RESORT;
  1184 				vl->vehicles.flags |= VL_RESORT;
  1194 				w->SetDirty();
  1185 				w->SetDirty();
  1195 			}
  1186 			}
  1196 			break;
  1187 			break;
  1197 
  1188 
  1198 		case WE_RESIZE: /* Update the scroll + matrix */
  1189 		case WE_RESIZE: /* Update the scroll + matrix */