Changeset - r28823:ebda70ff18b6
[Not reviewed]
master
0 2 0
Peter Nelson - 9 months ago 2024-02-25 21:33:11
peter1138@openttd.org
Codefix: DrawEngineList does not accept EngineID.

Replace min/max parameters of DrawEngineList with scrollbar reference, and use iterators instead of indices.
2 files changed with 12 insertions and 17 deletions:
0 comments (0 inline, 0 general)
src/autoreplace_gui.cpp
Show inline comments
 
@@ -24,25 +24,25 @@
 
#include "core/geometry_func.hpp"
 
#include "rail_gui.h"
 
#include "road_gui.h"
 
#include "widgets/dropdown_func.h"
 
#include "autoreplace_cmd.h"
 
#include "group_cmd.h"
 
#include "settings_cmd.h"
 

	
 
#include "widgets/autoreplace_widget.h"
 

	
 
#include "safeguards.h"
 

	
 
void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_list, uint16_t min, uint16_t max, EngineID selected_id, bool show_count, GroupID selected_group);
 
void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_list, const Scrollbar &sb, EngineID selected_id, bool show_count, GroupID selected_group);
 

	
 
static bool EngineNumberSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
 
{
 
	return Engine::Get(a.engine_id)->list_position < Engine::Get(b.engine_id)->list_position;
 
}
 

	
 
/**
 
 * Rebuild the left autoreplace list if an engine is removed or added
 
 * @param e Engine to check if it is removed or added
 
 * @param id_g The group the engine belongs to
 
 *  Note: this function only works if it is called either
 
 *   - when a new vehicle is build, but before it's counted in num_engines
 
@@ -478,29 +478,27 @@ public:
 
					}
 
				} else {
 
					str = STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED;
 
				}
 

	
 
				DrawString(r.Shrink(WidgetDimensions::scaled.frametext, WidgetDimensions::scaled.framerect), str, TC_BLACK, SA_HOR_CENTER);
 
				break;
 
			}
 

	
 
			case WID_RV_LEFT_MATRIX:
 
			case WID_RV_RIGHT_MATRIX: {
 
				int side = (widget == WID_RV_LEFT_MATRIX) ? 0 : 1;
 
				EngineID start  = static_cast<EngineID>(this->vscroll[side]->GetPosition()); // what is the offset for the start (scrolling)
 
				EngineID end    = static_cast<EngineID>(std::min<size_t>(this->vscroll[side]->GetCapacity() + start, this->engines[side].size()));
 

	
 
				/* Do the actual drawing */
 
				DrawEngineList((VehicleType)this->window_number, r, this->engines[side], start, end, this->sel_engine[side], side == 0, this->sel_group);
 
				DrawEngineList((VehicleType)this->window_number, r, this->engines[side], *this->vscroll[side], this->sel_engine[side], side == 0, this->sel_group);
 
				break;
 
			}
 
		}
 
	}
 

	
 
	void OnPaint() override
 
	{
 
		if (this->engines[0].NeedRebuild() || this->engines[1].NeedRebuild()) this->GenerateLists();
 

	
 
		Company *c = Company::Get(_local_company);
 

	
 
		/* Disable the "Start Replacing" button if:
src/build_vehicle_gui.cpp
Show inline comments
 
@@ -989,76 +989,73 @@ int DrawVehiclePurchaseInfo(int left, in
 
		DrawString(left, right, y, config->GetName(), TC_BLACK);
 
		y += GetCharacterHeight(FS_NORMAL);
 
	}
 

	
 
	return y;
 
}
 

	
 
/**
 
 * Engine drawing loop
 
 * @param type Type of vehicle (VEH_*)
 
 * @param r The Rect of the list
 
 * @param eng_list What engines to draw
 
 * @param min where to start in the list
 
 * @param max where in the list to end
 
 * @param sb Scrollbar of list.
 
 * @param selected_id what engine to highlight as selected, if any
 
 * @param show_count Whether to show the amount of engines or not
 
 * @param selected_group the group to list the engines of
 
 */
 
void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_list, uint16_t min, uint16_t max, EngineID selected_id, bool show_count, GroupID selected_group)
 
void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_list, const Scrollbar &sb, EngineID selected_id, bool show_count, GroupID selected_group)
 
