From e45e8a39c87f0452823e26e9579ac92a4a7921b5 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sun, 22 Sep 2024 10:33:44 +0100 Subject: [PATCH] Add: Overlay cargo icon in vehicle/depot list when holding shift+ctrl. (#12938) --- src/aircraft_gui.cpp | 11 +++++++ src/depot_gui.cpp | 9 ++++++ src/group_gui.cpp | 9 ++++++ src/lang/english.txt | 8 ++--- src/roadveh_gui.cpp | 10 ++++++ src/ship_gui.cpp | 1 + src/train_gui.cpp | 10 ++++++ src/vehicle_gui.cpp | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/vehicle_gui_base.h | 16 ++++++++++ 9 files changed, 155 insertions(+), 4 deletions(-) diff --git a/src/aircraft_gui.cpp b/src/aircraft_gui.cpp index cb7eae122a..ee2bf15ea3 100644 --- a/src/aircraft_gui.cpp +++ b/src/aircraft_gui.cpp @@ -97,6 +97,17 @@ void DrawAircraftImage(const Vehicle *v, const Rect &r, VehicleID selection, Eng PaletteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v); seq.Draw(x, y, pal, (v->vehstatus & VS_CRASHED) != 0); + + /* Aircraft can store cargo in their shadow, show this if present. */ + const Vehicle *u = v->Next(); + assert(u != nullptr); + int dx = 0; + if (u->cargo_cap > 0 && u->cargo_type != v->cargo_type) { + dx = GetLargestCargoIconSize().width / 2; + DrawCargoIconOverlay(x + dx, y, u->cargo_type); + } + if (v->cargo_cap > 0) DrawCargoIconOverlay(x - dx, y, v->cargo_type); + if (helicopter) { const Aircraft *a = Aircraft::From(v); VehicleSpriteSeq rotor_seq; diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp index e62915fe2c..9caa33e1c2 100644 --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -974,6 +974,15 @@ struct DepotWindow : Window { } } + bool last_overlay_state; + void OnMouseLoop() override + { + if (last_overlay_state != ShowCargoIconOverlay()) { + last_overlay_state = ShowCargoIconOverlay(); + this->SetDirty(); + } + } + void OnMouseDrag(Point pt, WidgetID widget) override { if (this->sel == INVALID_VEHICLE) return; diff --git a/src/group_gui.cpp b/src/group_gui.cpp index aa9ecf34be..a48baead9b 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -692,6 +692,15 @@ public: } } + bool last_overlay_state; + void OnMouseLoop() override + { + if (last_overlay_state != ShowCargoIconOverlay()) { + last_overlay_state = ShowCargoIconOverlay(); + this->SetDirty(); + } + } + void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override { switch (widget) { diff --git a/src/lang/english.txt b/src/lang/english.txt index c6e4fa3d3b..dddadd8f93 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -4009,10 +4009,10 @@ STR_VEHICLE_LIST_SHIP_CAPTION :{WHITE}{STRING2 STR_VEHICLE_LIST_AIRCRAFT_CAPTION :{WHITE}{STRING2} - {COMMA} Aircraft ###length VEHICLE_TYPES -STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP :{BLACK}Trains - click on train for information -STR_VEHICLE_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Road vehicles - click on vehicle for information -STR_VEHICLE_LIST_SHIP_TOOLTIP :{BLACK}Ships - click on ship for information -STR_VEHICLE_LIST_AIRCRAFT_TOOLTIP :{BLACK}Aircraft - click on aircraft for information +STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP :{BLACK}Trains - click on train for information. Hold Ctrl+Shift to overlay cargo type +STR_VEHICLE_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Road vehicles - click on vehicle for information. Hold Ctrl+Shift to overlay cargo type +STR_VEHICLE_LIST_SHIP_TOOLTIP :{BLACK}Ships - click on ship for information. Hold Ctrl+Shift to overlay cargo type +STR_VEHICLE_LIST_AIRCRAFT_TOOLTIP :{BLACK}Aircraft - click on aircraft for information. Hold Ctrl+Shift to overlay cargo type ###length VEHICLE_TYPES STR_VEHICLE_LIST_AVAILABLE_TRAINS :Available Trains diff --git a/src/roadveh_gui.cpp b/src/roadveh_gui.cpp index f2ee0c6684..358a27bbaf 100644 --- a/src/roadveh_gui.cpp +++ b/src/roadveh_gui.cpp @@ -132,6 +132,10 @@ void DrawRoadVehImage(const Vehicle *v, const Rect &r, VehicleID selection, Engi AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi); + bool do_overlays = ShowCargoIconOverlay(); + /* List of overlays, only used if cargo icon overlays are enabled. */ + static std::vector overlays; + int px = rtl ? max_width + skip : -skip; int y = r.Height() / 2; for (; u != nullptr && (rtl ? px > 0 : px < max_width); u = u->Next()) @@ -146,9 +150,15 @@ void DrawRoadVehImage(const Vehicle *v, const Rect &r, VehicleID selection, Engi seq.Draw(px + (rtl ? -offset.x : offset.x), y + offset.y, pal, (u->vehstatus & VS_CRASHED) != 0); } + if (do_overlays) AddCargoIconOverlay(overlays, px, width, u); px += rtl ? -width : width; } + if (do_overlays) { + DrawCargoIconOverlays(overlays, y); + overlays.clear(); + } + if (v->index == selection) { int height = ScaleSpriteTrad(12); Rect hr = {(rtl ? px : 0), 0, (rtl ? max_width : px) - 1, height - 1}; diff --git a/src/ship_gui.cpp b/src/ship_gui.cpp index fbc174fc8d..2ea017e7bc 100644 --- a/src/ship_gui.cpp +++ b/src/ship_gui.cpp @@ -44,6 +44,7 @@ void DrawShipImage(const Vehicle *v, const Rect &r, VehicleID selection, EngineI int y = ScaleSpriteTrad(-1) + CenterBounds(r.top, r.bottom, 0); seq.Draw(x, y, GetVehiclePalette(v), false); + if (v->cargo_cap > 0) DrawCargoIconOverlay(x, y, v->cargo_type); if (v->index == selection) { x += x_offs; diff --git a/src/train_gui.cpp b/src/train_gui.cpp index d62d3dce55..16328bf224 100644 --- a/src/train_gui.cpp +++ b/src/train_gui.cpp @@ -106,6 +106,10 @@ void DrawTrainImage(const Train *v, const Rect &r, VehicleID selection, EngineIm { AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi); + bool do_overlays = ShowCargoIconOverlay(); + /* List of overlays, only used if cargo icon overlays are enabled. */ + static std::vector overlays; + int px = rtl ? max_width + skip : -skip; int y = r.Height() / 2; bool sel_articulated = false; @@ -143,9 +147,15 @@ void DrawTrainImage(const Train *v, const Rect &r, VehicleID selection, EngineIm } } + if (do_overlays) AddCargoIconOverlay(overlays, px, width, v); px += rtl ? -width : width; } + if (do_overlays) { + DrawCargoIconOverlays(overlays, y); + overlays.clear(); + } + if (dragging && drag_at_end_of_train) { /* Highlight the drag-and-drop destination at the end of the train. */ HighlightDragPosition(px, max_width, y, selection, _cursor.vehchain); diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 2a43b351a3..ef502123b9 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -329,6 +329,82 @@ static bool CargoFilter(const GUIVehicleGroup *vehgroup, const CargoID cid) return false; } +/** + * Test if cargo icon overlays should be drawn. + * @returns true iff cargo icon overlays should be drawn. + */ +bool ShowCargoIconOverlay() +{ + return _shift_pressed && _ctrl_pressed; +} + +/** + * Add a cargo icon to the list of overlays. + * @param overlays List of overlays. + * @param x Horizontal position. + * @param width Width available. + * @param v Vehicle to add. + */ +void AddCargoIconOverlay(std::vector &overlays, int x, int width, const Vehicle *v) +{ + bool rtl = _current_text_dir == TD_RTL; + if (!v->IsArticulatedPart() || v->cargo_type != v->Previous()->cargo_type) { + /* Add new overlay slot. */ + overlays.emplace_back(rtl ? x - width : x, rtl ? x : x + width, v->cargo_type, v->cargo_cap); + } else { + /* This is an articulated part with the same cargo type, adjust left or right of last overlay slot. */ + if (rtl) { + overlays.back().left -= width; + } else { + overlays.back().right += width; + } + overlays.back().cargo_cap += v->cargo_cap; + } +} + +/** + * Draw a cargo icon overlaying an existing sprite, with a black contrast outline. + * @param x Horizontal position from left. + * @param y Vertical position from top. + * @param cid Cargo ID to draw icon for. + */ +void DrawCargoIconOverlay(int x, int y, CargoID cid) +{ + if (!ShowCargoIconOverlay()) return; + if (!IsValidCargoID(cid)) return; + + const CargoSpec *cs = CargoSpec::Get(cid); + + SpriteID spr = cs->GetCargoIcon(); + if (spr == 0) return; + + Dimension d = GetSpriteSize(spr); + d.width /= 2; + d.height /= 2; + int one = ScaleGUITrad(1); + + /* Draw the cargo icon in black shifted 4 times to create the outline. */ + DrawSprite(spr, PALETTE_ALL_BLACK, x - d.width - one, y - d.height); + DrawSprite(spr, PALETTE_ALL_BLACK, x - d.width + one, y - d.height); + DrawSprite(spr, PALETTE_ALL_BLACK, x - d.width, y - d.height - one); + DrawSprite(spr, PALETTE_ALL_BLACK, x - d.width, y - d.height + one); + /* Draw the cargo icon normally. */ + DrawSprite(spr, PAL_NONE, x - d.width, y - d.height); +} + +/** + * Draw a list of cargo icon overlays. + * @param overlays List of overlays. + * @param y Vertical position. + */ +void DrawCargoIconOverlays(std::span overlays, int y) +{ + for (const auto &cio : overlays) { + if (cio.cargo_cap == 0) continue; + DrawCargoIconOverlay((cio.left + cio.right) / 2, y, cio.cargo_type); + } +} + static GUIVehicleGroupList::FilterFunction * const _vehicle_group_filter_funcs[] = { &CargoFilter, }; @@ -2053,6 +2129,15 @@ public: this->DrawWidgets(); } + bool last_overlay_state; + void OnMouseLoop() override + { + if (last_overlay_state != ShowCargoIconOverlay()) { + last_overlay_state = ShowCargoIconOverlay(); + this->SetDirty(); + } + } + void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override { switch (widget) { diff --git a/src/vehicle_gui_base.h b/src/vehicle_gui_base.h index 21053c4921..88f76bdc61 100644 --- a/src/vehicle_gui_base.h +++ b/src/vehicle_gui_base.h @@ -139,6 +139,22 @@ struct BaseVehicleListWindow : public Window { } }; +struct CargoIconOverlay { + int left; + int right; + CargoID cargo_type; + uint cargo_cap; + + constexpr CargoIconOverlay(int left, int right, CargoID cargo_type, uint cargo_cap) + : left(left), right(right), cargo_type(cargo_type), cargo_cap(cargo_cap) + { } +}; + +bool ShowCargoIconOverlay(); +void AddCargoIconOverlay(std::vector &overlays, int x, int width, const Vehicle *v); +void DrawCargoIconOverlay(int x, int y, CargoID cid); +void DrawCargoIconOverlays(std::span overlays, int y); + uint GetVehicleListHeight(VehicleType type, uint divisor = 1); struct Sorting { -- 2.11.4.GIT