diff --git a/locale/en.properties b/locale/en.properties
index d6a1032..63e6c5f 100644
--- a/locale/en.properties
+++ b/locale/en.properties
@@ -219,16 +219,63 @@ mod_manager/collection_delete_confirm = The collection «{0}» will be deleted.
mod_manager/collection_delete_done = Collection deleted. Its mods stay in the system.
mod_manager/collection_nested_readonly = This block is nested deeper — open it on its own to change it.
mod_manager/collection_forked = Block “{0}” copied for this game — other games stay unchanged.
-mod_manager/help_open = What do the controls on this screen mean?
-mod_manager/help_close = Close help
-mod_manager/help_mods_title = Mods
-mod_manager/help_mods_body = This is the list of mods installed on this device. Use the search box in the header to find a mod by its name, and the refresh button to re-read the catalog — freshly installed mods appear at once. Click a mod card to open its page with the description, the version and the actions. The switch on each card turns the mod on or off for the games that use it; a disabled mod keeps its files but is not loaded. Scenes and content of a disabled mod disappear from running games until you enable it again, while your saves are kept either way.
-mod_manager/help_mod_page_title = Mod page
-mod_manager/help_mod_page_body = This page shows one mod in detail: the description, the author, the version and the list of its dependencies. From here you can enable or disable the mod for the current games, and open its scenes if the mod provides any. The links under the description jump to the collections this mod belongs to. The back button and Escape return you to the mods list; the on/off state of the mod is saved with your game and survives restarts, so there is no need to set it every time. If two mods ship the same file, the page tells you which one wins.
-mod_manager/help_collections_title = Collections
-mod_manager/help_collections_body = The collections tab lists game collections: ready-made bundles of mods that play like separate games. Every card shows the cover, the title and the mods the collection includes. Click a card to open the collection, and use Configure to open the scheme editor for it. Installing a collection fetches the mods it needs; removing it never deletes your saves — the game's data sleeps and returns together with the collection.
-mod_manager/help_scheme_title = Scheme editor
-mod_manager/help_scheme_body = The scheme editor changes what a collection includes: which mods take part in the game and in which order they load. Turn the checkboxes on and off to add or remove mods, and drag rows to change the load order — when two mods ship the same file, the one loaded later wins. The editor validates your scheme before saving and warns about missing dependencies. Changes apply on the next launch of the game; your saves are kept, and the data of absent mods sleeps until the mod returns.
+mod_manager/help_open = Contextual hints (F1)
+mod_manager/help_active = Hover over a control · Left click — pin the hint · Esc — exit
+mod_manager/collection_order_legend = Dependency → the mod that needs it. Card positions and group boundaries do not define load order.
+mod_manager/enable_tooltip = Load this mod in games that use it.
+mod_manager/disable_tooltip = Do not load this mod. Its files and saves are kept.
+mod_manager/hint_mods_tab_title = Mods
+mod_manager/hint_mods_tab_body = The catalog and installed mods. Manage mod files, versions and whether games load them here.
+mod_manager/hint_collections_tab_title = Collections
+mod_manager/hint_collections_tab_body = Ready-made mod sets that run as separate games. Their contents can be changed in the scheme editor.
+mod_manager/hint_collection_search_title = Search collections
+mod_manager/hint_collection_search_body = Filters cards by title, description, identifier and tags.
+mod_manager/hint_refresh_title = Refresh
+mod_manager/hint_refresh_body = Reloads the catalog and compares it with installed mods. Your current settings are preserved.
+mod_manager/hint_mod_search_title = Search mods
+mod_manager/hint_mod_search_body = Filters the list by mod title, author or identifier.
+mod_manager/hint_mod_sort_title = Sorting
+mod_manager/hint_mod_sort_body = Changes only the card order: by name, author or installation state.
+mod_manager/hint_filters_reset_title = Reset filters
+mod_manager/hint_filters_reset_body = Restores the default search, states, categories and grouping.
+mod_manager/hint_group_categories_title = Group by category
+mod_manager/hint_group_categories_body = Groups cards into sections without changing the mods themselves.
+mod_manager/hint_mod_card_title = Mod card
+mod_manager/hint_mod_card_body = Click an empty part of the card to open its description, dependencies and every available action.
+mod_manager/hint_mod_version_title = Mod version
+mod_manager/hint_mod_version_body = Chooses the version to install or update. Labels mark the latest and currently installed versions.
+mod_manager/hint_mod_action_title = Mod action
+mod_manager/hint_mod_action_body = The action follows the mod state: install, update, change version, reinstall or delete.
+mod_manager/hint_mod_enabled_title = Mod loading
+mod_manager/hint_mod_enabled_body = A disabled mod stays on disk but is not loaded by games. Saves and mod data are preserved.
+mod_manager/hint_mod_delete_title = Delete mod
+mod_manager/hint_mod_delete_body = Removes the mod files from this device. Collections and game saves are not deleted.
+mod_manager/hint_mod_collections_title = Used in collections
+mod_manager/hint_mod_collections_body = Opens the collections that include this mod.
+mod_manager/hint_collection_new_title = New collection
+mod_manager/hint_collection_new_body = Creates an empty game scheme. Add mods and mechanics in the editor.
+mod_manager/hint_collection_apply_title = Apply contents
+mod_manager/hint_collection_apply_body = Installs missing mods and enables required ones. You can review the plan first.
+mod_manager/hint_collection_edit_title = Configure collection
+mod_manager/hint_collection_edit_body = Opens the game contents: mods, dependencies, load order and the change plan.
+mod_manager/hint_collection_delete_title = Delete collection
+mod_manager/hint_collection_delete_body = Deletes only the collection. Installed mods and game saves are kept.
+mod_manager/hint_collection_add_mechanic_title = Add mechanic
+mod_manager/hint_collection_add_mechanic_body = Adds a group for related mods and their settings to the scheme.
+mod_manager/hint_collection_game_title = Edited collection
+mod_manager/hint_collection_game_body = Switches the editor to another game without closing this screen.
+mod_manager/hint_collection_problems_title = Scheme problems
+mod_manager/hint_collection_problems_body = Lists missing mods, incompatible versions and conflicts that prevent the game from running.
+mod_manager/hint_collection_plan_title = Change plan
+mod_manager/hint_collection_plan_body = Shows which mods applying the scheme will install and enable.
+mod_manager/hint_collection_json_title = Scheme as JSON
+mod_manager/hint_collection_json_body = Opens the scheme as text for inspection and precise editing.
+mod_manager/hint_collection_reset_title = Discard changes
+mod_manager/hint_collection_reset_body = Restores the last saved scheme. Mods that are already installed are not removed.
+mod_manager/hint_collection_links_title = Scheme links
+mod_manager/hint_collection_links_body = Shows or hides dependency lines between groups and mods.
+mod_manager/hint_load_order_title = Load order
+mod_manager/hint_load_order_body = Mods load from top to bottom. When two mods replace the same resource, the lower mod wins.
mod_manager/sort_tooltip = Sort the list: by name, author or install state.
mod_manager/filters_reset_tooltip = Return every filter and the search box to their defaults.
mod_manager/collection_json_tooltip = Open the scheme as raw JSON: view, edit and apply it back.
@@ -236,3 +283,29 @@ mod_manager/collection_reset_tooltip = Discard all unsaved scheme changes.
mod_manager/collection_game_tooltip = Switch the scheme being edited to another collection.
mod_manager/collection_plan_tooltip = Open the plan: what apply will install and enable.
mod_manager/collection_problems_tooltip = Open the problem list: missing mods, version gaps and conflicts.
+
+# Graphite collection editor
+mod_manager/collection_links_selected = Selected links
+mod_manager/collection_links_all = All links
+mod_manager/collection_links_none = No links
+mod_manager/collection_canvas_search = Find in scheme…
+mod_manager/collection_canvas_fit = Fit width
+mod_manager/collection_canvas_arrange = Arrange
+mod_manager/collection_canvas_focus = Show selection
+mod_manager/collection_version_caption = Version for this collection
+mod_manager/collection_version_hint = This is the game requirement, not the installed mod version.
+mod_manager/collection_version_edit = Change requirement
+mod_manager/collection_version_any = Any
+mod_manager/collection_version_minimum = At least
+mod_manager/collection_version_exact = Exactly
+mod_manager/collection_version_branch = Branch
+mod_manager/collection_version_maximum = At most
+mod_manager/collection_version_greater = Above
+mod_manager/collection_version_less = Below
+mod_manager/collection_version_branch_hint = Branch: ^1 accepts 1.x; ^1.2 accepts 1.2.x.
+mod_manager/collection_version_invalid = Invalid version. Enter a value such as 2.0.0.
+mod_manager/collection_role_hint = A group describes the mod’s purpose in this game; another game may assign it a different role.
+mod_manager/collection_used_by = Required by: {0}
+mod_manager/collection_other_role = {0} → {1}
+mod_manager/hint_collection_dependencies_title = Dependencies and group purpose
+mod_manager/hint_collection_dependencies_body = Dependency → the mod that needs it. Card positions and group boundaries do not define load order. A group describes the mod’s purpose in this game; another game may assign it a different role.
diff --git a/locale/es.properties b/locale/es.properties
index c109b99..9934cce 100644
--- a/locale/es.properties
+++ b/locale/es.properties
@@ -219,16 +219,63 @@ mod_manager/collection_delete_confirm = Se eliminará la colección «{0}». Sus
mod_manager/collection_delete_done = Colección eliminada. Sus mods siguen en el sistema.
mod_manager/collection_nested_readonly = Este bloque está anidado más adentro: ábrelo por separado para cambiarlo.
mod_manager/collection_forked = Bloque «{0}» copiado para este juego: los demás juegos no cambian.
-mod_manager/help_open = Ayuda: ¿qué hace cada control de esta pantalla?
-mod_manager/help_close = Cerrar la ayuda
-mod_manager/help_mods_title = Mods
-mod_manager/help_mods_body = Esta es la lista de mods instalados en este dispositivo. Usa el cuadro de búsqueda de la cabecera para encontrar un mod por su nombre y el botón de actualizar para releer el catálogo: los mods recién instalados aparecen enseguida. Haz clic en la tarjeta de un mod para abrir su página con la descripción, la versión y las acciones. El interruptor de cada tarjeta activa o desactiva el mod en los juegos que lo usan; un mod desactivado conserva sus archivos pero no se carga. Las escenas y el contenido de un mod desactivado desaparecen de los juegos en marcha hasta que lo vuelvas a activar; tus partidas guardadas se conservan igualmente.
-mod_manager/help_mod_page_title = Página del mod
-mod_manager/help_mod_page_body = Esta página muestra un mod en detalle: la descripción, el autor, la versión y la lista de sus dependencias. Desde aquí puedes activar o desactivar el mod en los juegos actuales y abrir sus escenas si el mod las ofrece. Los enlaces bajo la descripción llevan a las colecciones a las que pertenece el mod. El botón de atrás y Escape te devuelven a la lista de mods; el estado del mod se guarda con tu partida y sobrevive a los reinicios, así que no hace falta configurarlo cada vez. Si dos mods traen el mismo archivo, la página te dice cuál gana.
-mod_manager/help_collections_title = Colecciones
-mod_manager/help_collections_body = La pestaña de colecciones muestra las colecciones de juegos: paquetes listos de mods que se juegan como juegos aparte. Cada tarjeta muestra la portada, el título y los mods que incluye la colección. Haz clic en una tarjeta para abrir la colección y usa Configurar para abrir el editor de esquema. Instalar una colección descarga los mods que necesita; quitarla nunca borra tus partidas guardadas: los datos del juego descansan y vuelven cuando la colección regresa.
-mod_manager/help_scheme_title = Editor de esquema
-mod_manager/help_scheme_body = El editor de esquema cambia lo que incluye una colección: qué mods participan en el juego y en qué orden se cargan. Marca y desmarca las casillas para añadir o quitar mods y arrastra las filas para cambiar el orden de carga: cuando dos mods traen el mismo archivo, gana el que se carga después. Antes de guardar, el editor valida tu esquema y avisa de las dependencias que faltan. Los cambios se aplican en el próximo inicio del juego; tus partidas se conservan y los datos de los mods ausentes descansan hasta que el mod vuelva.
+mod_manager/help_open = Sugerencias contextuales (F1)
+mod_manager/help_active = Pasa el cursor por un control · Clic izquierdo: fijar · Esc: salir
+mod_manager/collection_order_legend = Dependencia → mod que la necesita. La posición y los grupos no definen el orden de carga.
+mod_manager/enable_tooltip = Cargar este mod en los juegos que lo utilizan.
+mod_manager/disable_tooltip = No cargar este mod. Sus archivos y partidas se conservan.
+mod_manager/hint_mods_tab_title = Mods
+mod_manager/hint_mods_tab_body = El catálogo y los mods instalados. Gestiona sus archivos, versiones y carga en los juegos.
+mod_manager/hint_collections_tab_title = Colecciones
+mod_manager/hint_collections_tab_body = Conjuntos de mods que funcionan como juegos independientes. Su contenido se edita en el editor de esquema.
+mod_manager/hint_collection_search_title = Buscar colecciones
+mod_manager/hint_collection_search_body = Filtra las tarjetas por título, descripción, identificador y etiquetas.
+mod_manager/hint_refresh_title = Actualizar
+mod_manager/hint_refresh_body = Recarga el catálogo y lo compara con los mods instalados. Conserva la configuración actual.
+mod_manager/hint_mod_search_title = Buscar mods
+mod_manager/hint_mod_search_body = Filtra la lista por título, autor o identificador del mod.
+mod_manager/hint_mod_sort_title = Ordenación
+mod_manager/hint_mod_sort_body = Solo cambia el orden de las tarjetas: por nombre, autor o estado de instalación.
+mod_manager/hint_filters_reset_title = Restablecer filtros
+mod_manager/hint_filters_reset_body = Restaura la búsqueda, los estados, las categorías y la agrupación predeterminados.
+mod_manager/hint_group_categories_title = Agrupar por categorías
+mod_manager/hint_group_categories_body = Agrupa las tarjetas en secciones sin cambiar los mods.
+mod_manager/hint_mod_card_title = Tarjeta del mod
+mod_manager/hint_mod_card_body = Haz clic en una zona libre para abrir la descripción, las dependencias y todas las acciones.
+mod_manager/hint_mod_version_title = Versión del mod
+mod_manager/hint_mod_version_body = Elige la versión que instalar o actualizar. Las marcas indican la más reciente y la instalada.
+mod_manager/hint_mod_action_title = Acción del mod
+mod_manager/hint_mod_action_body = La acción depende del estado: instalar, actualizar, cambiar de versión, reinstalar o eliminar.
+mod_manager/hint_mod_enabled_title = Carga del mod
+mod_manager/hint_mod_enabled_body = Un mod desactivado sigue en el disco, pero los juegos no lo cargan. Las partidas y los datos se conservan.
+mod_manager/hint_mod_delete_title = Eliminar mod
+mod_manager/hint_mod_delete_body = Elimina los archivos del mod del dispositivo. Las colecciones y partidas se conservan.
+mod_manager/hint_mod_collections_title = Uso en colecciones
+mod_manager/hint_mod_collections_body = Abre las colecciones que incluyen este mod.
+mod_manager/hint_collection_new_title = Nueva colección
+mod_manager/hint_collection_new_body = Crea un esquema de juego vacío al que añadir mods y mecánicas.
+mod_manager/hint_collection_apply_title = Aplicar contenido
+mod_manager/hint_collection_apply_body = Instala los mods que faltan y activa los necesarios. Antes puedes revisar el plan.
+mod_manager/hint_collection_edit_title = Configurar colección
+mod_manager/hint_collection_edit_body = Abre el contenido del juego: mods, dependencias, orden de carga y plan de cambios.
+mod_manager/hint_collection_delete_title = Eliminar colección
+mod_manager/hint_collection_delete_body = Elimina solo la colección. Los mods instalados y las partidas se conservan.
+mod_manager/hint_collection_add_mechanic_title = Añadir mecánica
+mod_manager/hint_collection_add_mechanic_body = Añade al esquema un grupo para mods relacionados y sus ajustes.
+mod_manager/hint_collection_game_title = Colección en edición
+mod_manager/hint_collection_game_body = Cambia el editor a otro juego sin cerrar esta pantalla.
+mod_manager/hint_collection_problems_title = Problemas del esquema
+mod_manager/hint_collection_problems_body = Muestra mods ausentes, versiones incompatibles y conflictos que impiden iniciar el juego.
+mod_manager/hint_collection_plan_title = Plan de cambios
+mod_manager/hint_collection_plan_body = Muestra qué mods se instalarán y activarán al aplicar el esquema.
+mod_manager/hint_collection_json_title = Esquema en JSON
+mod_manager/hint_collection_json_body = Abre el esquema como texto para revisarlo y editarlo con precisión.
+mod_manager/hint_collection_reset_title = Descartar cambios
+mod_manager/hint_collection_reset_body = Restaura el último esquema guardado. No desinstala los mods existentes.
+mod_manager/hint_collection_links_title = Enlaces del esquema
+mod_manager/hint_collection_links_body = Muestra u oculta las líneas de dependencia entre grupos y mods.
+mod_manager/hint_load_order_title = Orden de carga
+mod_manager/hint_load_order_body = Los mods se cargan de arriba abajo. Si dos sustituyen el mismo recurso, prevalece el inferior.
mod_manager/sort_tooltip = Ordenar la lista: por nombre, autor o estado de instalación.
mod_manager/filters_reset_tooltip = Devolver todos los filtros y el cuadro de búsqueda a sus valores predeterminados.
mod_manager/collection_json_tooltip = Abrir el esquema como JSON sin formato: verlo, editarlo y aplicarlo de vuelta.
@@ -236,3 +283,29 @@ mod_manager/collection_reset_tooltip = Descartar todos los cambios sin guardar d
mod_manager/collection_game_tooltip = Cambiar el esquema que se está editando a otra colección.
mod_manager/collection_plan_tooltip = Abrir el plan: qué instalará y activará la aplicación.
mod_manager/collection_problems_tooltip = Abrir la lista de problemas: mods que faltan, versiones y conflictos.
+
+# Graphite collection editor
+mod_manager/collection_links_selected = Enlaces seleccionados
+mod_manager/collection_links_all = Todos los enlaces
+mod_manager/collection_links_none = Sin enlaces
+mod_manager/collection_canvas_search = Buscar en el esquema…
+mod_manager/collection_canvas_fit = Ajustar ancho
+mod_manager/collection_canvas_arrange = Organizar
+mod_manager/collection_canvas_focus = Ver selección
+mod_manager/collection_version_caption = Versión para esta colección
+mod_manager/collection_version_hint = Es el requisito del juego, no la versión instalada del mod.
+mod_manager/collection_version_edit = Cambiar requisito
+mod_manager/collection_version_any = Cualquiera
+mod_manager/collection_version_minimum = Como mínimo
+mod_manager/collection_version_exact = Exacta
+mod_manager/collection_version_branch = Rama
+mod_manager/collection_version_maximum = Como máximo
+mod_manager/collection_version_greater = Mayor que
+mod_manager/collection_version_less = Menor que
+mod_manager/collection_version_branch_hint = Rama: ^1 acepta 1.x; ^1.2 acepta 1.2.x.
+mod_manager/collection_version_invalid = Versión no válida. Introduce, por ejemplo, 2.0.0.
+mod_manager/collection_role_hint = El grupo describe la función del mod en este juego; otro juego puede asignarle otra función.
+mod_manager/collection_used_by = Requerido por: {0}
+mod_manager/collection_other_role = {0} → {1}
+mod_manager/hint_collection_dependencies_title = Dependencias y función de los grupos
+mod_manager/hint_collection_dependencies_body = Dependencia → mod que la necesita. La posición y los grupos no definen el orden de carga. El grupo describe la función del mod en este juego; otro juego puede asignarle otra función.
diff --git a/locale/ja.properties b/locale/ja.properties
index ddd9cad..86b3eaa 100644
--- a/locale/ja.properties
+++ b/locale/ja.properties
@@ -219,16 +219,63 @@ mod_manager/collection_delete_confirm = コレクション「{0}」を削除し
mod_manager/collection_delete_done = コレクションを削除しました。MOD はシステムに残っています。
mod_manager/collection_nested_readonly = このブロックはさらに深く入れ子になっています——変更するには単独で開いてください。
mod_manager/collection_forked = ブロック「{0}」をこのゲーム用にコピーしました——他のゲームは変わりません。
-mod_manager/help_open = この画面の操作の説明を表示
-mod_manager/help_close = ヘルプを閉じる
-mod_manager/help_mods_title = MOD
-mod_manager/help_mods_body = これは端末にインストールされたModの一覧です。ヘッダーの検索ボックスで名前からModを探し、更新ボタンでカタログを読み込み直します。新しくインストールしたModは、更新するとすぐ一覧に現れます。Modのカードをクリックすると、説明・バージョン・実行できる操作を示すページが開きます。各カードのスイッチで、そのModを使うゲームに対して有効と無効を切り替えられます。無効にしたModはファイルをそのまま残しますが、ゲームには読み込まれません。無効化されたModのシーンや内容は、もう一度有効にするまで実行中のゲームから消えます。セーブデータはどちらの場合も保たれます。
-mod_manager/help_mod_page_title = Modのページ
-mod_manager/help_mod_page_body = このページでは一つのModを詳しく表示します。説明、作者、バージョン、そして依存しているModの一覧です。ここから現在のゲームに対してModを有効または無効にでき、Modがシーンを提供していれば、そのシーンを直接開くこともできます。説明の下にあるリンクは、このModが含まれるコレクションへ移動します。戻るボタンとEscapeキーでModの一覧に戻ります。Modの有効・無効の状態はゲームと一緒に保存され、再起動の後も変わらないので、毎回設定し直す必要はありません。同じファイルを含むModが二つあれば、どちらが優先されるかもページに表示されます。
-mod_manager/help_collections_title = コレクション
-mod_manager/help_collections_body = コレクションタブには、ゲームのコレクションが並びます。コレクションとは、ひとつのゲームとして遊べるModのまとまりです。各カードにはカバー画像、タイトル、そしてコレクションに含まれるModが表示されます。カードをクリックしてコレクションを開き、「構成」ボタンで構成エディターを開けます。コレクションをインストールすると、必要なModがまとめて取り込まれます。コレクションを削除してもセーブデータは決して消えません。ゲームのデータは休止状態で待機し、コレクションを戻せば一緒に戻ります。
-mod_manager/help_scheme_title = 構成エディター
-mod_manager/help_scheme_body = 構成エディターは、コレクションの中身を変更します。どのModをゲームに参加させ、どの順序で読み込むかをここで決めます。チェックボックスの切り替えでModを追加・削除し、行をドラッグして読み込み順を変更します。同じファイルを含むMod同士は、後から読み込まれる方が優先されます。保存の前に構成が検証され、不足している依存関係があれば警告が出ます。変更は次にゲームを起動したときに適用されます。セーブデータはそのまま残り、存在しないModのデータは、そのModが戻ってくるまで眠ります。
+mod_manager/help_open = コンテキストヒント(F1)
+mod_manager/help_active = コントロールにポインターを合わせる · 左クリックで固定 · Escで終了
+mod_manager/collection_order_legend = 依存先 → それを必要とするMOD。カードの位置やグループの境界は読み込み順を決めません。
+mod_manager/enable_tooltip = このMODを使用するゲームで読み込みます。
+mod_manager/disable_tooltip = このMODを読み込みません。ファイルとセーブは残ります。
+mod_manager/hint_mods_tab_title = MOD
+mod_manager/hint_mods_tab_body = カタログとインストール済みMODです。ファイル、バージョン、ゲームでの読み込みを管理します。
+mod_manager/hint_collections_tab_title = コレクション
+mod_manager/hint_collections_tab_body = 独立したゲームとして実行できるMODのセットです。内容は構成エディターで変更できます。
+mod_manager/hint_collection_search_title = コレクションを検索
+mod_manager/hint_collection_search_body = タイトル、説明、ID、タグでカードを絞り込みます。
+mod_manager/hint_refresh_title = 更新
+mod_manager/hint_refresh_body = カタログを再読み込みし、インストール済みMODと照合します。現在の設定は保持されます。
+mod_manager/hint_mod_search_title = MODを検索
+mod_manager/hint_mod_search_body = MODのタイトル、作者、IDで一覧を絞り込みます。
+mod_manager/hint_mod_sort_title = 並べ替え
+mod_manager/hint_mod_sort_body = カードの順序だけを名前、作者、インストール状態で並べ替えます。
+mod_manager/hint_filters_reset_title = フィルターをリセット
+mod_manager/hint_filters_reset_body = 検索、状態、カテゴリー、グループ化を初期設定に戻します。
+mod_manager/hint_group_categories_title = カテゴリーでグループ化
+mod_manager/hint_group_categories_body = MODを変更せず、カードをカテゴリー別にまとめます。
+mod_manager/hint_mod_card_title = MODカード
+mod_manager/hint_mod_card_body = カードの空いている部分をクリックすると、説明、依存関係、全操作を開きます。
+mod_manager/hint_mod_version_title = MODのバージョン
+mod_manager/hint_mod_version_body = インストールや更新に使うバージョンを選びます。最新版とインストール済み版が印で分かります。
+mod_manager/hint_mod_action_title = MODの操作
+mod_manager/hint_mod_action_body = 状態に応じて、インストール、更新、バージョン変更、再インストール、削除を実行します。
+mod_manager/hint_mod_enabled_title = MODの読み込み
+mod_manager/hint_mod_enabled_body = 無効なMODはディスクに残りますが、ゲームでは読み込まれません。セーブとMODデータは保持されます。
+mod_manager/hint_mod_delete_title = MODを削除
+mod_manager/hint_mod_delete_body = MODファイルを端末から削除します。コレクションとセーブデータは削除しません。
+mod_manager/hint_mod_collections_title = 使用しているコレクション
+mod_manager/hint_mod_collections_body = このMODを含むコレクションを開きます。
+mod_manager/hint_collection_new_title = 新しいコレクション
+mod_manager/hint_collection_new_body = 空のゲーム構成を作成します。MODとメカニクスはエディターで追加できます。
+mod_manager/hint_collection_apply_title = 内容を適用
+mod_manager/hint_collection_apply_body = 不足しているMODをインストールし、必要なMODを有効にします。事前にプランを確認できます。
+mod_manager/hint_collection_edit_title = コレクションを設定
+mod_manager/hint_collection_edit_body = MOD、依存関係、読み込み順、変更プランを開きます。
+mod_manager/hint_collection_delete_title = コレクションを削除
+mod_manager/hint_collection_delete_body = コレクションだけを削除し、インストール済みMODとセーブデータは保持します。
+mod_manager/hint_collection_add_mechanic_title = メカニクスを追加
+mod_manager/hint_collection_add_mechanic_body = 関連するMODと設定をまとめるグループを構成に追加します。
+mod_manager/hint_collection_game_title = 編集中のコレクション
+mod_manager/hint_collection_game_body = この画面を閉じずに、エディターを別のゲームへ切り替えます。
+mod_manager/hint_collection_problems_title = 構成の問題
+mod_manager/hint_collection_problems_body = 起動を妨げる不足MOD、互換性のないバージョン、競合を表示します。
+mod_manager/hint_collection_plan_title = 変更プラン
+mod_manager/hint_collection_plan_body = 構成の適用時にインストールおよび有効化されるMODを表示します。
+mod_manager/hint_collection_json_title = JSON形式の構成
+mod_manager/hint_collection_json_body = 構成をテキストで開き、確認と精密な編集を行えます。
+mod_manager/hint_collection_reset_title = 変更を破棄
+mod_manager/hint_collection_reset_body = 最後に保存した構成に戻します。インストール済みMODは削除しません。
+mod_manager/hint_collection_links_title = 構成のリンク
+mod_manager/hint_collection_links_body = グループとMODの依存関係を示す線の表示を切り替えます。
+mod_manager/hint_load_order_title = 読み込み順
+mod_manager/hint_load_order_body = MODは上から下へ読み込まれます。同じリソースを置き換える場合は下のMODが優先されます。
mod_manager/sort_tooltip = リストの並べ替え:名前・作者・インストール状態。
mod_manager/filters_reset_tooltip = すべてのフィルターと検索ボックスを既定の状態に戻します。
mod_manager/collection_json_tooltip = 構成を生のJSONとして開きます。表示・編集して元に適用できます。
@@ -236,3 +283,29 @@ mod_manager/collection_reset_tooltip = 保存していない構成の変更を
mod_manager/collection_game_tooltip = 編集中の構成を別のコレクションに切り替えます。
mod_manager/collection_plan_tooltip = プランを開きます:適用で何をインストールし、何を有効にするか。
mod_manager/collection_problems_tooltip = 問題の一覧を開きます:不足しているMod、バージョン、競合。
+
+# Graphite collection editor
+mod_manager/collection_links_selected = 選択中の接続
+mod_manager/collection_links_all = すべての接続
+mod_manager/collection_links_none = 接続を非表示
+mod_manager/collection_canvas_search = 図内を検索…
+mod_manager/collection_canvas_fit = 幅に合わせる
+mod_manager/collection_canvas_arrange = 自動配置
+mod_manager/collection_canvas_focus = 選択を表示
+mod_manager/collection_version_caption = このコレクションのバージョン
+mod_manager/collection_version_hint = ゲームの要件です。インストール済みのMODバージョンは変わりません。
+mod_manager/collection_version_edit = 要件を変更
+mod_manager/collection_version_any = 任意
+mod_manager/collection_version_minimum = 以上
+mod_manager/collection_version_exact = 固定
+mod_manager/collection_version_branch = ブランチ
+mod_manager/collection_version_maximum = 以下
+mod_manager/collection_version_greater = より新しい
+mod_manager/collection_version_less = より古い
+mod_manager/collection_version_branch_hint = ブランチ:^1 は 1.x、^1.2 は 1.2.x を許可します。
+mod_manager/collection_version_invalid = 無効なバージョンです。例:2.0.0。
+mod_manager/collection_role_hint = グループはこのゲームでのMODの用途です。他のゲームでは異なる役割になり得ます。
+mod_manager/collection_used_by = 必要とするMOD:{0}
+mod_manager/collection_other_role = {0} → {1}
+mod_manager/hint_collection_dependencies_title = 依存関係とグループの用途
+mod_manager/hint_collection_dependencies_body = 依存先 → それを必要とするMOD。カードの位置やグループの境界は読み込み順を決めません。 グループはこのゲームでのMODの用途です。他のゲームでは異なる役割になり得ます。
diff --git a/locale/ko.properties b/locale/ko.properties
index 82368dd..92c7fd8 100644
--- a/locale/ko.properties
+++ b/locale/ko.properties
@@ -219,7 +219,63 @@ mod_manager/collection_delete_confirm = 컬렉션 "{0}"이(가) 삭제됩니다.
mod_manager/collection_delete_done = 컬렉션을 삭제했습니다. 모드는 시스템에 남아 있습니다.
mod_manager/collection_nested_readonly = 이 블록은 더 깊이 중첩되어 있습니다 — 바꾸려면 따로 여세요.
mod_manager/collection_forked = 블록 "{0}"을(를) 이 게임용으로 복사했습니다 — 다른 게임은 그대로입니다.
-mod_manager/help_open = 이 화면의 조작 방법 보기
+mod_manager/help_open = 상황별 힌트 (F1)
+mod_manager/help_active = 컨트롤에 포인터를 올리세요 · 왼쪽 클릭으로 고정 · Esc로 종료
+mod_manager/collection_order_legend = 의존 모드 → 이를 필요로 하는 모드. 카드 위치와 그룹 경계는 로드 순서를 정하지 않습니다.
+mod_manager/enable_tooltip = 이 모드를 사용하는 게임에서 불러옵니다.
+mod_manager/disable_tooltip = 이 모드를 불러오지 않습니다. 파일과 저장 데이터는 유지됩니다.
+mod_manager/hint_mods_tab_title = 모드
+mod_manager/hint_mods_tab_body = 카탈로그와 설치된 모드입니다. 파일, 버전, 게임에서의 불러오기를 관리합니다.
+mod_manager/hint_collections_tab_title = 컬렉션
+mod_manager/hint_collections_tab_body = 별도의 게임처럼 실행되는 모드 묶음입니다. 구성 편집기에서 내용을 바꿀 수 있습니다.
+mod_manager/hint_collection_search_title = 컬렉션 검색
+mod_manager/hint_collection_search_body = 제목, 설명, 식별자, 태그로 카드를 필터링합니다.
+mod_manager/hint_refresh_title = 새로 고침
+mod_manager/hint_refresh_body = 카탈로그를 다시 불러와 설치된 모드와 비교합니다. 현재 설정은 유지됩니다.
+mod_manager/hint_mod_search_title = 모드 검색
+mod_manager/hint_mod_search_body = 모드 제목, 제작자 또는 식별자로 목록을 필터링합니다.
+mod_manager/hint_mod_sort_title = 정렬
+mod_manager/hint_mod_sort_body = 카드 순서만 이름, 제작자 또는 설치 상태 기준으로 바꿉니다.
+mod_manager/hint_filters_reset_title = 필터 초기화
+mod_manager/hint_filters_reset_body = 검색, 상태, 카테고리, 그룹화를 기본값으로 되돌립니다.
+mod_manager/hint_group_categories_title = 카테고리별 그룹화
+mod_manager/hint_group_categories_body = 모드는 바꾸지 않고 카드만 카테고리별로 묶습니다.
+mod_manager/hint_mod_card_title = 모드 카드
+mod_manager/hint_mod_card_body = 카드의 빈 곳을 클릭하면 설명, 의존성과 모든 작업이 열립니다.
+mod_manager/hint_mod_version_title = 모드 버전
+mod_manager/hint_mod_version_body = 설치하거나 업데이트할 버전을 선택합니다. 최신 버전과 설치된 버전이 표시됩니다.
+mod_manager/hint_mod_action_title = 모드 작업
+mod_manager/hint_mod_action_body = 상태에 따라 설치, 업데이트, 버전 변경, 재설치 또는 삭제를 실행합니다.
+mod_manager/hint_mod_enabled_title = 모드 불러오기
+mod_manager/hint_mod_enabled_body = 꺼진 모드는 디스크에 남지만 게임에서 불러오지 않습니다. 저장 파일과 모드 데이터는 유지됩니다.
+mod_manager/hint_mod_delete_title = 모드 삭제
+mod_manager/hint_mod_delete_body = 장치에서 모드 파일을 삭제합니다. 컬렉션과 게임 저장 파일은 삭제하지 않습니다.
+mod_manager/hint_mod_collections_title = 사용 중인 컬렉션
+mod_manager/hint_mod_collections_body = 이 모드가 포함된 컬렉션을 엽니다.
+mod_manager/hint_collection_new_title = 새 컬렉션
+mod_manager/hint_collection_new_body = 빈 게임 구성을 만듭니다. 편집기에서 모드와 메커닉을 추가하세요.
+mod_manager/hint_collection_apply_title = 구성 적용
+mod_manager/hint_collection_apply_body = 없는 모드를 설치하고 필요한 모드를 켭니다. 먼저 플랜을 확인할 수 있습니다.
+mod_manager/hint_collection_edit_title = 컬렉션 구성
+mod_manager/hint_collection_edit_body = 게임의 모드, 의존성, 불러오기 순서와 변경 플랜을 엽니다.
+mod_manager/hint_collection_delete_title = 컬렉션 삭제
+mod_manager/hint_collection_delete_body = 컬렉션만 삭제합니다. 설치된 모드와 게임 저장 파일은 유지됩니다.
+mod_manager/hint_collection_add_mechanic_title = 메커닉 추가
+mod_manager/hint_collection_add_mechanic_body = 관련 모드와 설정을 묶는 그룹을 구성에 추가합니다.
+mod_manager/hint_collection_game_title = 편집 중인 컬렉션
+mod_manager/hint_collection_game_body = 현재 화면을 닫지 않고 편집기를 다른 게임으로 전환합니다.
+mod_manager/hint_collection_problems_title = 구성 문제
+mod_manager/hint_collection_problems_body = 실행을 막는 누락 모드, 호환되지 않는 버전과 충돌을 보여 줍니다.
+mod_manager/hint_collection_plan_title = 변경 플랜
+mod_manager/hint_collection_plan_body = 구성을 적용할 때 설치하고 켤 모드를 보여 줍니다.
+mod_manager/hint_collection_json_title = JSON 구성
+mod_manager/hint_collection_json_body = 구성을 텍스트로 열어 검토하고 정밀하게 편집합니다.
+mod_manager/hint_collection_reset_title = 변경 취소
+mod_manager/hint_collection_reset_body = 마지막으로 저장한 구성을 복원합니다. 설치된 모드는 제거하지 않습니다.
+mod_manager/hint_collection_links_title = 구성 연결
+mod_manager/hint_collection_links_body = 그룹과 모드 사이의 의존성 선을 표시하거나 숨깁니다.
+mod_manager/hint_load_order_title = 불러오기 순서
+mod_manager/hint_load_order_body = 모드는 위에서 아래로 불러와집니다. 같은 리소스를 바꾸면 아래 모드가 적용됩니다.
mod_manager/help_close = 도움말 닫기
mod_manager/help_mods_title = 모드
mod_manager/help_mods_body = 이 장치에 설치된 모드 목록입니다. 헤더의 검색 상자로 이름을 찾고, 새로 고침 버튼으로 카탈로그를 다시 읽습니다. 방금 설치한 모드도 새로 고치면 바로 목록에 나타납니다. 모드 카드를 클릭하면 설명, 버전, 동작이 있는 페이지가 열립니다. 각 카드의 스위치는 그 모드를 사용하는 게임에서 모드를 켜거나 끕니다. 꺼진 모드는 파일을 유지하지만 불러오지 않습니다. 꺼진 모드의 장면과 콘텐츠는 다시 켤 때까지 실행 중인 게임에서 사라지지만, 저장 파일은 언제나 유지됩니다.
@@ -236,3 +292,29 @@ mod_manager/collection_reset_tooltip = 저장하지 않은 구성 변경을 모
mod_manager/collection_game_tooltip = 편집 중인 구성을 다른 컬렉션으로 바꿉니다.
mod_manager/collection_plan_tooltip = 플랜을 엽니다: 적용 시 무엇을 설치하고 켜는지.
mod_manager/collection_problems_tooltip = 문제 목록을 엽니다: 빠진 모드, 버전 차이, 충돌.
+
+# Graphite collection editor
+mod_manager/collection_links_selected = 선택한 연결
+mod_manager/collection_links_all = 모든 연결
+mod_manager/collection_links_none = 연결 숨기기
+mod_manager/collection_canvas_search = 도식에서 찾기…
+mod_manager/collection_canvas_fit = 너비에 맞춤
+mod_manager/collection_canvas_arrange = 자동 배치
+mod_manager/collection_canvas_focus = 선택 항목 보기
+mod_manager/collection_version_caption = 이 컬렉션의 버전 요구 사항
+mod_manager/collection_version_hint = 게임의 버전 요구 사항이며 설치된 모드 버전은 바뀌지 않습니다.
+mod_manager/collection_version_edit = 요구 사항 변경
+mod_manager/collection_version_any = 모든 버전
+mod_manager/collection_version_minimum = 최소 버전
+mod_manager/collection_version_exact = 정확한 버전
+mod_manager/collection_version_branch = 버전 분기
+mod_manager/collection_version_maximum = 최대 버전
+mod_manager/collection_version_greater = 초과
+mod_manager/collection_version_less = 미만
+mod_manager/collection_version_branch_hint = 분기: ^1은 1.x를, ^1.2는 1.2.x를 허용합니다.
+mod_manager/collection_version_invalid = 잘못된 버전입니다. 예: 2.0.0.
+mod_manager/collection_role_hint = 그룹은 이 게임에서 모드의 용도를 설명합니다. 다른 게임에서는 역할이 다를 수 있습니다.
+mod_manager/collection_used_by = 필요로 하는 모드: {0}
+mod_manager/collection_other_role = {0} → {1}
+mod_manager/hint_collection_dependencies_title = 의존성과 그룹 용도
+mod_manager/hint_collection_dependencies_body = 의존 모드 → 이를 필요로 하는 모드. 카드 위치와 그룹 경계는 로드 순서를 정하지 않습니다. 그룹은 이 게임에서 모드의 용도를 설명합니다. 다른 게임에서는 역할이 다를 수 있습니다.
diff --git a/locale/ru.properties b/locale/ru.properties
index cb2b5f3..5d1a874 100644
--- a/locale/ru.properties
+++ b/locale/ru.properties
@@ -219,16 +219,63 @@ mod_manager/collection_delete_confirm = Коллекция «{0}» будет у
mod_manager/collection_delete_done = Коллекция удалена. Моды остались в системе.
mod_manager/collection_nested_readonly = Этот блок вложен глубже — откройте его отдельно, чтобы изменить.
mod_manager/collection_forked = Блок «{0}» скопирован для этой игры — другие игры не изменятся.
-mod_manager/help_open = Подсказка: что делают элементы этого экрана
-mod_manager/help_close = Закрыть справку
-mod_manager/help_mods_title = Моды
-mod_manager/help_mods_body = Список модов, установленных на этом устройстве. Поле поиска в заголовке находит мод по названию, кнопка обновления перечитывает каталог — только что установленные моды появляются сразу. Щёлкните карточку мода, чтобы открыть его страницу с описанием, версией и действиями. Переключатель на карточке включает или выключает мод для игр, которые его используют; выключенный мод хранит файлы, но не загружается. Сцены и содержимое выключенного мода исчезают из запущенных игр, пока вы снова его не включите; сохранения остаются в любом случае.
-mod_manager/help_mod_page_title = Страница мода
-mod_manager/help_mod_page_body = Здесь показан один мод подробно: описание, автор, версия и список его зависимостей. Отсюда можно включить или выключить мод для текущих игр, а также открыть его сцены, если мод их предоставляет. Ссылки под описанием ведут к коллекциям, куда мод входит. Кнопка «Назад» и Escape возвращают к списку модов; состояние мода сохраняется вместе с игрой и переживает перезапуск, задавать его заново не нужно. Если два мода содержат один и тот же файл, страница подскажет, какой из них победит.
-mod_manager/help_collections_title = Коллекции
-mod_manager/help_collections_body = Вкладка коллекций показывает игровые коллекции: готовые наборы модов, которые играются как отдельные игры. На каждой карточке — обложка, название и список модов коллекции. Щёлкните карточку, чтобы открыть коллекцию, и нажмите «Настроить», чтобы открыть редактор схемы. Установка коллекции загружает нужные ей моды; удаление коллекции никогда не трогает ваши сохранения — данные игры спят и возвращаются вместе с коллекцией.
-mod_manager/help_scheme_title = Редактор схемы
-mod_manager/help_scheme_body = Редактор схемы меняет состав коллекции: какие моды участвуют в игре и в каком порядке они загружаются. Включайте и выключайте флажки, чтобы добавить или убрать мод, перетаскивайте строки, чтобы изменить порядок загрузки, — поздние моды перекрывают ранние, когда оба содержат один и тот же файл. Перед сохранением редактор проверяет схему и предупреждает о недостающих зависимостях. Изменения вступают в силу при следующем запуске игры; сохранения остаются, а данные отсутствующих модов спят до их возвращения.
+mod_manager/help_open = Контекстные подсказки (F1)
+mod_manager/help_active = Наведите на элемент · ЛКМ — закрепить подсказку · Esc — выйти
+mod_manager/collection_order_legend = Зависимость → мод, которому она нужна. Положение карточки и границы групп не задают порядок загрузки.
+mod_manager/enable_tooltip = Загружать мод в играх, которые его используют.
+mod_manager/disable_tooltip = Не загружать мод. Файлы и сохранения останутся.
+mod_manager/hint_mods_tab_title = Моды
+mod_manager/hint_mods_tab_body = Каталог и установленные моды. Здесь вы управляете файлами, версиями и загрузкой модов в играх.
+mod_manager/hint_collections_tab_title = Коллекции
+mod_manager/hint_collections_tab_body = Готовые наборы модов, которые запускаются как отдельные игры. Их состав можно менять в редакторе схемы.
+mod_manager/hint_collection_search_title = Поиск коллекций
+mod_manager/hint_collection_search_body = Фильтрует карточки по названию, описанию, идентификатору и тегам.
+mod_manager/hint_refresh_title = Обновить
+mod_manager/hint_refresh_body = Заново загружает каталог и сверяет его с установленными модами. Текущие настройки не сбрасываются.
+mod_manager/hint_mod_search_title = Поиск модов
+mod_manager/hint_mod_search_body = Фильтрует список по названию, автору или идентификатору мода.
+mod_manager/hint_mod_sort_title = Сортировка
+mod_manager/hint_mod_sort_body = Меняет только порядок карточек: по имени, автору или состоянию установки.
+mod_manager/hint_filters_reset_title = Сброс фильтров
+mod_manager/hint_filters_reset_body = Возвращает поиск, состояния, категории и группировку к значениям по умолчанию.
+mod_manager/hint_group_categories_title = Группировка по категориям
+mod_manager/hint_group_categories_body = Объединяет карточки в разделы. Состояние модов при этом не меняется.
+mod_manager/hint_mod_card_title = Карточка мода
+mod_manager/hint_mod_card_body = Нажмите на свободное место карточки, чтобы открыть описание, зависимости и все действия с модом.
+mod_manager/hint_mod_version_title = Версия мода
+mod_manager/hint_mod_version_body = Выбирает версию для установки или обновления. Пометки показывают последнюю и уже установленную версии.
+mod_manager/hint_mod_action_title = Действие с модом
+mod_manager/hint_mod_action_body = Действие зависит от состояния: установка, обновление, смена версии, переустановка или удаление.
+mod_manager/hint_mod_enabled_title = Загрузка мода
+mod_manager/hint_mod_enabled_body = Выключенный мод остаётся на диске, но не загружается в играх. Сохранения и данные модов сохраняются.
+mod_manager/hint_mod_delete_title = Удаление мода
+mod_manager/hint_mod_delete_body = Удаляет файлы мода с устройства. Коллекции и сохранения игр не удаляются.
+mod_manager/hint_mod_collections_title = Использование в коллекциях
+mod_manager/hint_mod_collections_body = Открывает коллекции, в состав которых входит этот мод.
+mod_manager/hint_collection_new_title = Новая коллекция
+mod_manager/hint_collection_new_body = Создаёт пустую схему игры. Моды и правила можно добавить в редакторе.
+mod_manager/hint_collection_apply_title = Применить состав
+mod_manager/hint_collection_apply_body = Устанавливает недостающие моды и включает нужные. Перед выполнением можно посмотреть план.
+mod_manager/hint_collection_edit_title = Настроить коллекцию
+mod_manager/hint_collection_edit_body = Открывает состав игры: моды, зависимости, порядок загрузки и план изменений.
+mod_manager/hint_collection_delete_title = Удаление коллекции
+mod_manager/hint_collection_delete_body = Удаляет только коллекцию. Установленные моды и сохранения игр остаются.
+mod_manager/hint_collection_add_mechanic_title = Добавить механику
+mod_manager/hint_collection_add_mechanic_body = Добавляет в схему группу для связанных модов и их настроек.
+mod_manager/hint_collection_game_title = Редактируемая коллекция
+mod_manager/hint_collection_game_body = Переключает редактор на другую игру, не закрывая текущий экран.
+mod_manager/hint_collection_problems_title = Проблемы схемы
+mod_manager/hint_collection_problems_body = Показывает отсутствующие моды, неподходящие версии и конфликты, которые мешают запуску.
+mod_manager/hint_collection_plan_title = План изменений
+mod_manager/hint_collection_plan_body = Показывает, какие моды будут установлены и включены при применении схемы.
+mod_manager/hint_collection_json_title = Схема в JSON
+mod_manager/hint_collection_json_body = Открывает текстовое представление схемы для просмотра и точного редактирования.
+mod_manager/hint_collection_reset_title = Отменить изменения
+mod_manager/hint_collection_reset_body = Возвращает последнюю сохранённую схему. Уже установленные моды не удаляются.
+mod_manager/hint_collection_links_title = Связи на схеме
+mod_manager/hint_collection_links_body = Показывает или скрывает линии зависимостей между группами и модами.
+mod_manager/hint_load_order_title = Порядок загрузки
+mod_manager/hint_load_order_body = Моды загружаются сверху вниз. Если два мода заменяют один ресурс, используется вариант нижнего мода.
mod_manager/sort_tooltip = Сортировка списка: по имени, автору или состоянию установки.
mod_manager/filters_reset_tooltip = Вернуть все фильтры и поле поиска к значениям по умолчанию.
mod_manager/collection_json_tooltip = Открыть схему как чистый JSON: посмотреть, отредактировать и применить обратно.
@@ -236,3 +283,29 @@ mod_manager/collection_reset_tooltip = Отменить все несохран
mod_manager/collection_game_tooltip = Переключить редактируемую схему на другую коллекцию.
mod_manager/collection_plan_tooltip = Открыть план: что установит и включит применение схемы.
mod_manager/collection_problems_tooltip = Открыть список проблем: отсутствующие моды, версии и конфликты.
+
+# Graphite collection editor
+mod_manager/collection_links_selected = Связи выбранного
+mod_manager/collection_links_all = Все связи
+mod_manager/collection_links_none = Без связей
+mod_manager/collection_canvas_search = Найти на схеме…
+mod_manager/collection_canvas_fit = Вписать
+mod_manager/collection_canvas_arrange = Расположить
+mod_manager/collection_canvas_focus = К выбранному
+mod_manager/collection_version_caption = Версия для этой коллекции
+mod_manager/collection_version_hint = Это требование игры, а не установленная версия мода.
+mod_manager/collection_version_edit = Изменить требование
+mod_manager/collection_version_any = Любая
+mod_manager/collection_version_minimum = Не ниже
+mod_manager/collection_version_exact = Точно
+mod_manager/collection_version_branch = Ветка
+mod_manager/collection_version_maximum = Не выше
+mod_manager/collection_version_greater = Выше
+mod_manager/collection_version_less = Ниже
+mod_manager/collection_version_branch_hint = Ветка: ^1 принимает 1.x; ^1.2 принимает 1.2.x.
+mod_manager/collection_version_invalid = Некорректная версия. Укажите, например, 2.0.0.
+mod_manager/collection_role_hint = Группа задаёт назначение мода в этой игре; в другой игре его роль может отличаться.
+mod_manager/collection_used_by = Нужен для: {0}
+mod_manager/collection_other_role = {0} → {1}
+mod_manager/hint_collection_dependencies_title = Зависимости и назначение групп
+mod_manager/hint_collection_dependencies_body = Зависимость → мод, которому она нужна. Положение карточки и границы групп не задают порядок загрузки. Группа задаёт назначение мода в этой игре; в другой игре его роль может отличаться.
diff --git a/locale/vi.properties b/locale/vi.properties
index 3f8343c..452240b 100644
--- a/locale/vi.properties
+++ b/locale/vi.properties
@@ -219,16 +219,63 @@ mod_manager/collection_delete_confirm = Bộ sưu tập «{0}» sẽ bị xóa.
mod_manager/collection_delete_done = Đã xóa bộ sưu tập. Các mod của nó vẫn ở trong hệ thống.
mod_manager/collection_nested_readonly = Khối này nằm lồng sâu hơn — hãy mở riêng nó để thay đổi.
mod_manager/collection_forked = Đã sao chép khối "{0}" cho game này — các game khác giữ nguyên.
-mod_manager/help_open = Xem chú thích các điều khiển trên màn hình này
-mod_manager/help_close = Đóng trợ giúp
-mod_manager/help_mods_title = Mod
-mod_manager/help_mods_body = Đây là danh sách mod đã cài trên thiết bị này. Dùng ô tìm kiếm ở đầu trang để tìm mod theo tên, và nút làm mới để đọc lại danh mục — mod mới cài sẽ xuất hiện ngay. Nhấp vào thẻ mod để mở trang của nó với mô tả, phiên bản và các thao tác. Công tắc trên mỗi thẻ bật hoặc tắt mod cho những trò chơi dùng nó; mod bị tắt vẫn giữ tệp nhưng không được nạp. Cảnh và nội dung của mod bị tắt biến mất khỏi trò chơi đang chạy cho tới khi bạn bật lại, còn bản lưu của bạn vẫn được giữ.
-mod_manager/help_mod_page_title = Trang mod
-mod_manager/help_mod_page_body = Trang này hiển thị chi tiết một mod: mô tả, tác giả, phiên bản và danh sách phụ thuộc. Từ đây bạn có thể bật hoặc tắt mod cho các trò chơi hiện tại, và mở các cảnh của mod nếu nó có cung cấp. Các liên kết dưới phần mô tả dẫn tới những bộ sưu tập có chứa mod này. Nút quay lại và Escape đưa bạn về danh sách mod; trạng thái bật/tắt của mod được lưu cùng trò chơi và giữ nguyên sau khi khởi động lại, nên không cần đặt lại mỗi lần. Nếu hai mod đều có cùng một tệp, trang sẽ cho biết tệp của mod nào thắng.
-mod_manager/help_collections_title = Bộ sưu tập
-mod_manager/help_collections_body = Thẻ bộ sưu tập liệt kê các bộ sưu tập trò chơi: những gói mod sẵn sàng chơi như những trò chơi riêng biệt. Mỗi thẻ hiển thị ảnh bìa, tên và các mod mà bộ sưu tập gồm có. Nhấp vào thẻ để mở bộ sưu tập, dùng nút Cấu hình để mở trình sửa sơ đồ của nó. Cài đặt bộ sưu tập sẽ tải các mod nó cần; gỡ bỏ không bao giờ xoá bản lưu của bạn — dữ liệu trò chơi ngủ đông và quay lại cùng với bộ sưu tập.
-mod_manager/help_scheme_title = Trình sửa sơ đồ
-mod_manager/help_scheme_body = Trình sửa sơ đồ thay đổi nội dung của bộ sưu tập: mod nào tham gia trò chơi và theo thứ tự nạp nào. Bật tắt các ô chọn để thêm hoặc bỏ mod, kéo các hàng để đổi thứ tự nạp — khi hai mod đều có cùng một tệp, mod nạp sau sẽ thắng. Trước khi lưu, trình sửa sơ đồ kiểm tra sơ đồ và cảnh báo về phụ thuộc còn thiếu. Thay đổi có hiệu lực ở lần khởi động trò chơi kế tiếp; bản lưu của bạn được giữ lại, dữ liệu của các mod vắng mặt ngủ cho tới khi mod trở lại.
+mod_manager/help_open = Gợi ý theo ngữ cảnh (F1)
+mod_manager/help_active = Di chuột lên điều khiển · Nhấp trái để ghim · Esc để thoát
+mod_manager/collection_order_legend = Phụ thuộc → mod cần nó. Vị trí thẻ và ranh giới nhóm không quyết định thứ tự tải.
+mod_manager/enable_tooltip = Nạp mod này trong các game có sử dụng nó.
+mod_manager/disable_tooltip = Không nạp mod này. Tệp và bản lưu vẫn được giữ.
+mod_manager/hint_mods_tab_title = Mod
+mod_manager/hint_mods_tab_body = Danh mục và mod đã cài. Quản lý tệp, phiên bản và việc game nạp mod tại đây.
+mod_manager/hint_collections_tab_title = Bộ sưu tập
+mod_manager/hint_collections_tab_body = Các gói mod chạy như game độc lập. Có thể đổi nội dung trong trình sửa sơ đồ.
+mod_manager/hint_collection_search_title = Tìm bộ sưu tập
+mod_manager/hint_collection_search_body = Lọc thẻ theo tên, mô tả, định danh và thẻ phân loại.
+mod_manager/hint_refresh_title = Làm mới
+mod_manager/hint_refresh_body = Nạp lại danh mục và đối chiếu với mod đã cài. Thiết lập hiện tại được giữ nguyên.
+mod_manager/hint_mod_search_title = Tìm mod
+mod_manager/hint_mod_search_body = Lọc danh sách theo tên, tác giả hoặc định danh mod.
+mod_manager/hint_mod_sort_title = Sắp xếp
+mod_manager/hint_mod_sort_body = Chỉ đổi thứ tự thẻ theo tên, tác giả hoặc trạng thái cài đặt.
+mod_manager/hint_filters_reset_title = Đặt lại bộ lọc
+mod_manager/hint_filters_reset_body = Khôi phục tìm kiếm, trạng thái, danh mục và cách nhóm mặc định.
+mod_manager/hint_group_categories_title = Nhóm theo danh mục
+mod_manager/hint_group_categories_body = Nhóm các thẻ vào từng mục mà không thay đổi mod.
+mod_manager/hint_mod_card_title = Thẻ mod
+mod_manager/hint_mod_card_body = Nhấp vào chỗ trống trên thẻ để mở mô tả, phụ thuộc và mọi thao tác khả dụng.
+mod_manager/hint_mod_version_title = Phiên bản mod
+mod_manager/hint_mod_version_body = Chọn phiên bản để cài hoặc cập nhật. Nhãn chỉ ra bản mới nhất và bản đang cài.
+mod_manager/hint_mod_action_title = Thao tác với mod
+mod_manager/hint_mod_action_body = Thao tác tùy trạng thái: cài, cập nhật, đổi phiên bản, cài lại hoặc xóa.
+mod_manager/hint_mod_enabled_title = Nạp mod
+mod_manager/hint_mod_enabled_body = Mod bị tắt vẫn trên đĩa nhưng game không nạp. Bản lưu và dữ liệu mod được giữ.
+mod_manager/hint_mod_delete_title = Xóa mod
+mod_manager/hint_mod_delete_body = Xóa tệp mod khỏi thiết bị. Không xóa bộ sưu tập và bản lưu game.
+mod_manager/hint_mod_collections_title = Dùng trong bộ sưu tập
+mod_manager/hint_mod_collections_body = Mở các bộ sưu tập có chứa mod này.
+mod_manager/hint_collection_new_title = Bộ sưu tập mới
+mod_manager/hint_collection_new_body = Tạo sơ đồ game trống. Thêm mod và cơ chế trong trình sửa.
+mod_manager/hint_collection_apply_title = Áp dụng nội dung
+mod_manager/hint_collection_apply_body = Cài mod còn thiếu và bật mod cần thiết. Có thể xem kế hoạch trước.
+mod_manager/hint_collection_edit_title = Cấu hình bộ sưu tập
+mod_manager/hint_collection_edit_body = Mở nội dung game: mod, phụ thuộc, thứ tự nạp và kế hoạch thay đổi.
+mod_manager/hint_collection_delete_title = Xóa bộ sưu tập
+mod_manager/hint_collection_delete_body = Chỉ xóa bộ sưu tập. Mod đã cài và bản lưu game được giữ.
+mod_manager/hint_collection_add_mechanic_title = Thêm cơ chế
+mod_manager/hint_collection_add_mechanic_body = Thêm nhóm cho các mod liên quan và thiết lập của chúng vào sơ đồ.
+mod_manager/hint_collection_game_title = Bộ sưu tập đang sửa
+mod_manager/hint_collection_game_body = Chuyển trình sửa sang game khác mà không đóng màn hình này.
+mod_manager/hint_collection_problems_title = Vấn đề của sơ đồ
+mod_manager/hint_collection_problems_body = Liệt kê mod thiếu, phiên bản không tương thích và xung đột ngăn game chạy.
+mod_manager/hint_collection_plan_title = Kế hoạch thay đổi
+mod_manager/hint_collection_plan_body = Cho biết mod nào sẽ được cài và bật khi áp dụng sơ đồ.
+mod_manager/hint_collection_json_title = Sơ đồ dạng JSON
+mod_manager/hint_collection_json_body = Mở sơ đồ dưới dạng văn bản để kiểm tra và sửa chính xác.
+mod_manager/hint_collection_reset_title = Hủy thay đổi
+mod_manager/hint_collection_reset_body = Khôi phục sơ đồ đã lưu gần nhất. Không gỡ các mod đã cài.
+mod_manager/hint_collection_links_title = Liên kết sơ đồ
+mod_manager/hint_collection_links_body = Hiện hoặc ẩn đường phụ thuộc giữa các nhóm và mod.
+mod_manager/hint_load_order_title = Thứ tự nạp
+mod_manager/hint_load_order_body = Mod nạp từ trên xuống dưới. Khi hai mod thay cùng một tài nguyên, mod phía dưới được dùng.
mod_manager/sort_tooltip = Sắp xếp danh sách: theo tên, tác giả hoặc trạng thái cài đặt.
mod_manager/filters_reset_tooltip = Đưa mọi bộ lọc và ô tìm kiếm về mặc định.
mod_manager/collection_json_tooltip = Mở sơ đồ dưới dạng JSON thô: xem, sửa rồi áp dụng lại.
@@ -236,3 +283,29 @@ mod_manager/collection_reset_tooltip = Bỏ mọi thay đổi chưa lưu của s
mod_manager/collection_game_tooltip = Chuyển sơ đồ đang sửa sang bộ sưu tập khác.
mod_manager/collection_plan_tooltip = Mở kế hoạch: việc áp dụng sẽ cài và bật những gì.
mod_manager/collection_problems_tooltip = Mở danh sách vấn đề: mod còn thiếu, khác phiên bản và xung đột.
+
+# Graphite collection editor
+mod_manager/collection_links_selected = Liên kết đã chọn
+mod_manager/collection_links_all = Mọi liên kết
+mod_manager/collection_links_none = Ẩn liên kết
+mod_manager/collection_canvas_search = Tìm trong sơ đồ…
+mod_manager/collection_canvas_fit = Vừa chiều rộng
+mod_manager/collection_canvas_arrange = Sắp xếp
+mod_manager/collection_canvas_focus = Hiện mục đã chọn
+mod_manager/collection_version_caption = Phiên bản cho bộ sưu tập này
+mod_manager/collection_version_hint = Đây là yêu cầu của game, không phải phiên bản mod đã cài.
+mod_manager/collection_version_edit = Đổi yêu cầu
+mod_manager/collection_version_any = Bất kỳ
+mod_manager/collection_version_minimum = Tối thiểu
+mod_manager/collection_version_exact = Chính xác
+mod_manager/collection_version_branch = Nhánh
+mod_manager/collection_version_maximum = Tối đa
+mod_manager/collection_version_greater = Lớn hơn
+mod_manager/collection_version_less = Nhỏ hơn
+mod_manager/collection_version_branch_hint = Nhánh: ^1 chấp nhận 1.x; ^1.2 chấp nhận 1.2.x.
+mod_manager/collection_version_invalid = Phiên bản không hợp lệ. Ví dụ: 2.0.0.
+mod_manager/collection_role_hint = Nhóm mô tả vai trò của mod trong game này; game khác có thể gán vai trò khác.
+mod_manager/collection_used_by = Cần cho: {0}
+mod_manager/collection_other_role = {0} → {1}
+mod_manager/hint_collection_dependencies_title = Phụ thuộc và vai trò nhóm
+mod_manager/hint_collection_dependencies_body = Phụ thuộc → mod cần nó. Vị trí thẻ và ranh giới nhóm không quyết định thứ tự tải. Nhóm mô tả vai trò của mod trong game này; game khác có thể gán vai trò khác.
diff --git a/locale/zh.properties b/locale/zh.properties
index 0621b28..92dd2d7 100644
--- a/locale/zh.properties
+++ b/locale/zh.properties
@@ -219,16 +219,63 @@ mod_manager/collection_delete_confirm = 合集"{0}"将被删除。它的模组
mod_manager/collection_delete_done = 合集已删除。它的模组仍在系统中。
mod_manager/collection_nested_readonly = 这个模块嵌套得更深——请单独打开它来修改。
mod_manager/collection_forked = 模块"{0}"已为本游戏复制——其他游戏保持不变。
-mod_manager/help_open = 查看本界面各控件的说明
-mod_manager/help_close = 关闭帮助
-mod_manager/help_mods_title = 模组
-mod_manager/help_mods_body = 这里是已安装到这台设备上的全部模组的列表。顶部的搜索框可以按名称快速查找模组,旁边的刷新按钮会重新读取目录,刚安装的模组会立刻出现。点击任意模组卡片即可打开它的页面,查看描述、版本和可以执行的操作。每张卡片上的开关决定使用该模组的游戏是否加载它;停用的模组会保留自己的文件,但不会进入游戏。被停用模组的场景和内容会从正在运行的游戏中消失,直到你重新启用它为止,你的存档数据始终保留。列表为空时先刷新目录;如果模组只属于某个游戏,切换游戏后它会出现在对应的列表里。
-mod_manager/help_mod_page_title = 模组页面
-mod_manager/help_mod_page_body = 这个页面详细展示一个模组:描述、作者、版本,以及它依赖的其他模组。在这里可以把模组对当前的游戏启用或停用,如果模组提供了场景,也可以直接打开这些场景。描述下方的链接会跳转到包含这个模组的合集。返回按钮和 Esc 键带你回到模组列表;模组的开关状态会和游戏一起保存,重启之后依然保持不变,不需要每次重新设置。如果两个模组带有同一个文件,页面会告诉你哪一方生效。如果你只是想试用一个模组,可以在这里看完它的依赖,再去合集中决定是否安装,避免装上互相冲突的内容。
-mod_manager/help_collections_title = 合集
-mod_manager/help_collections_body = 合集标签页列出游戏的合集:合集是一组打包好的模组,玩起来就像一款独立的游戏。每张卡片显示封面、标题,以及这个合集包含的模组。点击卡片即可打开合集,使用“配置”按钮可以打开它的结构编辑器。安装合集会把它需要的模组一并取回来;移除合集绝不会删除你的存档——游戏的数据只是安静等待,合集回来时会随之恢复,你不会丢失任何东西。合集的封面上还标有它的类别和来源,安装之前可以先把几个合集对比一下,再决定要玩哪一个;找不到想要的合集时,先用刷新按钮更新目录再来查看。
-mod_manager/help_scheme_title = 结构编辑器
-mod_manager/help_scheme_body = 结构编辑器修改合集的内容:哪些模组参与这个游戏,以及它们按什么顺序加载。勾选或取消勾选可以添加或移除模组,拖动行可以改变加载顺序——当两个模组带有同一个文件时,后加载的会覆盖先加载的,页面上会用提示标出这样的覆盖关系。保存之前编辑器会检查结构,并对缺失的依赖提出警告,照着提示补齐即可。更改在下次启动游戏时生效;你的存档保留不动,缺失模组的数据会休眠,等模组回来时一并恢复。对结构没有把握时,先不要改动游戏自带的合集,复制一份再做试验更安全。
+mod_manager/help_open = 上下文提示(F1)
+mod_manager/help_active = 将指针移到控件上 · 左键单击固定提示 · Esc 退出
+mod_manager/collection_order_legend = 依赖项 → 使用它的模组。卡片位置和分组边界不决定加载顺序。
+mod_manager/enable_tooltip = 在使用此模组的游戏中加载它。
+mod_manager/disable_tooltip = 不加载此模组。文件和存档会保留。
+mod_manager/hint_mods_tab_title = 模组
+mod_manager/hint_mods_tab_body = 模组目录和已安装的模组。在这里管理文件、版本以及游戏是否加载它们。
+mod_manager/hint_collections_tab_title = 合集
+mod_manager/hint_collections_tab_body = 可作为独立游戏运行的模组组合。可以在结构编辑器中更改其内容。
+mod_manager/hint_collection_search_title = 搜索合集
+mod_manager/hint_collection_search_body = 按标题、描述、标识符和标签筛选卡片。
+mod_manager/hint_refresh_title = 刷新
+mod_manager/hint_refresh_body = 重新加载目录并与已安装的模组核对,保留当前设置。
+mod_manager/hint_mod_search_title = 搜索模组
+mod_manager/hint_mod_search_body = 按模组标题、作者或标识符筛选列表。
+mod_manager/hint_mod_sort_title = 排序
+mod_manager/hint_mod_sort_body = 只改变卡片顺序:按名称、作者或安装状态。
+mod_manager/hint_filters_reset_title = 重置筛选
+mod_manager/hint_filters_reset_body = 恢复默认的搜索、状态、类别和分组方式。
+mod_manager/hint_group_categories_title = 按类别分组
+mod_manager/hint_group_categories_body = 将卡片按类别分区,不改变模组本身。
+mod_manager/hint_mod_card_title = 模组卡片
+mod_manager/hint_mod_card_body = 点击卡片空白处可打开描述、依赖项和全部可用操作。
+mod_manager/hint_mod_version_title = 模组版本
+mod_manager/hint_mod_version_body = 选择要安装或更新的版本。标记会指出最新版和当前安装版。
+mod_manager/hint_mod_action_title = 模组操作
+mod_manager/hint_mod_action_body = 操作随模组状态变化:安装、更新、切换版本、重新安装或删除。
+mod_manager/hint_mod_enabled_title = 加载模组
+mod_manager/hint_mod_enabled_body = 停用的模组仍保留在磁盘上,但游戏不会加载。存档和模组数据都会保留。
+mod_manager/hint_mod_delete_title = 删除模组
+mod_manager/hint_mod_delete_body = 从设备上删除模组文件,不删除合集和游戏存档。
+mod_manager/hint_mod_collections_title = 用于合集
+mod_manager/hint_mod_collections_body = 打开包含此模组的合集。
+mod_manager/hint_collection_new_title = 新合集
+mod_manager/hint_collection_new_body = 创建空的游戏结构,然后在编辑器中添加模组和机制。
+mod_manager/hint_collection_apply_title = 应用内容
+mod_manager/hint_collection_apply_body = 安装缺失的模组并启用所需模组。执行前可以先查看计划。
+mod_manager/hint_collection_edit_title = 配置合集
+mod_manager/hint_collection_edit_body = 打开游戏内容:模组、依赖项、加载顺序和更改计划。
+mod_manager/hint_collection_delete_title = 删除合集
+mod_manager/hint_collection_delete_body = 只删除合集,保留已安装的模组和游戏存档。
+mod_manager/hint_collection_add_mechanic_title = 添加机制
+mod_manager/hint_collection_add_mechanic_body = 在结构中添加一组相关模组及其设置。
+mod_manager/hint_collection_game_title = 正在编辑的合集
+mod_manager/hint_collection_game_body = 不关闭当前界面,直接切换到另一个游戏。
+mod_manager/hint_collection_problems_title = 结构问题
+mod_manager/hint_collection_problems_body = 列出阻碍游戏运行的缺失模组、不兼容版本和冲突。
+mod_manager/hint_collection_plan_title = 更改计划
+mod_manager/hint_collection_plan_body = 显示应用结构时将安装和启用哪些模组。
+mod_manager/hint_collection_json_title = JSON 结构
+mod_manager/hint_collection_json_body = 以文本形式打开结构,便于检查和精确编辑。
+mod_manager/hint_collection_reset_title = 放弃更改
+mod_manager/hint_collection_reset_body = 恢复上次保存的结构,不移除已经安装的模组。
+mod_manager/hint_collection_links_title = 结构连线
+mod_manager/hint_collection_links_body = 显示或隐藏组与模组之间的依赖连线。
+mod_manager/hint_load_order_title = 加载顺序
+mod_manager/hint_load_order_body = 模组从上到下加载。两个模组替换同一资源时,下方的模组生效。
mod_manager/sort_tooltip = 对列表排序:按名称、作者或安装状态。
mod_manager/filters_reset_tooltip = 把所有筛选条件和搜索框恢复为默认值。
mod_manager/collection_json_tooltip = 以原始 JSON 打开结构:查看、编辑后再应用回去。
@@ -236,3 +283,29 @@ mod_manager/collection_reset_tooltip = 放弃所有未保存的结构修改。
mod_manager/collection_game_tooltip = 把正在编辑的结构切换到另一个合集。
mod_manager/collection_plan_tooltip = 打开计划:应用时会安装和启用哪些模组。
mod_manager/collection_problems_tooltip = 打开问题列表:缺失的模组、版本差距和冲突。
+
+# Graphite collection editor
+mod_manager/collection_links_selected = 所选模组的连线
+mod_manager/collection_links_all = 所有连线
+mod_manager/collection_links_none = 隐藏连线
+mod_manager/collection_canvas_search = 在图中查找…
+mod_manager/collection_canvas_fit = 适应宽度
+mod_manager/collection_canvas_arrange = 自动排列
+mod_manager/collection_canvas_focus = 显示所选项
+mod_manager/collection_version_caption = 此合集的版本要求
+mod_manager/collection_version_hint = 这是游戏的版本要求,不是已安装的模组版本。
+mod_manager/collection_version_edit = 修改要求
+mod_manager/collection_version_any = 任意版本
+mod_manager/collection_version_minimum = 不低于
+mod_manager/collection_version_exact = 精确版本
+mod_manager/collection_version_branch = 版本分支
+mod_manager/collection_version_maximum = 不高于
+mod_manager/collection_version_greater = 高于
+mod_manager/collection_version_less = 低于
+mod_manager/collection_version_branch_hint = 分支:^1 接受 1.x;^1.2 接受 1.2.x。
+mod_manager/collection_version_invalid = 版本无效。请输入例如 2.0.0。
+mod_manager/collection_role_hint = 分组说明模组在本游戏中的用途;在其他游戏中,它可以有不同的作用。
+mod_manager/collection_used_by = 被以下模组依赖:{0}
+mod_manager/collection_other_role = {0} → {1}
+mod_manager/hint_collection_dependencies_title = 依赖关系与分组用途
+mod_manager/hint_collection_dependencies_body = 依赖项 → 使用它的模组。卡片位置和分组边界不决定加载顺序。 分组说明模组在本游戏中的用途;在其他游戏中,它可以有不同的作用。
diff --git a/scenes/components/mod_help_panel.tscn b/scenes/components/mod_help_panel.tscn
index 42c2174..f920f8c 100644
--- a/scenes/components/mod_help_panel.tscn
+++ b/scenes/components/mod_help_panel.tscn
@@ -9,55 +9,68 @@ anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
+mouse_filter = 2
script = ExtResource("1_help")
-[node name="Dim" type="ColorRect" parent="."]
-layout_mode = 1
-anchors_preset = 15
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 2
-color = Color(0, 0, 0, 0.6)
-
-[node name="Center" type="CenterContainer" parent="."]
-layout_mode = 1
-anchors_preset = 15
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 2
+[node name="Highlight" type="Panel" parent="."]
+visible = false
+layout_mode = 0
mouse_filter = 2
-[node name="Frame" type="PanelContainer" parent="Center"]
-custom_minimum_size = Vector2(820, 600)
-layout_mode = 2
+[node name="Card" type="PanelContainer" parent="."]
+visible = false
+custom_minimum_size = Vector2(320, 0)
+layout_mode = 0
+mouse_filter = 0
-[node name="Margin" type="MarginContainer" parent="Center/Frame"]
+[node name="Margin" type="MarginContainer" parent="Card"]
layout_mode = 2
-theme_override_constants/margin_left = 24
-theme_override_constants/margin_top = 18
-theme_override_constants/margin_right = 24
-theme_override_constants/margin_bottom = 18
+theme_override_constants/margin_left = 12
+theme_override_constants/margin_top = 10
+theme_override_constants/margin_right = 12
+theme_override_constants/margin_bottom = 10
-[node name="Column" type="VBoxContainer" parent="Center/Frame/Margin"]
+[node name="Column" type="VBoxContainer" parent="Card/Margin"]
layout_mode = 2
-theme_override_constants/separation = 12
+theme_override_constants/separation = 4
-[node name="Header" type="HBoxContainer" parent="Center/Frame/Margin/Column"]
+[node name="Title" type="Label" parent="Card/Margin/Column"]
layout_mode = 2
-theme_override_constants/separation = 12
+theme_override_font_sizes/font_size = 13
+autowrap_mode = 3
-[node name="Title" type="Label" parent="Center/Frame/Margin/Column/Header"]
+[node name="Body" type="RichTextLabel" parent="Card/Margin/Column"]
+custom_minimum_size = Vector2(296, 0)
layout_mode = 2
size_flags_horizontal = 3
-theme_override_font_sizes/font_size = 20
-
-[node name="Close" type="Button" parent="Center/Frame/Margin/Column/Header"]
-layout_mode = 2
-
-[node name="Body" type="RichTextLabel" parent="Center/Frame/Margin/Column"]
-layout_mode = 2
-size_flags_vertical = 3
+theme_override_font_sizes/normal_font_size = 12
bbcode_enabled = true
selection_enabled = true
+scroll_active = false
+fit_content = true
+autowrap_mode = 3
+
+[node name="Footer" type="PanelContainer" parent="."]
+layout_mode = 1
+anchors_preset = 12
+anchor_top = 1.0
+anchor_right = 1.0
+anchor_bottom = 1.0
+offset_top = -34.0
+grow_horizontal = 2
+grow_vertical = 0
+mouse_filter = 2
+
+[node name="Margin" type="MarginContainer" parent="Footer"]
+layout_mode = 2
+theme_override_constants/margin_left = 16
+theme_override_constants/margin_top = 7
+theme_override_constants/margin_right = 16
+theme_override_constants/margin_bottom = 7
+mouse_filter = 2
+
+[node name="FooterText" type="Label" parent="Footer/Margin"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 12
+horizontal_alignment = 1
+mouse_filter = 2
diff --git a/scenes/mod_collections_screen.tscn b/scenes/mod_collections_screen.tscn
index 7865a7d..b5fbaca 100644
--- a/scenes/mod_collections_screen.tscn
+++ b/scenes/mod_collections_screen.tscn
@@ -2,6 +2,7 @@
[ext_resource type="Script" path="src/ModCollectionsScreen.cs" id="1_screen"]
[ext_resource type="Script" path="src/UI/CollectionSchemeCanvas.cs" id="2_canvas"]
+[ext_resource type="Script" path="src/UI/CollectionMiniMap.cs" id="3_map"]
[node name="ModCollectionsScreen" type="Control"]
layout_mode = 3
@@ -70,10 +71,9 @@ layout_mode = 2
size_flags_horizontal = 3
mouse_filter = 2
-[node name="EdgesToggle" type="CheckBox" parent="Margin/Root/Header"]
+[node name="EdgesToggle" type="OptionButton" parent="Margin/Root/Header"]
layout_mode = 2
size_flags_vertical = 4
-button_pressed = true
[node name="Problems" type="Button" parent="Margin/Root/Header"]
layout_mode = 2
@@ -112,25 +112,101 @@ size_flags_vertical = 4
layout_mode = 2
theme_override_constants/separation = 8
+[node name="Tools" type="HBoxContainer" parent="Margin/Root"]
+layout_mode = 2
+theme_override_constants/separation = 8
+
+[node name="AddMod" type="Button" parent="Margin/Root/Tools"]
+layout_mode = 2
+text = "mod_manager/collection_add_mod"
+
+[node name="Search" type="LineEdit" parent="Margin/Root/Tools"]
+custom_minimum_size = Vector2(170, 0)
+layout_mode = 2
+placeholder_text = "mod_manager/collection_canvas_search"
+
+[node name="Spacer" type="Control" parent="Margin/Root/Tools"]
+layout_mode = 2
+size_flags_horizontal = 3
+mouse_filter = 2
+
+[node name="ZoomOut" type="Button" parent="Margin/Root/Tools"]
+layout_mode = 2
+text = "−"
+
+[node name="Zoom" type="Label" parent="Margin/Root/Tools"]
+custom_minimum_size = Vector2(42, 0)
+layout_mode = 2
+horizontal_alignment = 1
+vertical_alignment = 1
+text = "100%"
+
+[node name="ZoomIn" type="Button" parent="Margin/Root/Tools"]
+layout_mode = 2
+text = "+"
+
+[node name="Fit" type="Button" parent="Margin/Root/Tools"]
+layout_mode = 2
+text = "mod_manager/collection_canvas_fit"
+
+[node name="Arrange" type="Button" parent="Margin/Root/Tools"]
+layout_mode = 2
+text = "mod_manager/collection_canvas_arrange"
+
+[node name="Focus" type="Button" parent="Margin/Root/Tools"]
+layout_mode = 2
+text = "mod_manager/collection_canvas_focus"
+
+[node name="OrderLegend" type="Label" parent="Margin/Root"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 12
+mouse_filter = 0
+
[node name="Body" type="HSplitContainer" parent="Margin/Root"]
layout_mode = 2
size_flags_vertical = 3
-[node name="CanvasScroll" type="ScrollContainer" parent="Margin/Root/Body"]
+[node name="CanvasHost" type="Control" parent="Margin/Root/Body"]
+custom_minimum_size = Vector2(440, 240)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
+mouse_filter = 2
+
+[node name="CanvasScroll" type="ScrollContainer" parent="Margin/Root/Body/CanvasHost"]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
horizontal_scroll_mode = 1
vertical_scroll_mode = 1
-[node name="SchemeCanvas" type="Control" parent="Margin/Root/Body/CanvasScroll"]
+[node name="SchemeCanvas" type="Control" parent="Margin/Root/Body/CanvasHost/CanvasScroll"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource("2_canvas")
+[node name="MiniMap" type="Control" parent="Margin/Root/Body/CanvasHost"]
+layout_mode = 1
+anchors_preset = 3
+anchor_left = 1.0
+anchor_top = 1.0
+anchor_right = 1.0
+anchor_bottom = 1.0
+offset_left = -170.0
+offset_top = -124.0
+offset_right = -18.0
+offset_bottom = -24.0
+grow_horizontal = 0
+grow_vertical = 0
+mouse_filter = 0
+script = ExtResource("3_map")
+
[node name="Details" type="PanelContainer" parent="Margin/Root/Body"]
-custom_minimum_size = Vector2(380, 0)
+custom_minimum_size = Vector2(330, 0)
layout_mode = 2
[node name="DetailScroll" type="ScrollContainer" parent="Margin/Root/Body/Details"]
@@ -174,6 +250,46 @@ autowrap_mode = 3
layout_mode = 2
autowrap_mode = 3
+[node name="VersionEditor" type="VBoxContainer" parent="Margin/Root/Body/Details/DetailScroll/Detail"]
+visible = false
+layout_mode = 2
+theme_override_constants/separation = 7
+
+[node name="Caption" type="Label" parent="Margin/Root/Body/Details/DetailScroll/Detail/VersionEditor"]
+layout_mode = 2
+text = "mod_manager/collection_version_caption"
+autowrap_mode = 3
+
+[node name="Fields" type="HBoxContainer" parent="Margin/Root/Body/Details/DetailScroll/Detail/VersionEditor"]
+layout_mode = 2
+theme_override_constants/separation = 8
+
+[node name="Policy" type="OptionButton" parent="Margin/Root/Body/Details/DetailScroll/Detail/VersionEditor/Fields"]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="Value" type="LineEdit" parent="Margin/Root/Body/Details/DetailScroll/Detail/VersionEditor/Fields"]
+custom_minimum_size = Vector2(100, 0)
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="Rule" type="Label" parent="Margin/Root/Body/Details/DetailScroll/Detail/VersionEditor"]
+layout_mode = 2
+autowrap_mode = 3
+
+[node name="Hint" type="Label" parent="Margin/Root/Body/Details/DetailScroll/Detail/VersionEditor"]
+layout_mode = 2
+text = "mod_manager/collection_version_hint"
+autowrap_mode = 3
+
+[node name="Feedback" type="Label" parent="Margin/Root/Body/Details/DetailScroll/Detail/VersionEditor"]
+layout_mode = 2
+autowrap_mode = 3
+
+[node name="SaveRule" type="Button" parent="Margin/Root/Body/Details/DetailScroll/Detail/VersionEditor"]
+layout_mode = 2
+text = "mod_manager/collection_version_edit"
+
[node name="DetailExtra" type="VBoxContainer" parent="Margin/Root/Body/Details/DetailScroll/Detail"]
layout_mode = 2
theme_override_constants/separation = 6
diff --git a/src/ModCollectionsScreen.cs b/src/ModCollectionsScreen.cs
index 03532cc..e914a79 100644
--- a/src/ModCollectionsScreen.cs
+++ b/src/ModCollectionsScreen.cs
@@ -11,6 +11,7 @@ using Godot;
using Cthangover.Mods.Interface.Base.Lists;
using Cthangover.Mods.Interface.Theming;
+using Cthangover.Mods.Interface.Tool;
namespace Mods.ModManager
{
///
@@ -39,7 +40,7 @@ namespace Mods.ModManager
private Button _newGame;
private Button _apply;
private OptionButton _gameSelect;
- private CheckBox _edgesToggle;
+ private OptionButton _edgesToggle;
private Button _pillProblems;
private Button _pillPlan;
private Label _modsCount;
@@ -86,6 +87,17 @@ namespace Mods.ModManager
private Button _revert;
private Button _delete;
private Label _savesInfo;
+ private Button _addMod;
+ private LineEdit _canvasSearch;
+ private Label _zoomLabel;
+ private VBoxContainer _versionEditor;
+ private OptionButton _versionPolicy;
+ private LineEdit _versionValue;
+ private Label _versionRule;
+ private Label _versionFeedback;
+ private ModCollectionModRef _versionReference;
+ private bool _fitAfterBuild = true;
+ private bool _fitQueued;
/// Drafts created by "Duplicate", mapped to the game they were copied from (offer to copy its saves).
private readonly Dictionary _duplicatedFrom = new(StringComparer.OrdinalIgnoreCase);
@@ -134,6 +146,7 @@ namespace Mods.ModManager
public void OpenCollection(string collectionId)
{
_currentId = collectionId;
+ _fitAfterBuild = true;
_selectedGroupKey = null;
_selectedModId = null;
// The gallery re-reads the store on every refresh; re-read it here
@@ -163,6 +176,254 @@ namespace Mods.ModManager
UnsubscribeEvents();
}
+ private void BindGraphiteControls()
+ {
+ var tools = "Margin/Root/Tools/";
+ _addMod = GetNode
- public void Init(string modId, string role, string title, string version, string stateLabel, Color stateColor, string tooltip)
+ public void Init(string groupKey, string modId, string role, string title, string version, string requirement, string stateLabel, Color stateColor, string tooltip)
{
EnsureConstructed();
ModId = modId;
+ GroupKey = groupKey;
_stateColor = stateColor;
_role.Text = string.IsNullOrEmpty(role) ? string.Empty : role.ToUpperInvariant();
_name.Text = title;
- _meta.Text = string.IsNullOrEmpty(version) ? stateLabel : $"{version} · {stateLabel}";
+ _meta.Text = string.IsNullOrEmpty(version) ? stateLabel
+ : version + (string.IsNullOrEmpty(requirement) ? string.Empty : " · " + requirement);
_dot.Color = stateColor;
- _style.BorderColor = stateColor;
+ _style.BorderColor = stateColor == UiTokens.Danger || stateColor == UiTokens.DangerText || stateColor == UiTokens.Warning
+ ? stateColor : UiTokens.LineCard;
_panel.TooltipText = tooltip ?? string.Empty;
}
@@ -75,7 +81,10 @@ namespace Mods.ModManager
public void SetSelected(bool selected)
{
EnsureConstructed();
- _style.BorderColor = selected ? UiTokens.Accent : _stateColor;
+ _style.BorderColor = selected ? UiTokens.Accent : UiTokens.LineCard;
+ _style.BgColor = selected ? UiTokens.SurfaceSelected : UiTokens.Surface1;
+ if (!selected && (_stateColor == UiTokens.Danger || _stateColor == UiTokens.DangerText || _stateColor == UiTokens.Warning))
+ _style.BorderColor = _stateColor;
}
protected override void Construct()
@@ -136,7 +145,7 @@ namespace Mods.ModManager
{
_dragging = true;
_moved = false;
- Selected?.Invoke(ModId);
+ Selected?.Invoke(this);
}
else
{
@@ -168,7 +177,7 @@ namespace Mods.ModManager
_moved = true;
Position = clamped;
- Moved?.Invoke(ModId, clamped);
+ Moved?.Invoke(this, clamped);
AcceptEvent();
}
}
diff --git a/src/UI/CollectionSchemeCanvas.cs b/src/UI/CollectionSchemeCanvas.cs
index 6b656ec..db4f83d 100644
--- a/src/UI/CollectionSchemeCanvas.cs
+++ b/src/UI/CollectionSchemeCanvas.cs
@@ -59,6 +59,9 @@ namespace Mods.ModManager
/// Raised after any drag or resize ends, so the layout can be flushed to the store.
public event Action LayoutChanged;
+ /// Scale or scroll changed; the toolbar and overview may refresh their presentation.
+ public event Action ViewChanged;
+
/// Whether dependency lines are painted; toggled from the header.
public bool ShowEdges { get; set; } = true;
@@ -74,6 +77,116 @@ namespace Mods.ModManager
private readonly Dictionary _cards = new(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary _chips = new(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary _chipGroups = new(StringComparer.OrdinalIgnoreCase);
+ private readonly Dictionary _instances = new(StringComparer.OrdinalIgnoreCase);
+ private readonly Dictionary _visibleFrames = new(StringComparer.OrdinalIgnoreCase);
+ private Control _content;
+ private CollectionMiniMap _miniMap;
+ private long _edgeMode;
+ private float _zoom = 1f;
+ private string _search = string.Empty;
+
+ /// Scale of the canvas contents, independent of persisted logical coordinates.
+ public float Zoom => _zoom;
+
+ /// Occupied logical bounds, excluding the empty scrollable workspace floor.
+ public Vector2 ContentBounds { get; private set; } = new(460f, 240f);
+
+ /// Current visible rectangle in logical coordinates, used by the overview map.
+ public Rect2 VisibleBounds
+ {
+ get
+ {
+ var scroll = GetParent();
+ return scroll == null ? new Rect2() : new Rect2(
+ new Vector2(scroll.ScrollHorizontal, scroll.ScrollVertical) / _zoom,
+ scroll.Size / _zoom);
+ }
+ }
+
+ /// Overview rectangles use the same logical geometry as the group frames.
+ public IReadOnlyDictionary GroupFrames => _visibleFrames;
+
+ /// Connects the scene-defined overview control after both controls entered the tree.
+ public void SetMiniMap(CollectionMiniMap miniMap)
+ {
+ _miniMap = miniMap;
+ _miniMap.Bind(this);
+ }
+
+ /// 0: selected mod only, 1: all dependencies, 2: hidden; group boundaries never change severity.
+ public void SetEdgeMode(long mode)
+ {
+ _edgeMode = mode;
+ SetEdgesVisible(mode != 2);
+ RebuildEdges();
+ }
+
+ /// Filters presentation only; hidden search matches do not leave the game's composition.
+ public void SetSearch(string query)
+ {
+ _search = query?.Trim() ?? string.Empty;
+ foreach (var chip in _instances.Values)
+ {
+ var node = FindNode(chip.ModId);
+ var match = _search.Length == 0 || chip.ModId.Contains(_search, StringComparison.OrdinalIgnoreCase)
+ || (node?.Title?.Contains(_search, StringComparison.OrdinalIgnoreCase) ?? false);
+ chip.Modulate = new Color(1, 1, 1, match ? 1f : 0.2f);
+ }
+ }
+
+ /// Increases scale without rewriting any stored group or chip positions.
+ public void ZoomIn() => SetZoom(_zoom * 1.15f);
+
+ /// Decreases scale without rewriting any stored group or chip positions.
+ public void ZoomOut() => SetZoom(_zoom / 1.15f);
+
+ /// Fits occupied group bounds horizontally; the empty scroll floor does not shrink the scheme.
+ public void FitWidth()
+ {
+ var scroll = GetParent();
+ if (scroll == null || scroll.Size.X <= 0f)
+ return;
+ SetZoom(Mathf.Min(1f, (scroll.Size.X - 24f) / Mathf.Max(1f, ContentBounds.X)));
+ scroll.ScrollHorizontal = 0;
+ scroll.ScrollVertical = 0;
+ RefreshViewport();
+ }
+
+ /// Re-packs the current groups; composition and individual chip locations stay unchanged.
+ public void ArrangeGroups()
+ {
+ var defaults = ComputeDefaultLayout();
+ foreach (var pair in defaults)
+ {
+ var rect = Rect(pair.Key);
+ rect.X = pair.Value.X;
+ rect.Y = pair.Value.Y;
+ _cards[pair.Key].SetFrame(new Rect2(pair.Value, new Vector2(rect.W, rect.H)));
+ }
+ UpdateCanvasSize();
+ RebuildEdges();
+ LayoutChanged?.Invoke();
+ }
+
+ /// Centers the scroll view on a logical canvas position (selection or overview click).
+ public void CenterOn(Vector2 position)
+ {
+ var scroll = GetParent();
+ if (scroll == null)
+ return;
+ scroll.ScrollHorizontal = Mathf.RoundToInt(position.X * _zoom - scroll.Size.X / 2f);
+ scroll.ScrollVertical = Mathf.RoundToInt(position.Y * _zoom - scroll.Size.Y / 2f);
+ RefreshViewport();
+ }
+
+ /// Reveals the selected occurrence, keeping another group's copy from stealing focus.
+ public void ShowSelection()
+ {
+ if (SelectedModId != null && _instances.TryGetValue(SelectedGroupKey + "|" + SelectedModId, out var chip))
+ CenterOn(chip.Position + _cards[chip.GroupKey].Position + chip.Size / 2f);
+ else if (SelectedGroupKey != null && _cards.TryGetValue(SelectedGroupKey, out var card))
+ CenterOn(card.Position + card.Size / 2f);
+ }
private bool _panning;
private Vector2 _panStartMouse;
@@ -94,7 +207,7 @@ namespace Mods.ModManager
_layout.Groups ??= new Dictionary();
_layout.Mods ??= new Dictionary();
- foreach (var child in GetChildren())
+ foreach (var child in _content.GetChildren())
{
if (child != _edges)
child.QueueFree();
@@ -103,6 +216,8 @@ namespace Mods.ModManager
_cards.Clear();
_chips.Clear();
_chipGroups.Clear();
+ _instances.Clear();
+ _visibleFrames.Clear();
if (graph != null && graph.Groups.Count > 0)
{
@@ -110,11 +225,12 @@ namespace Mods.ModManager
BuildCards();
}
- _edges.SetEdges(null, _chips, this);
- MoveChild(_edges, GetChildCount() - 1);
+ _edges.SetEdges(null, _chips, _content);
+ _content.MoveChild(_edges, _content.GetChildCount() - 1);
_edges.Visible = ShowEdges;
UpdateCanvasSize();
RebuildEdges();
+ SetSearch(_search);
}
/// Highlights one group and/or one mod; pass nulls to clear.
@@ -127,8 +243,20 @@ namespace Mods.ModManager
foreach (var pair in _cards)
pair.Value.SetSelected(string.Equals(pair.Key, groupKey, StringComparison.OrdinalIgnoreCase));
- foreach (var pair in _chips)
- pair.Value.SetSelected(string.Equals(pair.Key, modId, StringComparison.OrdinalIgnoreCase));
+ foreach (var pair in _chipGroups)
+ {
+ if (_instances.TryGetValue(pair.Value + "|" + pair.Key, out var primary))
+ _chips[pair.Key] = primary;
+ }
+
+ foreach (var chip in _instances.Values)
+ {
+ var selected = string.Equals(chip.GroupKey, groupKey, StringComparison.OrdinalIgnoreCase)
+ && string.Equals(chip.ModId, modId, StringComparison.OrdinalIgnoreCase);
+ chip.SetSelected(selected);
+ if (selected)
+ _chips[chip.ModId] = chip;
+ }
RebuildEdges();
}
@@ -145,15 +273,42 @@ namespace Mods.ModManager
/// Finds the group key owning a rendered mod chip, for inspector navigation.
public string GetGroupKeyOfMod(string modId)
- => modId != null && _chipGroups.TryGetValue(modId, out var key) ? key : null;
+ {
+ if (modId != null && string.Equals(modId, SelectedModId, StringComparison.OrdinalIgnoreCase)
+ && SelectedGroupKey != null)
+ return SelectedGroupKey;
+ return modId != null && _chipGroups.TryGetValue(modId, out var key) ? key : null;
+ }
protected override void Construct()
{
MouseFilter = MouseFilterEnum.Stop;
GuiInput += OnCanvasGuiInput;
+ _content = new Control { MouseFilter = MouseFilterEnum.Ignore };
+ AddChild(_content);
+ _content.Connect("draw", Callable.From((Action)DrawGrid));
_edges = new CollectionEdgeLayer();
- AddChild(_edges);
+ _content.AddChild(_edges);
_edges.EnsureConstructed();
+ var scroll = GetParent();
+ if (scroll != null)
+ {
+ scroll.GetHScrollBar().ValueChanged += OnScrollChanged;
+ scroll.GetVScrollBar().ValueChanged += OnScrollChanged;
+ scroll.Resized += RefreshViewport;
+ }
+ }
+
+ protected override void Destruct()
+ {
+ GuiInput -= OnCanvasGuiInput;
+ var scroll = GetParent();
+ if (scroll != null && GodotObject.IsInstanceValid(scroll))
+ {
+ scroll.GetHScrollBar().ValueChanged -= OnScrollChanged;
+ scroll.GetVScrollBar().ValueChanged -= OnScrollChanged;
+ scroll.Resized -= RefreshViewport;
+ }
}
private void BuildCards()
@@ -162,7 +317,7 @@ namespace Mods.ModManager
{
var rect = _layout.Groups[group.Key];
var card = new CollectionGroupCard();
- AddChild(card);
+ _content.AddChild(card);
var summary = Summarize(group);
card.Init(group, summary.Label, summary.Color, string.Equals(group.Key, SelectedGroupKey, StringComparison.OrdinalIgnoreCase));
@@ -174,6 +329,7 @@ namespace Mods.ModManager
card.Resized += OnCardResized;
card.DragFinished += OnDragFinished;
_cards[group.Key] = card;
+ _visibleFrames[group.Key] = rect;
foreach (var mod in group.Mods)
{
@@ -183,11 +339,14 @@ namespace Mods.ModManager
card.ModsLayer.AddChild(chip);
var node = FindNode(mod.ModId);
+ var requirement = ModDependency.Parse(mod.Requirement);
chip.Init(
+ group.Key,
mod.ModId,
mod.Role,
node?.Title ?? mod.ModId,
VersionOf(node),
+ requirement.IsValid && requirement.VersionRaw != null ? requirement.Operator + requirement.VersionRaw : null,
StateLabel(node),
StateColor(node),
BuildModTooltip(mod, node));
@@ -195,6 +354,7 @@ namespace Mods.ModManager
chip.Selected += OnChipSelected;
chip.Moved += OnChipMoved;
chip.DragFinished += OnDragFinished;
+ _instances[key] = chip;
if (!_chips.ContainsKey(mod.ModId))
{
@@ -396,11 +556,11 @@ namespace Mods.ModManager
GroupSelected?.Invoke(groupKey);
}
- private void OnChipSelected(string modId)
+ private void OnChipSelected(CollectionModChip chip)
{
- SelectedModId = modId;
- SelectedGroupKey = null;
- ModSelected?.Invoke(modId);
+ SelectedModId = chip.ModId;
+ SelectedGroupKey = chip.GroupKey;
+ ModSelected?.Invoke(chip.ModId);
}
private void OnCardCommand(string groupKey, string command)
@@ -427,12 +587,9 @@ namespace Mods.ModManager
RebuildEdges();
}
- private void OnChipMoved(string modId, Vector2 position)
+ private void OnChipMoved(CollectionModChip chip, Vector2 position)
{
- if (!_chipGroups.TryGetValue(modId, out var groupKey))
- return;
-
- var key = groupKey + "|" + modId;
+ var key = chip.GroupKey + "|" + chip.ModId;
if (!_layout.Mods.TryGetValue(key, out var point) || point == null)
{
point = new ModCollectionLayoutPoint();
@@ -472,11 +629,15 @@ namespace Mods.ModManager
var size = new Vector2(
Mathf.Max(maxX + GapX + 160f, MinCanvasWidth),
Mathf.Max(maxY + GapY + 120f, MinCanvasHeight));
+ ContentBounds = new Vector2(Mathf.Max(460f, maxX + GapX), Mathf.Max(240f, maxY + GapY));
// Drives the canvas rect through the surrounding ScrollContainer.
// _edges carries FullRect anchors (CollectionEdgeLayer.Construct),
// so it follows this resize automatically; assigning its Size
// directly would be overridden and logs an anchors warning.
- CustomMinimumSize = size;
+ _content.Size = size;
+ _content.Scale = Vector2.One * _zoom;
+ CustomMinimumSize = size * _zoom;
+ RefreshViewport();
}
private void RebuildEdges()
@@ -491,18 +652,60 @@ namespace Mods.ModManager
var fromGroup = GetGroupKeyOfMod(edge.FromModId);
var toGroup = GetGroupKeyOfMod(edge.ToModId);
+ var active = string.Equals(edge.FromModId, SelectedModId, StringComparison.OrdinalIgnoreCase)
+ || string.Equals(edge.ToModId, SelectedModId, StringComparison.OrdinalIgnoreCase);
+ if (_edgeMode == 0 && !active)
+ continue;
edges.Add(new CollectionEdge
{
FromModId = edge.FromModId,
ToModId = edge.ToModId,
Cross = !string.Equals(fromGroup, toGroup, StringComparison.OrdinalIgnoreCase),
- Active = string.Equals(edge.FromModId, SelectedModId, StringComparison.OrdinalIgnoreCase)
- || string.Equals(edge.ToModId, SelectedModId, StringComparison.OrdinalIgnoreCase),
+ Active = active,
+ Problem = HasProblem(edge.FromModId) || HasProblem(edge.ToModId),
});
}
}
- _edges.SetEdges(edges, _chips, this);
+ _edges.SetEdges(edges, _chips, _content);
+ RefreshViewport();
+ }
+
+ private bool HasProblem(string modId)
+ {
+ var node = FindNode(modId);
+ return node == null || node.State == ModCollectionNodeState.Missing
+ || node.State == ModCollectionNodeState.VersionMismatch;
+ }
+
+ private void SetZoom(float value)
+ {
+ var scroll = GetParent();
+ var center = scroll == null ? Vector2.Zero : VisibleBounds.GetCenter();
+ _zoom = Mathf.Clamp(value, 0.3f, 1.5f);
+ UpdateCanvasSize();
+ CenterOn(center);
+ }
+
+ private void OnScrollChanged(double value) => RefreshViewport();
+
+ private void RefreshViewport()
+ {
+ _content?.QueueRedraw();
+ _miniMap?.QueueRedraw();
+ ViewChanged?.Invoke();
+ }
+
+ private void DrawGrid()
+ {
+ var visible = VisibleBounds;
+ var start = visible.Position.Snapped(new Vector2(20f, 20f));
+ var color = new Color(UiTokens.LineCard, 0.55f);
+ for (var x = start.X; x <= visible.End.X + 20f; x += 20f)
+ {
+ for (var y = start.Y; y <= visible.End.Y + 20f; y += 20f)
+ _content.DrawCircle(new Vector2(x, y), 0.8f, color);
+ }
}
///
@@ -516,6 +719,17 @@ namespace Mods.ModManager
///
private void OnCanvasGuiInput(InputEvent @event)
{
+ if (@event is InputEventMouseButton wheel && wheel.Pressed && wheel.CtrlPressed)
+ {
+ if (wheel.ButtonIndex == MouseButton.WheelUp)
+ ZoomIn();
+ else if (wheel.ButtonIndex == MouseButton.WheelDown)
+ ZoomOut();
+ else
+ return;
+ AcceptEvent();
+ return;
+ }
if (@event is InputEventMouseButton button && button.ButtonIndex == MouseButton.Left)
{
if (button.Pressed)
diff --git a/src/UI/CollectionsGallery.cs b/src/UI/CollectionsGallery.cs
index 1ab84e2..e5d820f 100644
--- a/src/UI/CollectionsGallery.cs
+++ b/src/UI/CollectionsGallery.cs
@@ -151,7 +151,7 @@ namespace Mods.ModManager
row.AddChild(UiKit.Spacer());
var newGame = UiKit.Button(TranslationServer.Translate("mod_manager/gallery_new_game"), ButtonKind.Primary);
- newGame.TooltipText = newGame.Text;
+ ModHelpPanel.Attach(newGame, "collection_new");
newGame.Pressed += () => NewGameRequested?.Invoke();
row.AddChild(newGame);
_host.AddChild(row);
@@ -402,7 +402,7 @@ namespace Mods.ModManager
button.Disabled = true;
}
- button.TooltipText = button.Text;
+ ModHelpPanel.Attach(button, "collection_apply");
if (action != null)
button.Pressed += action;
return button;
@@ -411,7 +411,7 @@ namespace Mods.ModManager
private Button BuildEditButton(ModCollectionGameSummary summary)
{
var button = UiKit.Button(TranslationServer.Translate("mod_manager/gallery_edit_scheme"));
- button.TooltipText = button.Text;
+ ModHelpPanel.Attach(button, "collection_edit");
button.Disabled = _installingId != null;
button.Pressed += () => EditSchemeRequested?.Invoke(summary.Collection.Id);
return button;
@@ -420,7 +420,7 @@ namespace Mods.ModManager
private Button BuildDeleteButton(ModCollectionGameSummary summary)
{
var button = UiKit.Button(TranslationServer.Translate("mod_manager/collection_delete"), ButtonKind.Danger);
- button.TooltipText = button.Text;
+ ModHelpPanel.Attach(button, "collection_delete");
button.Disabled = _installingId != null;
button.Pressed += () => CollectionDeletion.Confirm(this, summary.Collection, () =>
{
diff --git a/src/UI/ModCard.cs b/src/UI/ModCard.cs
index 6b2aec3..c752c7e 100644
--- a/src/UI/ModCard.cs
+++ b/src/UI/ModCard.cs
@@ -76,12 +76,18 @@ namespace Mods.ModManager
_source.MouseFilter = Control.MouseFilterEnum.Pass;
AddThemeStyleboxOverride("panel", ModManagerTheme.CreateCardStyle(data.IsConflict));
+ ModHelpPanel.Attach(this, "mod_card");
+ ModHelpPanel.Attach(_versions, "mod_version");
+ ModHelpPanel.Attach(_action, "mod_action");
+ ModHelpPanel.Attach(_enabled, "mod_enabled");
+
_versions.ItemSelected += OnVersionSelected;
_action.Pressed += OnActionPressed;
_enabled.Toggled += OnEnabledPressed;
GuiInput += OnGuiInput;
BuildCollectionsLink();
+ ModHelpPanel.Attach(_collectionsLink, "mod_collections");
PopulateVersions();
RefreshState();
LoadPreview();
@@ -138,7 +144,7 @@ namespace Mods.ModManager
{
_versions.AddItem("v" + (_data.LocalVersion ?? "—"));
_versions.Disabled = true;
- _versions.TooltipText = _versions.GetItemText(0);
+ _versions.TooltipText = TranslationServer.Translate("mod_manager/hint_mod_version_body");
return;
}
@@ -164,9 +170,9 @@ namespace Mods.ModManager
}
_versions.Selected = selectedIndex;
- // "v1.2.0 · latest · installed" does not fit the narrow combo: it ends in an
- // ellipsis (clip_text in the scene), the full label is in the tooltip.
- _versions.TooltipText = _versions.GetItemText(selectedIndex);
+ // The combo clips its long version label, so its tooltip explains
+ // the version markers instead of repeating the truncated caption.
+ _versions.TooltipText = TranslationServer.Translate("mod_manager/hint_mod_version_body");
}
///
@@ -200,7 +206,6 @@ namespace Mods.ModManager
var text = ModCollectionLinks.BadgeText(_data.CollectionsCount);
_collectionsLink.Visible = text.Length > 0;
_collectionsLink.Text = text;
- _collectionsLink.TooltipText = text;
}
private void UpdateActionButton()
@@ -214,7 +219,6 @@ namespace Mods.ModManager
_action.Visible = true;
_action.Text = ModActionNames.Translate(kind.Value);
- _action.TooltipText = _action.Text;
if (ModActionNames.IsDanger(kind.Value))
CthangoverTheme.ApplyDanger(_action);
@@ -232,8 +236,8 @@ namespace Mods.ModManager
_enabled.ButtonPressed = !_data.IsDisabled;
_updatingEnabled = false;
_enabled.TooltipText = TranslationServer.Translate(_data.IsDisabled
- ? "mod_manager/action_enable"
- : "mod_manager/action_disable");
+ ? "mod_manager/enable_tooltip"
+ : "mod_manager/disable_tooltip");
}
private void LoadPreview()
@@ -291,7 +295,7 @@ namespace Mods.ModManager
return;
_data.SelectedDownload = _data.Downloads[(int)index];
- _versions.TooltipText = _versions.GetItemText((int)index);
+ _versions.TooltipText = TranslationServer.Translate("mod_manager/hint_mod_version_body");
_data.RecomputeStatus();
RefreshState();
VersionChanged?.Invoke(_data);
diff --git a/src/UI/ModDetailView.cs b/src/UI/ModDetailView.cs
index 146e93c..106cc4d 100644
--- a/src/UI/ModDetailView.cs
+++ b/src/UI/ModDetailView.cs
@@ -86,6 +86,8 @@ namespace Mods.ModManager
_conflictsBox = GetNode("Scroll/Content/ConflictsBox");
_conflictsText = GetNode