{
 
	static const int sprite_y_offsets[] = { -1, -1, -2, -2 };
 

	
 
	/* Obligatory sanity checks! */
 
	assert(max <= eng_list.size());
 
	auto [first, last] = sb.GetVisibleRangeIterators(eng_list);
 

	
 
	bool rtl = _current_text_dir == TD_RTL;
 
	int step_size = GetEngineListHeight(type);
 
	int sprite_left  = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_left;
 
	int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right;
 
	int sprite_width = sprite_left + sprite_right;
 
	int circle_width = std::max(GetScaledSpriteSize(SPR_CIRCLE_FOLDED).width, GetScaledSpriteSize(SPR_CIRCLE_UNFOLDED).width);
 
	int linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
 

	
 
	Rect ir      = r.WithHeight(step_size).Shrink(WidgetDimensions::scaled.matrix);
 
	int sprite_y_offset = ScaleSpriteTrad(sprite_y_offsets[type]) + ir.Height() / 2;
 

	
 
	Dimension replace_icon = {0, 0};
 
	int count_width = 0;
 
	if (show_count) {
 
		replace_icon = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE);
 

	
 
		uint biggest_num_engines = 0;
 
		for (auto i = min; i < max; i++) {
 
			const auto &item = eng_list[i];
 
			const uint num_engines = GetGroupNumEngines(_local_company, selected_group, item.engine_id);
 
		for (auto it = first; it != last; ++it) {
 
			const uint num_engines = GetGroupNumEngines(_local_company, selected_group, it->engine_id);
 
			biggest_num_engines = std::max(biggest_num_engines, num_engines);
 
		}
 

	
 
		SetDParam(0, biggest_num_engines);
 
		count_width = GetStringBoundingBox(STR_JUST_COMMA, FS_SMALL).width;
 
	}
 

	
 
	Rect tr = ir.Indent(circle_width + WidgetDimensions::scaled.hsep_normal + sprite_width + WidgetDimensions::scaled.hsep_wide, rtl); // Name position
 
	Rect cr = tr.Indent(replace_icon.width + WidgetDimensions::scaled.hsep_wide, !rtl).WithWidth(count_width, !rtl);  // Count position
 
	Rect rr = tr.WithWidth(replace_icon.width, !rtl);                                                                 // Replace icon position
 
	if (show_count) tr = tr.Indent(count_width + WidgetDimensions::scaled.hsep_normal + replace_icon.width + WidgetDimensions::scaled.hsep_wide, !rtl);
 

	
 
	int normal_text_y_offset = (ir.Height() - GetCharacterHeight(FS_NORMAL)) / 2;
 
	int small_text_y_offset  = ir.Height() - GetCharacterHeight(FS_SMALL);
 
	int replace_icon_y_offset = (ir.Height() - replace_icon.height) / 2;
 

	
 
	int y = ir.top;
 
	for (; min < max; min++, y += step_size) {
 
		const auto &item = eng_list[min];
 
	for (auto it = first; it != last; ++it) {
 
		const auto &item = *it;
 
		uint indent       = item.indent * WidgetDimensions::scaled.hsep_indent;
 
		bool has_variants = (item.flags & EngineDisplayFlags::HasVariants) != EngineDisplayFlags::None;
 
		bool is_folded    = (item.flags & EngineDisplayFlags::IsFolded)    != EngineDisplayFlags::None;
 
		bool shaded       = (item.flags & EngineDisplayFlags::Shaded)      != EngineDisplayFlags::None;
 
		/* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */
 
		const uint num_engines = GetGroupNumEngines(_local_company, selected_group, item.engine_id);
 

	
 
		const Engine *e = Engine::Get(item.engine_id);
 
		bool hidden = HasBit(e->company_hidden, _local_company);
 
		StringID str = hidden ? STR_HIDDEN_ENGINE_NAME : STR_ENGINE_NAME;
 
		TextColour tc = (item.engine_id == selected_id) ? TC_WHITE : ((hidden | shaded) ? (TC_GREY | TC_FORCED | TC_NO_SHADE) : TC_BLACK);
 

	
 
@@ -1076,28 +1073,29 @@ void DrawEngineList(VehicleType type, co
 
			SetDParam(0, num_engines);
 
			DrawString(cr.left, cr.right, y + small_text_y_offset, STR_JUST_COMMA, TC_BLACK, SA_RIGHT | SA_FORCE, false, FS_SMALL);
 
			if (EngineHasReplacementForCompany(Company::Get(_local_company), item.engine_id, selected_group)) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, rr.left, y + replace_icon_y_offset);
 
		}
 
		if (has_variants) {
 
			Rect fr = ir.Indent(indent, rtl).WithWidth(circle_width, rtl);
 
			DrawSpriteIgnorePadding(is_folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, {fr.left, y, fr.right, y + ir.Height() - 1}, SA_CENTER);
 
		}
 
		if (indent > 0) {
 
			/* Draw tree lines */
 
			Rect fr = ir.Indent(indent - WidgetDimensions::scaled.hsep_indent, rtl).WithWidth(circle_width, rtl);
 
			int ycenter = y + normal_text_y_offset + GetCharacterHeight(FS_NORMAL) / 2;
 
			bool continues = (min + 1U) < eng_list.size() && eng_list[min + 1].indent == item.indent;
 
			bool continues = std::next(it) != std::end(eng_list) && std::next(it)->indent == item.indent;
 
			GfxDrawLine(fr.left + circle_width / 2, y - WidgetDimensions::scaled.matrix.top, fr.left + circle_width / 2, continues ? y - WidgetDimensions::scaled.matrix.top + step_size - 1 : ycenter, linecolour, WidgetDimensions::scaled.fullbevel.top);
 
			GfxDrawLine(fr.left + circle_width / 2, ycenter, fr.right, ycenter, linecolour, WidgetDimensions::scaled.fullbevel.top);
 
		}
 
		y += step_size;
 
	}
 
}
 

	
 
/**
 
 * Display the dropdown for the vehicle sort criteria.
 
 * @param w Parent window (holds the dropdown button).
 
 * @param vehicle_type %Vehicle type being sorted.
 
 * @param selected Currently selected sort criterium.
 
 * @param button Widget button.
 
 */
 
void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, WidgetID button)
 
{
 
@@ -1782,26 +1780,25 @@ struct BuildVehicleWindow : Window {
 
				break;
 
		}
 
	}
 

	
 
	void DrawWidget(const Rect &r, WidgetID widget) const override
 
	{
 
		switch (widget) {
 
			case WID_BV_LIST:
 
				DrawEngineList(
 
					this->vehicle_type,
 
					r,
 
					this->eng_list,
 
					this->vscroll->GetPosition(),
 
					static_cast<uint16_t>(std::min<size_t>(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->eng_list.size())),
 
					*this->vscroll,
 
					this->sel_engine,
 
					false,
 
					DEFAULT_GROUP
 
				);
 
				break;
 

	
 
			case WID_BV_SORT_ASCENDING_DESCENDING:
 
				this->DrawSortButtonState(WID_BV_SORT_ASCENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP);
 
				break;
 
		}
 
	}
 

	
0 comments (0 inline, 0 general)