14 KiB
BuildsDialog
Обзор компонента
Minecraft_launcher — десктопный лаунчер Minecraft на Qt Quick. Сборка в нём — это именованный
набор «версия игры + модлоадер + адрес сервера» вместе с собственным содержимым .minecraft:
модами, конфигами и мирами. Активная сборка одна, её содержимое лежит в .minecraft, остальные
хранятся в архивах и разворачиваются при переключении.
BuildsDialog — окно управления этими сборками: слева список со сменой активной, справа карточка
выбранной — имя, сервер, версия Minecraft и модлоадеры. Отсюда же сборка ставится (скачивание
версии игры и модлоадера) и удаляется.
Карточка сохраняет правки по ходу редактирования, отдельной кнопки «Сохранить» нет: иначе появляется неочевидное несохранённое состояние, пока пользователь переключается между сборками в левом списке.
Место в проекте и зависимости
В начале файла объявлена pragma ComponentBehavior: Bound. Импортирует QtQuick,
QtQuick.Controls 2.15 и QtQuick.Layouts 2.15.
Использует три компонента из того же QML-модуля:
- LabelledField — поля названия сборки и адреса сервера;
- LoaderRow — по одной строке на каждый из четырёх модлоадеров;
- VersionPickerDialog — вложенное окно выбора версии Minecraft.
Работает с C++-типом LauncherBackend (launcherbackend.h, QML_ELEMENT в модуле
Minecraft_launcher) через свойство backend. Читает свойства customBuildNames,
activeBuildIndex, switching и busy; вызывает customBuildAt(), addCustomBuild(),
updateCustomBuild(), customBuildRemovalInfo(), removeCustomBuild(), checkInstallation(),
installCustomBuild() и refreshVersionCatalog(); слушает сигнал installedVersionsChanged.
Объявлен в QML_FILES модуля (CMakeLists.txt); использует ресурс images/Trash.svg.
Инстанцируется в Main.
Иерархия и роль
Корневой тип — Dialog: модальный, 880×600 px, нулевой внутренний отступ, тёмный фон со
скруглением и акцентной рамкой. Пока идёт смена активной сборки (backend.switching), окно
закрывается только кнопкой: архивация и распаковка .minecraft не должны прерываться случайным
щелчком мимо.
Содержимое — RowLayout из двух частей:
- Слева (260 px) список сборок и строка «+ Новая сборка» под ним. Строка списка показывает имя, пометку «активна» у активной сборки и корзину, появляющуюся при наведении. Вся колонка выключается на время смены активной сборки.
- Справа карточка выбранной сборки внутри
Flickable— она может не поместиться по высоте. Карточка выключается и приглушается, когда сборка не выбрана или идёт переключение.
Карточка сверху вниз: название, адрес сервера, поле версии Minecraft, панель модлоадеров и строка состояния комплектности. Поле версии — не выпадающий список, а прямоугольник, который только показывает выбор и открывает отдельное окно: версий около тысячи, и разбираться в них удобнее в окне с категориями.
Отдельно объявлен вложенный Dialog подтверждения удаления шириной 420 px с красной рамкой,
привязанный к тому же родителю, что и само окно.
Подвал несёт три кнопки: «Установить», «Сделать активной» и «Закрыть».
Свойства
| Свойство | Тип | По умолчанию | Обязательное | Описание |
|---|---|---|---|---|
backend |
var |
— | Да | Экземпляр LauncherBackend — хранилище сборок и исполнитель установки, удаления и переключения. |
editIndex |
int |
-1 |
Нет | Индекс сборки, открытой в карточке справа. Значение -1 означает, что карточка пуста и выключена. С активной сборкой не связан: активную меняет отдельная кнопка, чтобы случайный клик по списку не запускал архивацию .minecraft. |
loading |
bool |
false |
Нет | Признак того, что карточка сейчас заполняется данными сборки. Пока он выставлен, обработчики полей не должны писать обратно — иначе открытие сборки немедленно перезаписывало бы её. |
Внутренняя панель модлоадеров
Панель loaderPanel — это Column с четырьмя строками LoaderRow и собственным
маленьким API. Лоадеры несовместимы между собой: игра запускается ровно с одним профилем
versions/<id>, поэтому отметка одного снимает остальные, а «ничего не отмечено» — это чистая
ваниль.
| Свойство панели | Тип | Описание |
|---|---|---|
rows |
var |
Массив из четырёх строк лоадеров в порядке показа: Minecraft Forge (forge), Fabric Loader (fabric), NeoForge (neoforge), Quilt Loader (quilt). |
Функции панели: applyBuild(loader, loaderVersion) раздаёт данные сборки всем строкам;
selectedRow() возвращает отмеченную строку или null; keepOnly(row) очищает все строки,
кроме переданной; commitSelection() сохраняет выбор в сборку, записывая ключ лоадера, его версию
и пустой resolvedVersionId — профиль появится только после установки, а до неё сборка
запускается на чистой ванили.
Сигналы
Собственных сигналов компонент не объявляет: все изменения уходят прямо в бэкенд, и о них остальной интерфейс узнаёт по его сигналам.
Методы
selectBuild(int index) : void
Открывает сборку с указанным индексом в карточке. Читает данные через customBuildAt(),
выставляет loading на время заполнения полей, раздаёт лоадеры панели через applyBuild() и в
конце обновляет строку состояния.
askRemove(int index) : void
Спрашивает подтверждение перед удалением: оно необратимо и уносит с собой архив сборки. Запрашивает
customBuildRemovalInfo() и наполняет окно подтверждения именем сборки и тремя признаками — есть
ли у неё архив, активна ли она сейчас и последняя ли она. Индекс запоминается в самом окне
подтверждения, потому что к моменту ответа строка списка под курсором может быть уже другой.
Окно подтверждения объясняет последствия по этим признакам: вместе со сборкой удалится её архив, и
моды, конфиги и миры восстановить будет нельзя; активная сборка владеет содержимым .minecraft,
оно будет очищено, а на его место развернётся следующая сборка; для последней сборки содержимое
.minecraft остаётся на месте.
performRemove(int index) : void
Удаляет сборку через бэкенд и восстанавливает состояние карточки: если сборок не осталось,
сбрасывает editIndex в -1, иначе открывает соседнюю — ту же позицию или последнюю оставшуюся.
commit(var fields) : void
Сохраняет часть полей сборки: передаёт QVariantMap в updateCustomBuild() и обновляет строку
состояния. Ничего не делает во время заполнения карточки (loading) и при пустом editIndex —
это и есть защита от записи при открытии сборки.
Вызывается по завершении правки каждого поля: имени, адреса сервера, версии Minecraft и выбора модлоадера.
refreshStatus() : void
Пересчитывает строку комплектности под карточкой. Спрашивает у бэкенда checkInstallation() и
показывает либо сообщение о готовности к запуску, либо число недостающих файлов вместе с первым из
них. При пустом editIndex очищает строку.
newBuildName() : string
Придумывает имя для новой сборки: перебирает «Сборка 1», «Сборка 2» и так далее, пока не найдёт свободное среди существующих имён.
Взаимодействие с другими компонентами
Со стороны родителя. Main задаёт backend и открывает окно. Начальное состояние
окно выбирает само в обработчике onAboutToShow: просит обновить каталог версий и открывает
активную сборку, а при пустом списке оставляет карточку выключенной.
Внутрь — к вложенным компонентам. Поля LabelledField сообщают о правке
сигналом editingFinished, и карточка сразу вызывает commit() с обрезанным по краям значением.
Поле версии открывает VersionPickerDialog вызовом openFor() и получает
результат сигналом versionChosen; запись выбранной версии сама вызывает commit() через
обработчик изменения. Строки LoaderRow получают gameVersion привязкой к
выбранной версии игры, поэтому смена версии Minecraft автоматически перезапрашивает списки версий
лоадеров.
Наружу — к бэкенду. Кнопка «Установить» вызывает installCustomBuild(), кнопка «Сделать
активной» пишет в свойство activeBuildIndex. Обе выключены, пока лаунчер занят (busy), а
кнопка активации — ещё и когда выбранная сборка уже активна. Ход установки и переключения
показывает плашка ProgressPanel главного окна, а не это окно.
Обратная связь от бэкенда. Окно подписано на installedVersionsChanged через Connections:
установка версии или модлоадера меняет комплектность сборки, и строка состояния должна это
заметить, не дожидаясь переоткрытия окна.
Пример использования
BuildsDialog {
id: buildsDialog
parent: Overlay.overlay
anchors.centerIn: parent
backend: launcherBackend
}
Button {
text: qsTr("Сборки")
onClicked: buildsDialog.open()
}
При создании этого документа использовался ИИ.