/***************************************************************************** * Copyright (c) 2014-2022 OpenRCT2 developers * * For a complete list of all authors, please refer to contributors.md * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 * * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ #include #include #include #include #include #include #include #include #include #include using namespace OpenRCT2; static constexpr const StringId WINDOW_TITLE = STR_ASSET_PACKS; static constexpr const int32_t WW = 400; static constexpr const int32_t WH = 200; // clang-format off enum WindowAssetPacksWidgetIdx { WIDX_BACKGROUND, WIDX_TITLE, WIDX_CLOSE, WIDX_HIGH_LABEL, WIDX_LIST, WIDX_LOW_LABEL, WIDX_MOVE_UP, WIDX_MOVE_DOWN, WIDX_APPLY, }; static rct_widget WindowAssetPacksWidgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 0, 0 }, { 0, 0 }, WindowWidgetType::LabelCentred, WindowColour::Secondary, STR_HIGH_PRIORITY), MakeWidget({ 0, 0 }, { 0, 0 }, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL), MakeWidget({ 0, 0 }, { 0, 0 }, WindowWidgetType::LabelCentred, WindowColour::Secondary, STR_LOW_PRIORITY), MakeWidget({ 0, 0 }, { 0, 0 }, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_G2_ARROW_UP, STR_DECREASE_PRIOTITY_TIP), MakeWidget({ 0, 0 }, { 0, 0 }, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_G2_ARROW_DOWN, STR_INCREASE_PRIOTITY_TIP), MakeWidget({ 0, 0 }, { 0, 0 }, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_G2_RELOAD, STR_RELOAD_ASSET_PACKS_TIP), WIDGETS_END, }; // clang-format on class AssetPacksWindow final : public Window { private: static constexpr int32_t ItemHeight = SCROLLABLE_ROW_HEIGHT + 1; static constexpr int32_t ItemCheckBoxSize = ItemHeight - 3; std::optional _highlightedIndex; std::optional _selectedIndex; public: void OnOpen() override { widgets = WindowAssetPacksWidgets; WindowInitScrollWidgets(*this); } void OnClose() override { Apply(); } void OnMouseUp(WidgetIndex widgetIndex) override { switch (widgetIndex) { case WIDX_CLOSE: Close(); break; case WIDX_MOVE_UP: ReorderSelectedAssetPack(-1); break; case WIDX_MOVE_DOWN: ReorderSelectedAssetPack(1); break; case WIDX_APPLY: Apply(); break; } } ScreenSize OnScrollGetSize(int32_t scrollIndex) override { ScreenSize result; auto assetPackManager = GetContext()->GetAssetPackManager(); if (assetPackManager != nullptr) { auto numAssetPacks = assetPackManager->GetCount() + 1; // +1 for the base assets item result.height = static_cast(numAssetPacks * ItemHeight); } if (_highlightedIndex) { _highlightedIndex = {}; Invalidate(); } return result; } void OnScrollMouseDown(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override { auto isCheckBox = false; auto index = GetAssetPackIndexFromPosition(screenCoords, isCheckBox); // Click on checkbox if (index && isCheckBox) { auto assetPackManager = GetContext()->GetAssetPackManager(); if (assetPackManager != nullptr) { auto assetPack = assetPackManager->GetAssetPack(*index); if (assetPack != nullptr) { assetPack->SetEnabled(!assetPack->IsEnabled()); Invalidate(); } } } // Select item if (_selectedIndex != index) { _selectedIndex = index; Invalidate(); } } void OnScrollMouseOver(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override { auto isCheckBox = false; auto index = GetAssetPackIndexFromPosition(screenCoords, isCheckBox); if (_highlightedIndex != index) { _highlightedIndex = index; Invalidate(); } } void OnPrepareDraw() override { widgets[WIDX_BACKGROUND].right = width - 1; widgets[WIDX_BACKGROUND].bottom = height - 1; widgets[WIDX_TITLE].right = width - 2; widgets[WIDX_CLOSE].left = width - 13; widgets[WIDX_CLOSE].right = width - 3; auto& list = widgets[WIDX_LIST]; list.left = 6; list.top = 20 + 11 + 3; list.right = width - 2 - 24 - 1; list.bottom = height - 6 - 11 - 3; widgets[WIDX_HIGH_LABEL].bottom = list.top - 1; widgets[WIDX_HIGH_LABEL].top = widgets[WIDX_HIGH_LABEL].bottom - 11 - 3; widgets[WIDX_HIGH_LABEL].left = list.left; widgets[WIDX_HIGH_LABEL].right = list.right; widgets[WIDX_LOW_LABEL].top = list.bottom + 1 + 3; widgets[WIDX_LOW_LABEL].bottom = widgets[WIDX_LOW_LABEL].top + 11 + 3; widgets[WIDX_LOW_LABEL].left = list.left; widgets[WIDX_LOW_LABEL].right = list.right; auto toolstripY = 20; auto toolstripRight = width - 2; auto toolstripLeft = toolstripRight - 24; for (WidgetIndex i = WIDX_MOVE_UP; i <= WIDX_APPLY; i++) { widgets[i].top = toolstripY; widgets[i].bottom = toolstripY + 24; widgets[i].left = toolstripLeft; widgets[i].right = toolstripRight; toolstripY += 24; } SetWidgetDisabled(WIDX_MOVE_UP, !_selectedIndex || _selectedIndex == 0U); SetWidgetDisabled(WIDX_MOVE_DOWN, !_selectedIndex || _selectedIndex >= GetNumAssetPacks() - 1); widgets[WIDX_APPLY].bottom = widgets[WIDX_LIST].bottom; widgets[WIDX_APPLY].top = widgets[WIDX_APPLY].bottom - 24; } void OnDraw(rct_drawpixelinfo& dpi) override { DrawWidgets(dpi); } void OnScrollDraw(int32_t scrollIndex, rct_drawpixelinfo& dpi) override { auto dpiCoords = ScreenCoordsXY{ dpi.x, dpi.y }; gfx_fill_rect( &dpi, { dpiCoords, dpiCoords + ScreenCoordsXY{ dpi.width - 1, dpi.height - 1 } }, ColourMapA[colours[1]].mid_light); auto assetPackManager = GetContext()->GetAssetPackManager(); if (assetPackManager == nullptr) return; auto numAssetPacks = assetPackManager->GetCount(); auto y = 0; for (size_t i = 0; i <= numAssetPacks; i++) { if (y > dpi.y + dpi.height) break; if (y + 11 < dpi.y) continue; auto isSelected = i == _selectedIndex; auto isHighlighted = i == _highlightedIndex; if (i == numAssetPacks) { auto ft = Formatter(); ft.Add(STR_BASE_GRAPHICS_MUSIC_SOUND); PaintItem(dpi, y, ft, true, isSelected, isHighlighted); } else { auto assetPack = assetPackManager->GetAssetPack(i); if (assetPack != nullptr) { auto isChecked = assetPack->IsEnabled(); auto ft = Formatter(); ft.Add(STR_STRING); ft.Add(assetPack->Name.c_str()); PaintItem(dpi, y, ft, isChecked, isSelected, isHighlighted); } } y += ItemHeight; } } private: void PaintItem(rct_drawpixelinfo& dpi, int32_t y, Formatter& ft, bool isChecked, bool isSelected, bool isHighlighted) { auto listWidth = dpi.width - 1; auto stringId = STR_BLACK_STRING; auto fillRectangle = ScreenRect{ { 0, y }, { listWidth, y + ItemHeight - 1 } }; if (isSelected) { gfx_fill_rect(&dpi, fillRectangle, ColourMapA[colours[1]].mid_dark); stringId = STR_WINDOW_COLOUR_2_STRINGID; } else if (isHighlighted) { gfx_fill_rect(&dpi, fillRectangle, ColourMapA[colours[1]].mid_dark); } DrawTextEllipsised(&dpi, { 16, y + 1 }, listWidth, stringId, ft); auto checkboxSize = ItemHeight - 3; PaintCheckbox(dpi, { { 2, y + 1 }, { 2 + checkboxSize + 1, y + 1 + checkboxSize } }, isChecked); } void PaintCheckbox(rct_drawpixelinfo& dpi, const ScreenRect& rect, bool checked) { gfx_fill_rect_inset(&dpi, rect, colours[1], INSET_RECT_F_E0); if (checked) { auto checkmark = Formatter(); checkmark.Add(STR_STRING); checkmark.Add(CheckBoxMarkString); DrawTextBasic(&dpi, ScreenCoordsXY{ rect.GetLeft() + 1, rect.GetTop() }, STR_WINDOW_COLOUR_2_STRINGID, checkmark); } } std::optional GetAssetPackIndexFromPosition(const ScreenCoordsXY& pos, bool& isCheckBox) { const auto index = pos.y / ItemHeight; if (index < 0 || static_cast(index) >= GetNumAssetPacks()) return std::nullopt; isCheckBox = pos.x >= 2 && pos.x <= 2 + ItemCheckBoxSize + 1; return static_cast(index); } size_t GetNumAssetPacks() const { auto assetPackManager = GetContext()->GetAssetPackManager(); if (assetPackManager == nullptr) return 0; return assetPackManager->GetCount(); } bool IsSelectedAssetPackEnabled() const { if (_selectedIndex) { auto assetPackManager = GetContext()->GetAssetPackManager(); if (assetPackManager != nullptr) { auto assetPack = assetPackManager->GetAssetPack(*_selectedIndex); if (assetPack != nullptr) { return assetPack->IsEnabled(); } } } return false; } void ReorderSelectedAssetPack(int32_t direction) { if (!_selectedIndex) return; auto assetPackManager = GetContext()->GetAssetPackManager(); if (assetPackManager == nullptr) return; if (direction < 0 && *_selectedIndex > 0) { assetPackManager->Swap(*_selectedIndex, *_selectedIndex - 1); (*_selectedIndex)--; Invalidate(); } else if (direction > 0 && *_selectedIndex < assetPackManager->GetCount() - 1) { assetPackManager->Swap(*_selectedIndex, *_selectedIndex + 1); (*_selectedIndex)++; Invalidate(); } } void Apply() { auto& objectManager = GetContext()->GetObjectManager(); objectManager.ResetObjects(); auto assetPackManager = GetContext()->GetAssetPackManager(); if (assetPackManager != nullptr) { assetPackManager->SaveEnabledAssetPacks(); } } }; rct_window* WindowAssetPacksOpen() { auto flags = WF_AUTO_POSITION | WF_CENTRE_SCREEN; return WindowFocusOrCreate(WindowClass::AssetPacks, WW, WH, flags); }