using System; using System.Collections.Generic; using Cthangover.Core.Mods; using Cthangover.Core.UI; using Cthangover.Core.UI.Theming; using Cthangover.Core.Utils; using Godot; using Cthangover.Mods.Interface.Base.Lists; namespace Mods.ModManager { /// /// Root of the mod manager screen. Opened from the main menu through the /// manifest main_menu button as a fullscreen overlay; closing frees the /// scene. The visual layout is decomposed into editable scenes /// (mod_filter_panel, mod_grid_view/mod_grid_group, /// mod_card, mod_detail_view) referenced from /// scenes/mod_manager_screen.tscn; this class only wires them to the /// model, runs mod operations (install/update/delete/enable) and reflects that /// all of them only take effect after a restart. /// public partial class ModManagerScreen : ModWidget { private ModManagerModel _model; private ModFilterState _filter; private ModGridView _grid; private ModDetailView _detail; private ModFilterPanel _filterPanel; private LineEdit _search; private OptionButton _sort; private Label _resultLabel; private PanelContainer _bannerPanel; private Label _bannerLabel; private Button _refreshButton; private string _installingId; private bool _restartRequired; private string _statusMessage; /// /// Merged collection store keyed by id (as produced by /// ), refreshed together with /// the model; feeds the "in N collections" badge on every tile. /// private Dictionary _collectionIndex; /// /// When true the screen runs as a tab of the mods hub: its own header /// close button and title are hidden and closing is handled by the /// hosting . Must be set before construction; /// filters, search, install and delete behaviour are unchanged. /// public bool Embedded { get; set; } /// Raised when a tile or the detail page asks to jump to the collections tab. public event Action CollectionsLinkRequested; /// /// Applies an external search query — collection cross-links jump to /// this tab with a mod id taken from a scheme problem. Updates the /// search box and refreshes the grid without touching other filters. /// public void SetSearch(string text) { var query = text ?? string.Empty; _filter.Search = query; if (GodotObject.IsInstanceValid(_search) && !string.Equals(_search.Text, query, StringComparison.Ordinal)) { _search.Text = query; } RefreshView(); } protected override void Construct() { MouseFilter = MouseFilterEnum.Stop; CthangoverTheme.Apply(this); _model = new ModManagerModel(); _filter = new ModFilterState(); BindSceneNodes(); SubscribeEvents(); CatalogService.LoadCache(); _model.Reload(); _filterPanel.Bind(_filter); RefreshAll(); StartCatalogRefreshIfNeeded(); } protected override void Destruct() { UnsubscribeEvents(); } /// Fetches the scene-built nodes, sets static captions and hooks the layout controls. private void BindSceneNodes() { var close = GetNode