src/autoreplace_gui.cpp
changeset 9174 5d1ba8c43503
parent 9172 4488ce29544f
child 9178 3235f895bf12
equal deleted inserted replaced
9173:b38373e203a9 9174:5d1ba8c43503
    23 #include "engine_base.h"
    23 #include "engine_base.h"
    24 
    24 
    25 #include "table/sprites.h"
    25 #include "table/sprites.h"
    26 #include "table/strings.h"
    26 #include "table/strings.h"
    27 
    27 
    28 struct replaceveh_d {
    28 void DrawEngineList(VehicleType type, int x, int y, const EngineList eng_list, uint16 min, uint16 max, EngineID selected_id, int count_location, GroupID selected_group);
    29 	byte sel_index[2];
       
    30 	EngineID sel_engine[2];
       
    31 	uint16 count[2];
       
    32 	bool wagon_btnstate; ///< true means engine is selected
       
    33 	EngineList list[2];
       
    34 	bool update_left;
       
    35 	bool update_right;
       
    36 	bool init_lists;
       
    37 	GroupID sel_group;
       
    38 };
       
    39 assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(replaceveh_d));
       
    40 
       
    41 static RailType _railtype_selected_in_replace_gui;
       
    42 
    29 
    43 static const StringID _rail_types_list[] = {
    30 static const StringID _rail_types_list[] = {
    44 	STR_RAIL_VEHICLES,
    31 	STR_RAIL_VEHICLES,
    45 	STR_ELRAIL_VEHICLES,
    32 	STR_ELRAIL_VEHICLES,
    46 	STR_MONORAIL_VEHICLES,
    33 	STR_MONORAIL_VEHICLES,
    75 	const EngineID va = *(const EngineID*)a;
    62 	const EngineID va = *(const EngineID*)a;
    76 	const EngineID vb = *(const EngineID*)b;
    63 	const EngineID vb = *(const EngineID*)b;
    77 	int r = ListPositionOfEngine(va) - ListPositionOfEngine(vb);
    64 	int r = ListPositionOfEngine(va) - ListPositionOfEngine(vb);
    78 
    65 
    79 	return r;
    66 	return r;
    80 }
       
    81 
       
    82 /* General Vehicle GUI based procedures that are independent of vehicle types */
       
    83 void InitializeVehiclesGuiList()
       
    84 {
       
    85 	_railtype_selected_in_replace_gui = RAILTYPE_RAIL;
       
    86 }
    67 }
    87 
    68 
    88 /** Rebuild the left autoreplace list if an engine is removed or added
    69 /** Rebuild the left autoreplace list if an engine is removed or added
    89  * @param e Engine to check if it is removed or added
    70  * @param e Engine to check if it is removed or added
    90  * @param id_g The group the engine belongs to
    71  * @param id_g The group the engine belongs to
   132 		case VEH_SHIP:       return ShipVehInfo(engine)->cargo_type;
   113 		case VEH_SHIP:       return ShipVehInfo(engine)->cargo_type;
   133 		case VEH_AIRCRAFT:   return CT_PASSENGERS; // all planes are build with passengers by default
   114 		case VEH_AIRCRAFT:   return CT_PASSENGERS; // all planes are build with passengers by default
   134 	}
   115 	}
   135 }
   116 }
   136 
   117 
   137 /** Figure out if an engine should be added to a list
       
   138  * @param e The EngineID
       
   139  * @param draw_left If true, then the left list is drawn (the engines specific to the railtype you selected)
       
   140  * @param show_engines if truem then locomotives are drawn, else wagons (never both)
       
   141  * @return true if the engine should be in the list (based on this check)
       
   142  */
       
   143 static bool GenerateReplaceRailList(EngineID e, bool draw_left, bool show_engines)
       
   144 {
       
   145 	const RailVehicleInfo *rvi = RailVehInfo(e);
       
   146 
       
   147 	/* Ensure that the wagon/engine selection fits the engine. */
       
   148 	if ((rvi->railveh_type == RAILVEH_WAGON) == show_engines) return false;
       
   149 
       
   150 	if (draw_left && show_engines) {
       
   151 		/* Ensure that the railtype is specific to the selected one */
       
   152 		if (rvi->railtype != _railtype_selected_in_replace_gui) return false;
       
   153 	} else {
       
   154 		/* Ensure that it's a compatible railtype to the selected one (like electric <-> diesel)
       
   155 		 * The vehicle do not have to have power on the railtype in question, only able to drive (pulled if needed) */
       
   156 		if (!IsCompatibleRail(rvi->railtype, _railtype_selected_in_replace_gui)) return false;
       
   157 	}
       
   158 	return true;
       
   159 }
       
   160 
       
   161 /** Figure out if two engines got at least one type of cargo in common (refitting if needed)
   118 /** Figure out if two engines got at least one type of cargo in common (refitting if needed)
   162  * @param engine_a one of the EngineIDs
   119  * @param engine_a one of the EngineIDs
   163  * @param engine_b the other EngineID
   120  * @param engine_b the other EngineID
   164  * @return true if they can both carry the same type of cargo (or at least one of them got no capacity at all)
   121  * @return true if they can both carry the same type of cargo (or at least one of them got no capacity at all)
   165  */
   122  */
   174 	if (EngInfo(engine_a)->refit_mask & EngInfo(engine_b)->refit_mask) return true; // both can refit to the same
   131 	if (EngInfo(engine_a)->refit_mask & EngInfo(engine_b)->refit_mask) return true; // both can refit to the same
   175 	if (CanRefitTo(engine_a, b) || CanRefitTo(engine_b, a)) return true; // one can refit to what the other one carries
   132 	if (CanRefitTo(engine_a, b) || CanRefitTo(engine_b, a)) return true; // one can refit to what the other one carries
   176 	return false;
   133 	return false;
   177 }
   134 }
   178 
   135 
   179 /** Generate a list
   136 /**
   180  * @param w Window, that contains the list
   137  * Window for the autoreplacing of vehicles.
   181  * @param draw_left true if generating the left list, otherwise false
       
   182  */
   138  */
   183 static void GenerateReplaceVehList(Window *w, bool draw_left)
   139 class ReplaceVehicleWindow : public Window {
   184 {
   140 	byte sel_index[2];
   185 	EngineID selected_engine = INVALID_ENGINE;
   141 	EngineID sel_engine[2];
   186 	VehicleType type = (VehicleType)w->window_number;
   142 	uint16 count[2];
   187 	byte i = draw_left ? 0 : 1;
   143 	bool wagon_btnstate; ///< true means engine is selected
   188 
   144 	EngineList list[2];
   189 	EngineList *list = &WP(w, replaceveh_d).list[i];
   145 	bool update_left;
   190 	list->clear();
   146 	bool update_right;
   191 
   147 	bool init_lists;
   192 	const Engine *e;
   148 	GroupID sel_group;
   193 	FOR_ALL_ENGINES_OF_TYPE(e, type) {
   149 	static RailType sel_railtype;
   194 		EngineID eid = e->index;
   150 
   195 		if (type == VEH_TRAIN && !GenerateReplaceRailList(eid, draw_left, WP(w, replaceveh_d).wagon_btnstate)) continue; // special rules for trains
   151 	/** Figure out if an engine should be added to a list
   196 
   152 	 * @param e The EngineID
   197 		if (draw_left) {
   153 	 * @param draw_left If true, then the left list is drawn (the engines specific to the railtype you selected)
   198 			const GroupID selected_group = WP(w, replaceveh_d).sel_group;
   154 	 * @param show_engines if truem then locomotives are drawn, else wagons (never both)
   199 			const uint num_engines = GetGroupNumEngines(_local_player, selected_group, eid);
   155 	 * @return true if the engine should be in the list (based on this check)
   200 
   156 	 */
   201 			/* Skip drawing the engines we don't have any of and haven't set for replacement */
   157 	bool GenerateReplaceRailList(EngineID e, bool draw_left, bool show_engines)
   202 			if (num_engines == 0 && EngineReplacementForPlayer(GetPlayer(_local_player), eid, selected_group) == INVALID_ENGINE) continue;
   158 	{
       
   159 		const RailVehicleInfo *rvi = RailVehInfo(e);
       
   160 
       
   161 		/* Ensure that the wagon/engine selection fits the engine. */
       
   162 		if ((rvi->railveh_type == RAILVEH_WAGON) == show_engines) return false;
       
   163 
       
   164 		if (draw_left && show_engines) {
       
   165 			/* Ensure that the railtype is specific to the selected one */
       
   166 			if (rvi->railtype != this->sel_railtype) return false;
   203 		} else {
   167 		} else {
   204 			/* This is for engines we can replace to and they should depend on what we selected to replace from */
   168 			/* Ensure that it's a compatible railtype to the selected one (like electric <-> diesel)
   205 			if (!IsEngineBuildable(eid, type, _local_player)) continue; // we need to be able to build the engine
   169 			 * The vehicle do not have to have power on the railtype in question, only able to drive (pulled if needed) */
   206 			if (!EnginesGotCargoInCommon(eid, WP(w, replaceveh_d).sel_engine[0])) continue; // the engines needs to be able to carry the same cargo
   170 			if (!IsCompatibleRail(rvi->railtype, this->sel_railtype)) return false;
   207 
   171 		}
   208 			/* Road vehicles can't be replaced by trams and vice-versa */
   172 		return true;
   209 			if (type == VEH_ROAD && HasBit(EngInfo(WP(w, replaceveh_d).sel_engine[0])->misc_flags, EF_ROAD_TRAM) != HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue;
   173 	}
   210 			if (eid == WP(w, replaceveh_d).sel_engine[0]) continue; // we can't replace an engine into itself (that would be autorenew)
   174 
   211 		}
   175 
   212 
   176 	/** Generate a list
   213 		list->push_back(eid);
   177 	 * @param w Window, that contains the list
   214 		if (eid == WP(w, replaceveh_d).sel_engine[i]) selected_engine = eid; // The selected engine is still in the list
   178 	 * @param draw_left true if generating the left list, otherwise false
   215 	}
   179 	 */
   216 	WP(w, replaceveh_d).sel_engine[i] = selected_engine; // update which engine we selected (the same or none, if it's not in the list anymore)
   180 	void GenerateReplaceVehList(Window *w, bool draw_left)
   217 	if (type == VEH_TRAIN) EngList_Sort(list, &TrainEngineNumberSorter);
   181 	{
   218 }
   182 		EngineID selected_engine = INVALID_ENGINE;
   219 
   183 		VehicleType type = (VehicleType)this->window_number;
   220 /** Generate the lists
   184 		byte i = draw_left ? 0 : 1;
   221  * @param w Window containing the lists
   185 
   222  */
   186 		EngineList *list = &this->list[i];
   223 static void GenerateLists(Window *w)
   187 		list->clear();
   224 {
   188 
   225 	EngineID e = WP(w, replaceveh_d).sel_engine[0];
   189 		const Engine *e;
   226 
   190 		FOR_ALL_ENGINES_OF_TYPE(e, type) {
   227 	if (WP(w, replaceveh_d).update_left == true) {
   191 			EngineID eid = e->index;
   228 		/* We need to rebuild the left list */
   192 			if (type == VEH_TRAIN && !GenerateReplaceRailList(eid, draw_left, this->wagon_btnstate)) continue; // special rules for trains
   229 		GenerateReplaceVehList(w, true);
   193 
   230 		SetVScrollCount(w, WP(w, replaceveh_d).list[0].size());
   194 			if (draw_left) {
   231 		if (WP(w, replaceveh_d).init_lists && WP(w, replaceveh_d).sel_engine[0] == INVALID_ENGINE && WP(w, replaceveh_d).list[0].size() != 0) {
   195 				const GroupID selected_group = this->sel_group;
   232 			WP(w, replaceveh_d).sel_engine[0] = WP(w, replaceveh_d).list[0][0];
   196 				const uint num_engines = GetGroupNumEngines(_local_player, selected_group, eid);
   233 		}
   197 
   234 	}
   198 				/* Skip drawing the engines we don't have any of and haven't set for replacement */
   235 
   199 				if (num_engines == 0 && EngineReplacementForPlayer(GetPlayer(_local_player), eid, selected_group) == INVALID_ENGINE) continue;
   236 	if (WP(w, replaceveh_d).update_right || e != WP(w, replaceveh_d).sel_engine[0]) {
   200 			} else {
   237 		/* Either we got a request to rebuild the right list or the left list selected a different engine */
   201 				/* This is for engines we can replace to and they should depend on what we selected to replace from */
   238 		if (WP(w, replaceveh_d).sel_engine[0] == INVALID_ENGINE) {
   202 				if (!IsEngineBuildable(eid, type, _local_player)) continue; // we need to be able to build the engine
   239 			/* Always empty the right list when nothing is selected in the left list */
   203 				if (!EnginesGotCargoInCommon(eid, this->sel_engine[0])) continue; // the engines needs to be able to carry the same cargo
   240 			WP(w, replaceveh_d).list[1].clear();
   204 
   241 			WP(w, replaceveh_d).sel_engine[1] = INVALID_ENGINE;
   205 				/* Road vehicles can't be replaced by trams and vice-versa */
   242 		} else {
   206 				if (type == VEH_ROAD && HasBit(EngInfo(this->sel_engine[0])->misc_flags, EF_ROAD_TRAM) != HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue;
   243 			GenerateReplaceVehList(w, false);
   207 				if (eid == this->sel_engine[0]) continue; // we can't replace an engine into itself (that would be autorenew)
   244 			SetVScroll2Count(w, WP(w, replaceveh_d).list[1].size());
       
   245 			if (WP(w, replaceveh_d).init_lists && WP(w, replaceveh_d).sel_engine[1] == INVALID_ENGINE && WP(w, replaceveh_d).list[1].size() != 0) {
       
   246 				WP(w, replaceveh_d).sel_engine[1] = WP(w, replaceveh_d).list[1][0];
       
   247 			}
   208 			}
   248 		}
   209 
   249 	}
   210 			list->push_back(eid);
   250 	/* Reset the flags about needed updates */
   211 			if (eid == this->sel_engine[i]) selected_engine = eid; // The selected engine is still in the list
   251 	WP(w, replaceveh_d).update_left  = false;
   212 		}
   252 	WP(w, replaceveh_d).update_right = false;
   213 		this->sel_engine[i] = selected_engine; // update which engine we selected (the same or none, if it's not in the list anymore)
   253 	WP(w, replaceveh_d).init_lists   = false;
   214 		if (type == VEH_TRAIN) EngList_Sort(list, &TrainEngineNumberSorter);
   254 }
   215 	}
   255 
   216 
   256 
   217 	/** Generate the lists */
   257 void DrawEngineList(VehicleType type, int x, int y, const EngineList eng_list, uint16 min, uint16 max, EngineID selected_id, int count_location, GroupID selected_group);
   218 	void GenerateLists()
   258 
   219 	{
   259 static void ReplaceVehicleWndProc(Window *w, WindowEvent *e)
   220 		EngineID e = this->sel_engine[0];
   260 {
   221 
   261 	/* Strings for the pulldown menu */
   222 		if (this->update_left == true) {
   262 	static const StringID _vehicle_type_names[] = {
   223 			/* We need to rebuild the left list */
   263 		STR_019F_TRAIN,
   224 			GenerateReplaceVehList(this, true);
   264 		STR_019C_ROAD_VEHICLE,
   225 			SetVScrollCount(this, this->list[0].size());
   265 		STR_019E_SHIP,
   226 			if (this->init_lists && this->sel_engine[0] == INVALID_ENGINE && this->list[0].size() != 0) {
   266 		STR_019D_AIRCRAFT
   227 				this->sel_engine[0] = this->list[0][0];
   267 	};
       
   268 
       
   269 	switch (e->event) {
       
   270 		case WE_CREATE:
       
   271 			WP(w, replaceveh_d).wagon_btnstate = true; // start with locomotives (all other vehicles will not read this bool)
       
   272 			new (&WP(w, replaceveh_d).list[0]) EngineList();
       
   273 			new (&WP(w, replaceveh_d).list[1]) EngineList();
       
   274 			WP(w, replaceveh_d).update_left   = true;
       
   275 			WP(w, replaceveh_d).update_right  = true;
       
   276 			WP(w, replaceveh_d).init_lists    = true;
       
   277 			WP(w, replaceveh_d).sel_engine[0] = INVALID_ENGINE;
       
   278 			WP(w, replaceveh_d).sel_engine[1] = INVALID_ENGINE;
       
   279 			break;
       
   280 
       
   281 		case WE_PAINT: {
       
   282 			if (WP(w, replaceveh_d).update_left || WP(w, replaceveh_d).update_right) GenerateLists(w);
       
   283 
       
   284 			Player *p = GetPlayer(_local_player);
       
   285 			EngineID selected_id[2];
       
   286 			const GroupID selected_group = WP(w, replaceveh_d).sel_group;
       
   287 
       
   288 			selected_id[0] = WP(w, replaceveh_d).sel_engine[0];
       
   289 			selected_id[1] = WP(w, replaceveh_d).sel_engine[1];
       
   290 
       
   291 			/* Disable the "Start Replacing" button if:
       
   292 			 *    Either list is empty
       
   293 			 * or The selected replacement engine has a replacement (to prevent loops)
       
   294 			 * or The right list (new replacement) has the existing replacement vehicle selected */
       
   295 			w->SetWidgetDisabledState(RVW_WIDGET_START_REPLACE,
       
   296 										 selected_id[0] == INVALID_ENGINE ||
       
   297 										 selected_id[1] == INVALID_ENGINE ||
       
   298 										 EngineReplacementForPlayer(p, selected_id[1], selected_group) != INVALID_ENGINE ||
       
   299 										 EngineReplacementForPlayer(p, selected_id[0], selected_group) == selected_id[1]);
       
   300 
       
   301 			/* Disable the "Stop Replacing" button if:
       
   302 			 *   The left list (existing vehicle) is empty
       
   303 			 *   or The selected vehicle has no replacement set up */
       
   304 			w->SetWidgetDisabledState(RVW_WIDGET_STOP_REPLACE,
       
   305 										 selected_id[0] == INVALID_ENGINE ||
       
   306 										 !EngineHasReplacementForPlayer(p, selected_id[0], selected_group));
       
   307 
       
   308 			/* now the actual drawing of the window itself takes place */
       
   309 			SetDParam(0, _vehicle_type_names[w->window_number]);
       
   310 
       
   311 			if (w->window_number == VEH_TRAIN) {
       
   312 				/* set on/off for renew_keep_length */
       
   313 				SetDParam(1, p->renew_keep_length ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
       
   314 
       
   315 				/* set wagon/engine button */
       
   316 				SetDParam(2, WP(w, replaceveh_d).wagon_btnstate ? STR_ENGINES : STR_WAGONS);
       
   317 
       
   318 				/* sets the colour of that art thing */
       
   319 				w->widget[RVW_WIDGET_TRAIN_FLUFF_LEFT].color  = _player_colors[_local_player];
       
   320 				w->widget[RVW_WIDGET_TRAIN_FLUFF_RIGHT].color = _player_colors[_local_player];
       
   321 			}
   228 			}
   322 
   229 		}
   323 			if (w->window_number == VEH_TRAIN) {
   230 
   324 				/* Show the selected railtype in the pulldown menu */
   231 		if (this->update_right || e != this->sel_engine[0]) {
   325 				RailType railtype = _railtype_selected_in_replace_gui;
   232 			/* Either we got a request to rebuild the right list or the left list selected a different engine */
   326 				w->widget[RVW_WIDGET_TRAIN_RAILTYPE_DROPDOWN].data = _rail_types_list[railtype];
   233 			if (this->sel_engine[0] == INVALID_ENGINE) {
   327 			}
   234 				/* Always empty the right list when nothing is selected in the left list */
   328 
   235 				this->list[1].clear();
   329 			DrawWindowWidgets(w);
   236 				this->sel_engine[1] = INVALID_ENGINE;
   330 
       
   331 			/* sets up the string for the vehicle that is being replaced to */
       
   332 			if (selected_id[0] != INVALID_ENGINE) {
       
   333 				if (!EngineHasReplacementForPlayer(p, selected_id[0], selected_group)) {
       
   334 					SetDParam(0, STR_NOT_REPLACING);
       
   335 				} else {
       
   336 					SetDParam(0, STR_ENGINE_NAME);
       
   337 					SetDParam(1, EngineReplacementForPlayer(p, selected_id[0], selected_group));
       
   338 				}
       
   339 			} else {
   237 			} else {
   340 				SetDParam(0, STR_NOT_REPLACING_VEHICLE_SELECTED);
   238 				GenerateReplaceVehList(this, false);
   341 			}
   239 				SetVScroll2Count(this, this->list[1].size());
   342 
   240 				if (this->init_lists && this->sel_engine[1] == INVALID_ENGINE && this->list[1].size() != 0) {
   343 			DrawString(145, w->widget[RVW_WIDGET_INFO_TAB].top + 1, STR_02BD, TC_BLACK);
   241 					this->sel_engine[1] = this->list[1][0];
   344 
       
   345 			/* Draw the lists */
       
   346 			for(byte i = 0; i < 2; i++) {
       
   347 				uint widget     = (i == 0) ? RVW_WIDGET_LEFT_MATRIX : RVW_WIDGET_RIGHT_MATRIX;
       
   348 				EngineList list = WP(w, replaceveh_d).list[i]; // which list to draw
       
   349 				EngineID start  = i == 0 ? w->vscroll.pos : w->vscroll2.pos; // what is the offset for the start (scrolling)
       
   350 				EngineID end    = min((i == 0 ? w->vscroll.cap : w->vscroll2.cap) + start, list.size());
       
   351 
       
   352 				/* Do the actual drawing */
       
   353 				DrawEngineList((VehicleType)w->window_number, w->widget[widget].left + 2, w->widget[widget].top + 1, list, start, end, WP(w, replaceveh_d).sel_engine[i], i == 0 ? w->widget[RVW_WIDGET_LEFT_MATRIX].right - 2 : 0, selected_group);
       
   354 
       
   355 				/* Also draw the details if an engine is selected */
       
   356 				if (WP(w, replaceveh_d).sel_engine[i] != INVALID_ENGINE) {
       
   357 					const Widget *wi = &w->widget[i == 0 ? RVW_WIDGET_LEFT_DETAILS : RVW_WIDGET_RIGHT_DETAILS];
       
   358 					int text_end = DrawVehiclePurchaseInfo(wi->left + 2, wi->top + 1, wi->right - wi->left - 2, WP(w, replaceveh_d).sel_engine[i]);
       
   359 
       
   360 					if (text_end > wi->bottom) {
       
   361 						w->SetDirty();
       
   362 						ResizeWindowForWidget(w, i == 0 ? RVW_WIDGET_LEFT_DETAILS : RVW_WIDGET_RIGHT_DETAILS, 0, text_end - wi->bottom);
       
   363 						w->SetDirty();
       
   364 					}
       
   365 				}
   242 				}
   366 			}
   243 			}
   367 
   244 		}
   368 		} break;   // end of paint
   245 		/* Reset the flags about needed updates */
   369 
   246 		this->update_left  = false;
   370 		case WE_CLICK: {
   247 		this->update_right = false;
   371 			switch (e->we.click.widget) {
   248 		this->init_lists   = false;
   372 				case RVW_WIDGET_TRAIN_ENGINEWAGON_TOGGLE:
   249 	}
   373 					WP(w, replaceveh_d).wagon_btnstate = !(WP(w, replaceveh_d).wagon_btnstate);
   250 
   374 					WP(w, replaceveh_d).update_left = true;
   251 public:
   375 					WP(w, replaceveh_d).init_lists  = true;
   252 	ReplaceVehicleWindow(const WindowDesc *desc, VehicleType vehicletype, GroupID id_g) : Window(desc, NULL, window_number)
   376 					w->SetDirty();
   253 	{
   377 					break;
   254 		this->wagon_btnstate = true; // start with locomotives (all other vehicles will not read this bool)
   378 
   255 		new (&this->list[0]) EngineList();
   379 				case RVW_WIDGET_TRAIN_RAILTYPE_DROPDOWN: /* Railtype selection dropdown menu */
   256 		new (&this->list[1]) EngineList();
   380 					ShowDropDownMenu(w, _rail_types_list, _railtype_selected_in_replace_gui, RVW_WIDGET_TRAIN_RAILTYPE_DROPDOWN, 0, ~GetPlayer(_local_player)->avail_railtypes);
   257 		this->update_left   = true;
   381 					break;
   258 		this->update_right  = true;
   382 
   259 		this->init_lists    = true;
   383 				case RVW_WIDGET_TRAIN_WAGONREMOVE_TOGGLE: /* toggle renew_keep_length */
   260 		this->sel_engine[0] = INVALID_ENGINE;
   384 					DoCommandP(0, 5, GetPlayer(_local_player)->renew_keep_length ? 0 : 1, NULL, CMD_SET_AUTOREPLACE);
   261 		this->sel_engine[1] = INVALID_ENGINE;
   385 					break;
   262 
   386 
   263 		this->resize.step_height = GetVehicleListHeight(vehicletype);
   387 				case RVW_WIDGET_START_REPLACE: { /* Start replacing */
   264 		this->vscroll.cap = this->resize.step_height == 14 ? 8 : 4;
   388 					EngineID veh_from = WP(w, replaceveh_d).sel_engine[0];
   265 
   389 					EngineID veh_to = WP(w, replaceveh_d).sel_engine[1];
   266 		Widget *widget = this->widget;
   390 					DoCommandP(0, 3 + (WP(w, replaceveh_d).sel_group << 16) , veh_from + (veh_to << 16), NULL, CMD_SET_AUTOREPLACE);
   267 		widget[RVW_WIDGET_LEFT_MATRIX].data = widget[RVW_WIDGET_RIGHT_MATRIX].data = (this->vscroll.cap << 8) + 1;
   391 				} break;
   268 
   392 
   269 		if (vehicletype == VEH_TRAIN) {
   393 				case RVW_WIDGET_STOP_REPLACE: { /* Stop replacing */
   270 			this->wagon_btnstate = true;
   394 					EngineID veh_from = WP(w, replaceveh_d).sel_engine[0];
   271 			/* The train window is bigger so we will move some of the widgets to fit the new size.
   395 					DoCommandP(0, 3 + (WP(w, replaceveh_d).sel_group << 16), veh_from + (INVALID_ENGINE << 16), NULL, CMD_SET_AUTOREPLACE);
   272 			* We will start by moving the resize button to the lower right corner.                 */
   396 				} break;
   273 			widget[RVW_WIDGET_RESIZE].top         = widget[RVW_WIDGET_TRAIN_ENGINEWAGON_TOGGLE].top;
   397 
   274 			widget[RVW_WIDGET_RESIZE].bottom      = widget[RVW_WIDGET_TRAIN_ENGINEWAGON_TOGGLE].bottom;
   398 				case RVW_WIDGET_LEFT_MATRIX:
   275 			widget[RVW_WIDGET_STOP_REPLACE].right = widget[RVW_WIDGET_RESIZE].right;
   399 				case RVW_WIDGET_RIGHT_MATRIX: {
   276 
   400 					uint i = (e->we.click.pt.y - 14) / w->resize.step_height;
   277 			/* The detail panel is one line taller for trains so we will move some of the widgets one line (10 pixels) down. */
   401 					uint16 click_scroll_pos = e->we.click.widget == RVW_WIDGET_LEFT_MATRIX ? w->vscroll.pos : w->vscroll2.pos;
   278 			widget[RVW_WIDGET_LEFT_DETAILS].bottom  += 10;
   402 					uint16 click_scroll_cap = e->we.click.widget == RVW_WIDGET_LEFT_MATRIX ? w->vscroll.cap : w->vscroll2.cap;
   279 			widget[RVW_WIDGET_RIGHT_DETAILS].bottom += 10;
   403 					byte click_side         = e->we.click.widget == RVW_WIDGET_LEFT_MATRIX ? 0 : 1;
   280 			for (int i = RVW_WIDGET_START_REPLACE; i < RVW_WIDGET_RESIZE; i++) {
   404 					size_t engine_count     = WP(w, replaceveh_d).list[click_side].size();
   281 				widget[i].top    += 10;
   405 
   282 				widget[i].bottom += 10;
   406 					if (i < click_scroll_cap) {
   283 			}
   407 						i += click_scroll_pos;
   284 		} else {
   408 						EngineID e = engine_count > i ? WP(w, replaceveh_d).list[click_side][i] : INVALID_ENGINE;
   285 			/* Since it's not a train we will hide the train only widgets. */
   409 						if (e == WP(w, replaceveh_d).sel_engine[click_side]) break; // we clicked the one we already selected
   286 			this->SetWidgetsHiddenState(true,
   410 						WP(w, replaceveh_d).sel_engine[click_side] = e;
   287 									RVW_WIDGET_TRAIN_ENGINEWAGON_TOGGLE,
   411 						if (click_side == 0) {
   288 									RVW_WIDGET_TRAIN_FLUFF_LEFT,
   412 							WP(w, replaceveh_d).update_right = true;
   289 									RVW_WIDGET_TRAIN_RAILTYPE_DROPDOWN,
   413 							WP(w, replaceveh_d).init_lists   = true;
   290 									RVW_WIDGET_TRAIN_FLUFF_RIGHT,
   414 						}
   291 									RVW_WIDGET_TRAIN_WAGONREMOVE_TOGGLE,
   415 						w->SetDirty();
   292 									WIDGET_LIST_END);
   416 						}
   293 		}
   417 					break;
   294 
       
   295 		ResizeWindow(this, 0, this->resize.step_height * this->vscroll.cap);
       
   296 
       
   297 		/* Set the minimum window size to the current window size */
       
   298 		this->resize.width  = this->width;
       
   299 		this->resize.height = this->height;
       
   300 
       
   301 		this->caption_color = _local_player;
       
   302 		this->sel_group = id_g;
       
   303 		this->vscroll2.cap = this->vscroll.cap;   // these two are always the same
       
   304 	}
       
   305 
       
   306 	virtual void OnPaint()
       
   307 	{
       
   308 		static const StringID _vehicle_type_names[] = {
       
   309 			STR_019F_TRAIN,
       
   310 			STR_019C_ROAD_VEHICLE,
       
   311 			STR_019E_SHIP,
       
   312 			STR_019D_AIRCRAFT
       
   313 		};
       
   314 
       
   315 		if (this->update_left || this->update_right) this->GenerateLists();
       
   316 
       
   317 		Player *p = GetPlayer(_local_player);
       
   318 		EngineID selected_id[2];
       
   319 		const GroupID selected_group = this->sel_group;
       
   320 
       
   321 		selected_id[0] = this->sel_engine[0];
       
   322 		selected_id[1] = this->sel_engine[1];
       
   323 
       
   324 		/* Disable the "Start Replacing" button if:
       
   325 		 *    Either list is empty
       
   326 		 * or The selected replacement engine has a replacement (to prevent loops)
       
   327 		 * or The right list (new replacement) has the existing replacement vehicle selected */
       
   328 		this->SetWidgetDisabledState(RVW_WIDGET_START_REPLACE,
       
   329 										selected_id[0] == INVALID_ENGINE ||
       
   330 										selected_id[1] == INVALID_ENGINE ||
       
   331 										EngineReplacementForPlayer(p, selected_id[1], selected_group) != INVALID_ENGINE ||
       
   332 										EngineReplacementForPlayer(p, selected_id[0], selected_group) == selected_id[1]);
       
   333 
       
   334 		/* Disable the "Stop Replacing" button if:
       
   335 		 *   The left list (existing vehicle) is empty
       
   336 		 *   or The selected vehicle has no replacement set up */
       
   337 		this->SetWidgetDisabledState(RVW_WIDGET_STOP_REPLACE,
       
   338 										selected_id[0] == INVALID_ENGINE ||
       
   339 										!EngineHasReplacementForPlayer(p, selected_id[0], selected_group));
       
   340 
       
   341 		/* now the actual drawing of the window itself takes place */
       
   342 		SetDParam(0, _vehicle_type_names[this->window_number]);
       
   343 
       
   344 		if (this->window_number == VEH_TRAIN) {
       
   345 			/* set on/off for renew_keep_length */
       
   346 			SetDParam(1, p->renew_keep_length ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
       
   347 
       
   348 			/* set wagon/engine button */
       
   349 			SetDParam(2, this->wagon_btnstate ? STR_ENGINES : STR_WAGONS);
       
   350 
       
   351 			/* sets the colour of that art thing */
       
   352 			this->widget[RVW_WIDGET_TRAIN_FLUFF_LEFT].color  = _player_colors[_local_player];
       
   353 			this->widget[RVW_WIDGET_TRAIN_FLUFF_RIGHT].color = _player_colors[_local_player];
       
   354 		}
       
   355 
       
   356 		if (this->window_number == VEH_TRAIN) {
       
   357 			/* Show the selected railtype in the pulldown menu */
       
   358 			this->widget[RVW_WIDGET_TRAIN_RAILTYPE_DROPDOWN].data = _rail_types_list[sel_railtype];
       
   359 		}
       
   360 
       
   361 		DrawWindowWidgets(this);
       
   362 
       
   363 		/* sets up the string for the vehicle that is being replaced to */
       
   364 		if (selected_id[0] != INVALID_ENGINE) {
       
   365 			if (!EngineHasReplacementForPlayer(p, selected_id[0], selected_group)) {
       
   366 				SetDParam(0, STR_NOT_REPLACING);
       
   367 			} else {
       
   368 				SetDParam(0, STR_ENGINE_NAME);
       
   369 				SetDParam(1, EngineReplacementForPlayer(p, selected_id[0], selected_group));
       
   370 			}
       
   371 		} else {
       
   372 			SetDParam(0, STR_NOT_REPLACING_VEHICLE_SELECTED);
       
   373 		}
       
   374 
       
   375 		DrawString(145, this->widget[RVW_WIDGET_INFO_TAB].top + 1, STR_02BD, TC_BLACK);
       
   376 
       
   377 		/* Draw the lists */
       
   378 		for (byte i = 0; i < 2; i++) {
       
   379 			uint widget     = (i == 0) ? RVW_WIDGET_LEFT_MATRIX : RVW_WIDGET_RIGHT_MATRIX;
       
   380 			EngineList list = this->list[i]; // which list to draw
       
   381 			EngineID start  = i == 0 ? this->vscroll.pos : this->vscroll2.pos; // what is the offset for the start (scrolling)
       
   382 			EngineID end    = min((i == 0 ? this->vscroll.cap : this->vscroll2.cap) + start, list.size());
       
   383 
       
   384 			/* Do the actual drawing */
       
   385 			DrawEngineList((VehicleType)this->window_number, this->widget[widget].left + 2, this->widget[widget].top + 1, list, start, end, this->sel_engine[i], i == 0 ? this->widget[RVW_WIDGET_LEFT_MATRIX].right - 2 : 0, selected_group);
       
   386 
       
   387 			/* Also draw the details if an engine is selected */
       
   388 			if (this->sel_engine[i] != INVALID_ENGINE) {
       
   389 				const Widget *wi = &this->widget[i == 0 ? RVW_WIDGET_LEFT_DETAILS : RVW_WIDGET_RIGHT_DETAILS];
       
   390 				int text_end = DrawVehiclePurchaseInfo(wi->left + 2, wi->top + 1, wi->right - wi->left - 2, this->sel_engine[i]);
       
   391 
       
   392 				if (text_end > wi->bottom) {
       
   393 					this->SetDirty();
       
   394 					ResizeWindowForWidget(this, i == 0 ? RVW_WIDGET_LEFT_DETAILS : RVW_WIDGET_RIGHT_DETAILS, 0, text_end - wi->bottom);
       
   395 					this->SetDirty();
       
   396 				}
       
   397 			}
       
   398 		}
       
   399 	}
       
   400 
       
   401 	virtual void OnClick(Point pt, int widget)
       
   402 	{
       
   403 		switch (widget) {
       
   404 			case RVW_WIDGET_TRAIN_ENGINEWAGON_TOGGLE:
       
   405 				this->wagon_btnstate = !(this->wagon_btnstate);
       
   406 				this->update_left = true;
       
   407 				this->init_lists  = true;
       
   408 				this->SetDirty();
       
   409 				break;
       
   410 
       
   411 			case RVW_WIDGET_TRAIN_RAILTYPE_DROPDOWN: /* Railtype selection dropdown menu */
       
   412 				ShowDropDownMenu(this, _rail_types_list, sel_railtype, RVW_WIDGET_TRAIN_RAILTYPE_DROPDOWN, 0, ~GetPlayer(_local_player)->avail_railtypes);
       
   413 				break;
       
   414 
       
   415 			case RVW_WIDGET_TRAIN_WAGONREMOVE_TOGGLE: /* toggle renew_keep_length */
       
   416 				DoCommandP(0, 5, GetPlayer(_local_player)->renew_keep_length ? 0 : 1, NULL, CMD_SET_AUTOREPLACE);
       
   417 				break;
       
   418 
       
   419 			case RVW_WIDGET_START_REPLACE: { /* Start replacing */
       
   420 				EngineID veh_from = this->sel_engine[0];
       
   421 				EngineID veh_to = this->sel_engine[1];
       
   422 				DoCommandP(0, 3 + (this->sel_group << 16) , veh_from + (veh_to << 16), NULL, CMD_SET_AUTOREPLACE);
       
   423 			} break;
       
   424 
       
   425 			case RVW_WIDGET_STOP_REPLACE: { /* Stop replacing */
       
   426 				EngineID veh_from = this->sel_engine[0];
       
   427 				DoCommandP(0, 3 + (this->sel_group << 16), veh_from + (INVALID_ENGINE << 16), NULL, CMD_SET_AUTOREPLACE);
       
   428 			} break;
       
   429 
       
   430 			case RVW_WIDGET_LEFT_MATRIX:
       
   431 			case RVW_WIDGET_RIGHT_MATRIX: {
       
   432 				uint i = (pt.y - 14) / this->resize.step_height;
       
   433 				uint16 click_scroll_pos = widget == RVW_WIDGET_LEFT_MATRIX ? this->vscroll.pos : this->vscroll2.pos;
       
   434 				uint16 click_scroll_cap = widget == RVW_WIDGET_LEFT_MATRIX ? this->vscroll.cap : this->vscroll2.cap;
       
   435 				byte click_side         = widget == RVW_WIDGET_LEFT_MATRIX ? 0 : 1;
       
   436 				size_t engine_count     = this->list[click_side].size();
       
   437 
       
   438 				if (i < click_scroll_cap) {
       
   439 					i += click_scroll_pos;
       
   440 					EngineID e = engine_count > i ? this->list[click_side][i] : INVALID_ENGINE;
       
   441 					if (e == this->sel_engine[click_side]) break; // we clicked the one we already selected
       
   442 					this->sel_engine[click_side] = e;
       
   443 					if (click_side == 0) {
       
   444 						this->update_right = true;
       
   445 						this->init_lists   = true;
   418 					}
   446 					}
   419 			}
   447 					this->SetDirty();
   420 			break;
   448 					}
   421 		}
   449 				break;
   422 
   450 				}
   423 		case WE_DROPDOWN_SELECT: { /* we have selected a dropdown item in the list */
   451 		}
   424 			RailType temp = (RailType)e->we.dropdown.index;
   452 	}
   425 			if (temp == _railtype_selected_in_replace_gui) break; // we didn't select a new one. No need to change anything
   453 
   426 			_railtype_selected_in_replace_gui = temp;
   454 	virtual void OnDropdownSelect(int widget, int index)
   427 			/* Reset scrollbar positions */
   455 	{
   428 			w->vscroll.pos  = 0;
   456 		RailType temp = (RailType)index;
   429 			w->vscroll2.pos = 0;
   457 		if (temp == sel_railtype) return; // we didn't select a new one. No need to change anything
   430 			/* Rebuild the lists */
   458 		sel_railtype = temp;
   431 			WP(w, replaceveh_d).update_left  = true;
   459 		/* Reset scrollbar positions */
   432 			WP(w, replaceveh_d).update_right = true;
   460 		this->vscroll.pos  = 0;
   433 			WP(w, replaceveh_d).init_lists   = true;
   461 		this->vscroll2.pos = 0;
   434 			w->SetDirty();
   462 		/* Rebuild the lists */
   435 		} break;
   463 		this->update_left  = true;
   436 
   464 		this->update_right = true;
   437 		case WE_RESIZE:
   465 		this->init_lists   = true;
   438 		{
   466 		this->SetDirty();
   439 			w->vscroll.cap  += e->we.sizing.diff.y / (int)w->resize.step_height;
   467 	}
   440 			w->vscroll2.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
   468 
   441 
   469 	virtual void OnResize(Point new_size, Point delta) {
   442 			Widget *widget = w->widget;
   470 		this->vscroll.cap  += delta.y / (int)this->resize.step_height;
   443 
   471 		this->vscroll2.cap += delta.y / (int)this->resize.step_height;
   444 			widget[RVW_WIDGET_LEFT_MATRIX].data = widget[RVW_WIDGET_RIGHT_MATRIX].data = (w->vscroll2.cap << 8) + 1;
   472 
   445 
   473 		Widget *widget = this->widget;
   446 			if (e->we.sizing.diff.x != 0) {
   474 
   447 				/* We changed the width of the window so we have to resize the lists.
   475 		widget[RVW_WIDGET_LEFT_MATRIX].data = widget[RVW_WIDGET_RIGHT_MATRIX].data = (this->vscroll2.cap << 8) + 1;
   448 				 * Because ResizeButtons() makes each widget the same size it can't be used on the lists
   476 
   449 				 * because then the lists would have the same size as the scrollbars.
   477 		if (delta.x != 0) {
   450 				 * Instead we use it on the detail panels.
   478 			/* We changed the width of the window so we have to resize the lists.
   451 				 * Afterwards we use the new location of the detail panels (the middle of the window)
   479 				* Because ResizeButtons() makes each widget the same size it can't be used on the lists
   452 				 * to place the lists.
   480 				* because then the lists would have the same size as the scrollbars.
   453 				 * This way the lists will have equal size while keeping the width of the scrollbars unchanged. */
   481 				* Instead we use it on the detail panels.
   454 				ResizeButtons(w, RVW_WIDGET_LEFT_DETAILS, RVW_WIDGET_RIGHT_DETAILS);
   482 				* Afterwards we use the new location of the detail panels (the middle of the window)
   455 				widget[RVW_WIDGET_RIGHT_MATRIX].left    = widget[RVW_WIDGET_RIGHT_DETAILS].left;
   483 				* to place the lists.
   456 				widget[RVW_WIDGET_LEFT_SCROLLBAR].right = widget[RVW_WIDGET_LEFT_DETAILS].right;
   484 				* This way the lists will have equal size while keeping the width of the scrollbars unchanged. */
   457 				widget[RVW_WIDGET_LEFT_SCROLLBAR].left  = widget[RVW_WIDGET_LEFT_SCROLLBAR].right - 11;
   485 			ResizeButtons(this, RVW_WIDGET_LEFT_DETAILS, RVW_WIDGET_RIGHT_DETAILS);
   458 				widget[RVW_WIDGET_LEFT_MATRIX].right    = widget[RVW_WIDGET_LEFT_SCROLLBAR].left - 1;
   486 			widget[RVW_WIDGET_RIGHT_MATRIX].left    = widget[RVW_WIDGET_RIGHT_DETAILS].left;
   459 			}
   487 			widget[RVW_WIDGET_LEFT_SCROLLBAR].right = widget[RVW_WIDGET_LEFT_DETAILS].right;
   460 		} break;
   488 			widget[RVW_WIDGET_LEFT_SCROLLBAR].left  = widget[RVW_WIDGET_LEFT_SCROLLBAR].right - 11;
   461 
   489 			widget[RVW_WIDGET_LEFT_MATRIX].right    = widget[RVW_WIDGET_LEFT_SCROLLBAR].left - 1;
   462 		case WE_INVALIDATE_DATA:
   490 		}
   463 			if (e->we.invalidate.data == true) {
   491 	}
   464 				WP(w, replaceveh_d).update_left = true;
   492 
   465 			} else {
   493 	virtual void OnInvalidateData(int data)
   466 				WP(w, replaceveh_d).update_right = true;
   494 	{
   467 			}
   495 		if (data != 0) {
   468 			break;
   496 			this->update_left = true;
   469 
   497 		} else {
   470 		case WE_DESTROY:
   498 			this->update_right = true;
   471 			WP(w, replaceveh_d).list[0].~EngineList(); // call destructor explicitly
   499 		}
   472 			WP(w, replaceveh_d).list[1].~EngineList();
   500 	}
   473 		break;
   501 };
   474 	}
       
   475 }
       
   476 
   502 
   477 static const Widget _replace_vehicle_widgets[] = {
   503 static const Widget _replace_vehicle_widgets[] = {
   478 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
   504 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
   479 {    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   443,     0,    13, STR_REPLACE_VEHICLES_WHITE,      STR_018C_WINDOW_TITLE_DRAG_THIS},
   505 {    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   443,     0,    13, STR_REPLACE_VEHICLES_WHITE,      STR_018C_WINDOW_TITLE_DRAG_THIS},
   480 {  WWT_STICKYBOX,     RESIZE_LR,    14,   444,   455,     0,    13, STR_NULL,                        STR_STICKY_BUTTON},
   506 {  WWT_STICKYBOX,     RESIZE_LR,    14,   444,   455,     0,    13, STR_NULL,                        STR_STICKY_BUTTON},
   502 static const WindowDesc _replace_rail_vehicle_desc = {
   528 static const WindowDesc _replace_rail_vehicle_desc = {
   503 	WDP_AUTO, WDP_AUTO, 456, 140, 456, 140,
   529 	WDP_AUTO, WDP_AUTO, 456, 140, 456, 140,
   504 	WC_REPLACE_VEHICLE, WC_NONE,
   530 	WC_REPLACE_VEHICLE, WC_NONE,
   505 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
   531 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
   506 	_replace_vehicle_widgets,
   532 	_replace_vehicle_widgets,
   507 	ReplaceVehicleWndProc
   533 	NULL
   508 };
   534 };
   509 
   535 
   510 static const WindowDesc _replace_vehicle_desc = {
   536 static const WindowDesc _replace_vehicle_desc = {
   511 	WDP_AUTO, WDP_AUTO, 456, 118, 456, 118,
   537 	WDP_AUTO, WDP_AUTO, 456, 118, 456, 118,
   512 	WC_REPLACE_VEHICLE, WC_NONE,
   538 	WC_REPLACE_VEHICLE, WC_NONE,
   513 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
   539 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
   514 	_replace_vehicle_widgets,
   540 	_replace_vehicle_widgets,
   515 	ReplaceVehicleWndProc
   541 	NULL
   516 };
   542 };
   517 
   543 
       
   544 RailType ReplaceVehicleWindow::sel_railtype = RAILTYPE_RAIL;
   518 
   545 
   519 void ShowReplaceGroupVehicleWindow(GroupID id_g, VehicleType vehicletype)
   546 void ShowReplaceGroupVehicleWindow(GroupID id_g, VehicleType vehicletype)
   520 {
   547 {
   521 	DeleteWindowById(WC_REPLACE_VEHICLE, vehicletype);
   548 	DeleteWindowById(WC_REPLACE_VEHICLE, vehicletype);
   522 	Window *w = vehicletype == VEH_TRAIN ? AllocateWindowDescFront<Window>(&_replace_rail_vehicle_desc, VEH_TRAIN)
   549 	new ReplaceVehicleWindow(vehicletype == VEH_TRAIN ? &_replace_rail_vehicle_desc : &_replace_vehicle_desc, vehicletype, id_g);
   523 										 : AllocateWindowDescFront<Window>(&_replace_vehicle_desc, vehicletype);
       
   524 
       
   525 	w->resize.step_height = GetVehicleListHeight(vehicletype);
       
   526 	w->vscroll.cap = w->resize.step_height == 14 ? 8 : 4;
       
   527 
       
   528 	Widget *widget = w->widget;
       
   529 	widget[RVW_WIDGET_LEFT_MATRIX].data = widget[RVW_WIDGET_RIGHT_MATRIX].data = (w->vscroll.cap << 8) + 1;
       
   530 
       
   531 	if (vehicletype == VEH_TRAIN) {
       
   532 		WP(w, replaceveh_d).wagon_btnstate = true;
       
   533 		/* The train window is bigger so we will move some of the widgets to fit the new size.
       
   534 		 * We will start by moving the resize button to the lower right corner.                 */
       
   535 		widget[RVW_WIDGET_RESIZE].top         = widget[RVW_WIDGET_TRAIN_ENGINEWAGON_TOGGLE].top;
       
   536 		widget[RVW_WIDGET_RESIZE].bottom      = widget[RVW_WIDGET_TRAIN_ENGINEWAGON_TOGGLE].bottom;
       
   537 		widget[RVW_WIDGET_STOP_REPLACE].right = widget[RVW_WIDGET_RESIZE].right;
       
   538 
       
   539 		/* The detail panel is one line taller for trains so we will move some of the widgets one line (10 pixels) down. */
       
   540 		widget[RVW_WIDGET_LEFT_DETAILS].bottom  += 10;
       
   541 		widget[RVW_WIDGET_RIGHT_DETAILS].bottom += 10;
       
   542 		for (int i = RVW_WIDGET_START_REPLACE; i < RVW_WIDGET_RESIZE; i++) {
       
   543 			widget[i].top    += 10;
       
   544 			widget[i].bottom += 10;
       
   545 		}
       
   546 	} else {
       
   547 		/* Since it's not a train we will hide the train only widgets. */
       
   548 		w->SetWidgetsHiddenState(true,
       
   549 								 RVW_WIDGET_TRAIN_ENGINEWAGON_TOGGLE,
       
   550 								 RVW_WIDGET_TRAIN_FLUFF_LEFT,
       
   551 								 RVW_WIDGET_TRAIN_RAILTYPE_DROPDOWN,
       
   552 								 RVW_WIDGET_TRAIN_FLUFF_RIGHT,
       
   553 								 RVW_WIDGET_TRAIN_WAGONREMOVE_TOGGLE,
       
   554 								 WIDGET_LIST_END);
       
   555 	}
       
   556 
       
   557 	ResizeWindow(w, 0, w->resize.step_height * w->vscroll.cap);
       
   558 
       
   559 	/* Set the minimum window size to the current window size */
       
   560 	w->resize.width  = w->width;
       
   561 	w->resize.height = w->height;
       
   562 
       
   563 	w->caption_color = _local_player;
       
   564 	WP(w, replaceveh_d).sel_group = id_g;
       
   565 	w->vscroll2.cap = w->vscroll.cap;   // these two are always the same
       
   566 }
   550 }