diff --git a/src/openrct2-ui/interface/Window.cpp b/src/openrct2-ui/interface/Window.cpp index f945e5a245..39fd2ed297 100644 --- a/src/openrct2-ui/interface/Window.cpp +++ b/src/openrct2-ui/interface/Window.cpp @@ -738,6 +738,11 @@ bool Window::IsWidgetPressed(WidgetIndex widgetIndex) const return WidgetIsPressed(*this, widgetIndex); } +void Window::SetWidgetEnabled(WidgetIndex widgetIndex, bool value) +{ + WidgetSetEnabled(*this, widgetIndex, value); +} + void Window::SetWidgetDisabled(WidgetIndex widgetIndex, bool value) { WidgetSetDisabled(*this, widgetIndex, value); diff --git a/src/openrct2-ui/interface/Window.h b/src/openrct2-ui/interface/Window.h index e75ad01e14..576e194ebe 100644 --- a/src/openrct2-ui/interface/Window.h +++ b/src/openrct2-ui/interface/Window.h @@ -22,6 +22,7 @@ struct Window : WindowBase void InvalidateWidget(WidgetIndex widgetIndex); bool IsWidgetDisabled(WidgetIndex widgetIndex) const; bool IsWidgetPressed(WidgetIndex widgetIndex) const; + void SetWidgetEnabled(WidgetIndex widgetIndex, bool value); void SetWidgetDisabled(WidgetIndex widgetIndex, bool value); void SetWidgetPressed(WidgetIndex widgetIndex, bool value); void SetCheckboxValue(WidgetIndex widgetIndex, bool value); diff --git a/src/openrct2-ui/windows/MapGen.cpp b/src/openrct2-ui/windows/MapGen.cpp index 31010b3b8c..8c65326e53 100644 --- a/src/openrct2-ui/windows/MapGen.cpp +++ b/src/openrct2-ui/windows/MapGen.cpp @@ -195,85 +195,6 @@ static Widget* PageWidgets[WINDOW_MAPGEN_PAGE_COUNT] = { #pragma endregion -#pragma region Events - -static void WindowMapgenSharedClose(WindowBase* w); -static void WindowMapgenSharedMouseup(WindowBase* w, WidgetIndex widgetIndex); - -static void WindowMapgenBaseMouseup(WindowBase* w, WidgetIndex widgetIndex); -static void WindowMapgenBaseMousedown(WindowBase* w, WidgetIndex widgetIndex, Widget* widget); -static void WindowMapgenBaseDropdown(WindowBase* w, WidgetIndex widgetIndex, int32_t dropdownIndex); -static void WindowMapgenBaseUpdate(WindowBase* w); -static void WindowMapgenTextinput(WindowBase* w, WidgetIndex widgetIndex, const char* text); -static void WindowMapgenBaseInvalidate(WindowBase* w); -static void WindowMapgenBasePaint(WindowBase* w, DrawPixelInfo* dpi); - -static void WindowMapgenRandomMouseup(WindowBase* w, WidgetIndex widgetIndex); -static void WindowMapgenRandomMousedown(WindowBase* w, WidgetIndex widgetIndex, Widget* widget); -static void WindowMapgenRandomUpdate(WindowBase* w); -static void WindowMapgenRandomInvalidate(WindowBase* w); -static void WindowMapgenRandomPaint(WindowBase* w, DrawPixelInfo* dpi); - -static void WindowMapgenSimplexMouseup(WindowBase* w, WidgetIndex widgetIndex); -static void WindowMapgenSimplexMousedown(WindowBase* w, WidgetIndex widgetIndex, Widget* widget); -static void WindowMapgenSimplexDropdown(WindowBase* w, WidgetIndex widgetIndex, int32_t dropdownIndex); -static void WindowMapgenSimplexUpdate(WindowBase* w); -static void WindowMapgenSimplexInvalidate(WindowBase* w); -static void WindowMapgenSimplexPaint(WindowBase* w, DrawPixelInfo* dpi); - -static void WindowMapgenHeightmapMouseup(WindowBase* w, WidgetIndex widgetIndex); -static void WindowMapgenHeightmapMousedown(WindowBase* w, WidgetIndex widgetIndex, Widget* widget); -static void WindowMapgenHeightmapInvalidate(WindowBase* w); -static void WindowMapgenHeightmapPaint(WindowBase* w, DrawPixelInfo* dpi); - -static WindowEventList BaseEvents([](auto& events) { - events.close = &WindowMapgenSharedClose; - events.mouse_up = &WindowMapgenBaseMouseup; - events.mouse_down = &WindowMapgenBaseMousedown; - events.dropdown = &WindowMapgenBaseDropdown; - events.update = &WindowMapgenBaseUpdate; - events.text_input = &WindowMapgenTextinput; - events.invalidate = &WindowMapgenBaseInvalidate; - events.paint = &WindowMapgenBasePaint; -}); - -static WindowEventList RandomEvents([](auto& events) { - events.close = &WindowMapgenSharedClose; - events.mouse_up = &WindowMapgenRandomMouseup; - events.mouse_down = &WindowMapgenRandomMousedown; - events.update = &WindowMapgenRandomUpdate; - events.invalidate = &WindowMapgenRandomInvalidate; - events.paint = &WindowMapgenRandomPaint; -}); - -static WindowEventList SimplexEvents([](auto& events) { - events.close = &WindowMapgenSharedClose; - events.mouse_up = &WindowMapgenSimplexMouseup; - events.mouse_down = &WindowMapgenSimplexMousedown; - events.dropdown = &WindowMapgenSimplexDropdown; - events.update = &WindowMapgenSimplexUpdate; - events.text_input = &WindowMapgenTextinput; - events.invalidate = &WindowMapgenSimplexInvalidate; - events.paint = &WindowMapgenSimplexPaint; -}); - -static WindowEventList HeightmapEvents([](auto& events) { - events.close = &WindowMapgenSharedClose; - events.mouse_up = &WindowMapgenHeightmapMouseup; - events.mouse_down = &WindowMapgenHeightmapMousedown; - events.invalidate = &WindowMapgenHeightmapInvalidate; - events.paint = &WindowMapgenHeightmapPaint; -}); - -static WindowEventList* PageEvents[] = { - &BaseEvents, - &RandomEvents, - &SimplexEvents, - &HeightmapEvents, -}; - -#pragma endregion - #pragma region Widget flags // clang-format off @@ -374,10 +295,6 @@ constexpr int32_t WATERLEVEL_MIN = 0; constexpr int32_t WATERLEVEL_MAX = 54; constexpr int32_t MAX_SMOOTH_ITERATIONS = 20; -static void WindowMapgenSetPage(WindowBase* w, int32_t page); -static void WindowMapgenSetPressedTab(WindowBase* w); -static void WindowMapgenDrawTabImages(DrawPixelInfo* dpi, WindowBase* w); - enum class ResizeDirection { Both, @@ -385,1005 +302,1084 @@ enum class ResizeDirection Y, }; -static TileCoordsXY _mapSize{ 150, 150 }; -static ResizeDirection _resizeDirection{ ResizeDirection::Both }; -static bool _mapWidthAndHeightLinked{ true }; -static int32_t _baseHeight = 12; -static int32_t _waterLevel = 6; -static int32_t _floorTexture = 0; -static int32_t _wallTexture = 0; -static bool _randomTerrain = true; -static int32_t _placeTrees = 1; +static void HeightmapLoadsaveCallback(int32_t result, const utf8* path); -static int32_t _simplex_low = 6; -static int32_t _simplex_high = 10; -static int32_t _simplex_base_freq = 60; -static int32_t _simplex_octaves = 4; - -static bool _heightmapLoaded = false; -static bool _heightmapSmoothMap = false; -static int32_t _heightmapSmoothStrength = 1; -static bool _heightmapNormalize = false; -static bool _heightmapSmoothTiles = true; -static int32_t _heightmapLow = 2; -static int32_t _heightmapHigh = 70; - -static void WindowMapgenChangeMapSize(int32_t sizeOffset) +class MapGenWindow final : public Window { - if (_mapWidthAndHeightLinked) - _resizeDirection = ResizeDirection::Both; +private: + TileCoordsXY _mapSize{ 150, 150 }; + ResizeDirection _resizeDirection{ ResizeDirection::Both }; + bool _mapWidthAndHeightLinked{ true }; + int32_t _baseHeight = 12; + int32_t _waterLevel = 6; + int32_t _floorTexture = 0; + int32_t _wallTexture = 0; + bool _randomTerrain = true; + int32_t _placeTrees = 1; - if (_resizeDirection != ResizeDirection::X) - _mapSize.y = std::clamp(_mapSize.y + sizeOffset, MINIMUM_MAP_SIZE_TECHNICAL, MAXIMUM_MAP_SIZE_TECHNICAL); - if (_resizeDirection != ResizeDirection::Y) - _mapSize.x = std::clamp(_mapSize.x + sizeOffset, MINIMUM_MAP_SIZE_TECHNICAL, MAXIMUM_MAP_SIZE_TECHNICAL); -} + int32_t _simplex_low = 6; + int32_t _simplex_high = 10; + int32_t _simplex_base_freq = 60; + int32_t _simplex_octaves = 4; -WindowBase* WindowMapgenOpen() -{ - WindowBase* w = WindowBringToFrontByClass(WindowClass::Mapgen); - if (w != nullptr) + bool _heightmapLoaded = false; + bool _heightmapSmoothMap = false; + int32_t _heightmapSmoothStrength = 1; + bool _heightmapNormalize = false; + bool _heightmapSmoothTiles = true; + int32_t _heightmapLow = 2; + int32_t _heightmapHigh = 70; + + void SetPage(int32_t newPage) { - return w; - } + page = newPage; + frame_no = 0; + RemoveViewport(); - w = WindowCreateCentred(WW, WH, PageEvents[WINDOW_MAPGEN_PAGE_BASE], WindowClass::Mapgen, WF_10); - w->number = 0; - w->frame_no = 0; + hold_down_widgets = HoldDownWidgets[newPage]; + widgets = PageWidgets[newPage]; + disabled_widgets = PageDisabledWidgets[newPage]; + pressed_widgets = PressedWidgets[newPage]; - w->page = WINDOW_MAPGEN_PAGE_BASE; - w->Invalidate(); - w->widgets = PageWidgets[WINDOW_MAPGEN_PAGE_BASE]; - w->hold_down_widgets = HoldDownWidgets[WINDOW_MAPGEN_PAGE_BASE]; - w->event_handlers = PageEvents[WINDOW_MAPGEN_PAGE_BASE]; - w->pressed_widgets = PressedWidgets[WINDOW_MAPGEN_PAGE_BASE]; - w->disabled_widgets = PageDisabledWidgets[WINDOW_MAPGEN_PAGE_BASE]; - WindowInitScrollWidgets(*w); - - _heightmapLoaded = false; - - return w; -} - -static void WindowMapgenSharedClose(WindowBase* w) -{ - MapGenUnloadHeightmap(); -} - -static void WindowMapgenSharedMouseup(WindowBase* w, WidgetIndex widgetIndex) -{ - switch (widgetIndex) - { - case WIDX_CLOSE: - WindowClose(*w); - break; - case WIDX_TAB_1: - case WIDX_TAB_2: - case WIDX_TAB_3: - case WIDX_TAB_4: - WindowMapgenSetPage(w, widgetIndex - WIDX_TAB_1); - break; - } -} - -static void WindowMapgenInputMapSize(WindowBase* w, WidgetIndex callingWidget, int32_t currentValue) -{ - Formatter ft; - ft.Add(MINIMUM_MAP_SIZE_PRACTICAL); - ft.Add(MAXIMUM_MAP_SIZE_PRACTICAL); - - // Practical map size is 2 lower than the technical map size - currentValue -= 2; - WindowTextInputOpen(w, callingWidget, STR_MAP_SIZE_2, STR_ENTER_MAP_SIZE, ft, STR_FORMAT_INTEGER, currentValue, 4); -} - -#pragma region Base page - -static void WindowMapgenBaseMouseup(WindowBase* w, WidgetIndex widgetIndex) -{ - WindowMapgenSharedMouseup(w, widgetIndex); - - MapGenSettings mapgenSettings; - Formatter ft; - switch (widgetIndex) - { - case WIDX_MAP_GENERATE: - mapgenSettings.mapSize = _mapSize; - mapgenSettings.height = _baseHeight + 2; - mapgenSettings.water_level = _waterLevel + 2; - mapgenSettings.floor = _floorTexture; - mapgenSettings.wall = _wallTexture; - - MapGenGenerateBlank(&mapgenSettings); - GfxInvalidateScreen(); - break; - case WIDX_MAP_SIZE_Y: - _resizeDirection = ResizeDirection::Y; - WindowMapgenInputMapSize(w, WIDX_MAP_SIZE_Y, _mapSize.y); - break; - case WIDX_MAP_SIZE_X: - _resizeDirection = ResizeDirection::X; - WindowMapgenInputMapSize(w, WIDX_MAP_SIZE_X, _mapSize.x); - break; - case WIDX_MAP_SIZE_LINK: - _mapWidthAndHeightLinked = !_mapWidthAndHeightLinked; - break; - case WIDX_BASE_HEIGHT: - ft.Add((BASESIZE_MIN - 12) / 2); - ft.Add((BASESIZE_MAX - 12) / 2); - WindowTextInputOpen( - w, WIDX_BASE_HEIGHT, STR_BASE_HEIGHT, STR_ENTER_BASE_HEIGHT, ft, STR_FORMAT_INTEGER, (_baseHeight - 12) / 2, 3); - break; - case WIDX_WATER_LEVEL: - ft.Add((WATERLEVEL_MIN - 12) / 2); - ft.Add((WATERLEVEL_MAX - 12) / 2); - WindowTextInputOpen( - w, WIDX_WATER_LEVEL, STR_WATER_LEVEL, STR_ENTER_WATER_LEVEL, ft, STR_FORMAT_INTEGER, (_waterLevel - 12) / 2, 3); - break; - } -} - -static void WindowMapgenBaseMousedown(WindowBase* w, WidgetIndex widgetIndex, Widget* widget) -{ - switch (widgetIndex) - { - case WIDX_MAP_SIZE_Y_UP: - _resizeDirection = ResizeDirection::Y; - WindowMapgenChangeMapSize(+1); - w->Invalidate(); - break; - case WIDX_MAP_SIZE_Y_DOWN: - _resizeDirection = ResizeDirection::Y; - WindowMapgenChangeMapSize(-1); - w->Invalidate(); - break; - case WIDX_MAP_SIZE_X_UP: - _resizeDirection = ResizeDirection::X; - WindowMapgenChangeMapSize(+1); - w->Invalidate(); - break; - case WIDX_MAP_SIZE_X_DOWN: - _resizeDirection = ResizeDirection::X; - WindowMapgenChangeMapSize(-1); - w->Invalidate(); - break; - case WIDX_BASE_HEIGHT_UP: - _baseHeight = std::min(_baseHeight + 2, BASESIZE_MAX); - w->Invalidate(); - break; - case WIDX_BASE_HEIGHT_DOWN: - _baseHeight = std::max(_baseHeight - 2, BASESIZE_MIN); - w->Invalidate(); - break; - case WIDX_WATER_LEVEL_UP: - _waterLevel = std::min(_waterLevel + 2, WATERLEVEL_MAX); - w->Invalidate(); - break; - case WIDX_WATER_LEVEL_DOWN: - _waterLevel = std::max(_waterLevel - 2, WATERLEVEL_MIN); - w->Invalidate(); - break; - case WIDX_FLOOR_TEXTURE: - LandTool::ShowSurfaceStyleDropdown(w, widget, _floorTexture); - break; - case WIDX_WALL_TEXTURE: - LandTool::ShowEdgeStyleDropdown(w, widget, _wallTexture); - break; - } -} - -static void WindowMapgenBaseDropdown(WindowBase* w, WidgetIndex widgetIndex, int32_t dropdownIndex) -{ - int32_t type; - - switch (widgetIndex) - { - case WIDX_FLOOR_TEXTURE: - if (dropdownIndex == -1) - dropdownIndex = gDropdownHighlightedIndex; - - type = (dropdownIndex == -1) ? _floorTexture : dropdownIndex; - - if (gLandToolTerrainSurface == type) - { - gLandToolTerrainSurface = OBJECT_ENTRY_INDEX_NULL; - } - else - { - gLandToolTerrainSurface = type; - _floorTexture = type; - } - w->Invalidate(); - break; - case WIDX_WALL_TEXTURE: - if (dropdownIndex == -1) - dropdownIndex = gDropdownHighlightedIndex; - - type = (dropdownIndex == -1) ? _wallTexture : dropdownIndex; - - if (gLandToolTerrainEdge == type) - { - gLandToolTerrainEdge = OBJECT_ENTRY_INDEX_NULL; - } - else - { - gLandToolTerrainEdge = type; - _wallTexture = type; - } - w->Invalidate(); - break; - } -} - -static void WindowMapgenBaseUpdate(WindowBase* w) -{ - // Tab animation - if (++w->frame_no >= TabAnimationLoops[w->page]) - w->frame_no = 0; - WidgetInvalidate(*w, WIDX_TAB_1); -} - -static void WindowMapgenTextinput(WindowBase* w, WidgetIndex widgetIndex, const char* text) -{ - int32_t value; - char* end; - - if (text == nullptr) - return; - - value = strtol(text, &end, 10); - - if (*end != '\0') - { - return; - } - - switch (widgetIndex) - { - case WIDX_MAP_SIZE_Y: - case WIDX_MAP_SIZE_X: - case WIDX_SIMPLEX_MAP_SIZE_Y: - case WIDX_SIMPLEX_MAP_SIZE_X: - // The practical size is 2 lower than the technical size - value += 2; - if (_resizeDirection == ResizeDirection::Y || _mapWidthAndHeightLinked) - _mapSize.y = value; - if (_resizeDirection == ResizeDirection::X || _mapWidthAndHeightLinked) - _mapSize.x = value; - break; - case WIDX_BASE_HEIGHT: - _baseHeight = std::clamp((value * 2) + 12, BASESIZE_MIN, BASESIZE_MAX); - break; - case WIDX_WATER_LEVEL: - _waterLevel = std::clamp((value * 2) + 12, WATERLEVEL_MIN, WATERLEVEL_MAX); - break; - } - - w->Invalidate(); -} - -static void WindowMapgenBaseInvalidate(WindowBase* w) -{ - if (w->widgets != PageWidgets[WINDOW_MAPGEN_PAGE_BASE]) - { - w->widgets = PageWidgets[WINDOW_MAPGEN_PAGE_BASE]; - WindowInitScrollWidgets(*w); - } - - // Only allow linking the map size when X and Y are the same - WidgetSetPressed(*w, WIDX_MAP_SIZE_LINK, _mapWidthAndHeightLinked); - WidgetSetDisabled(*w, WIDX_MAP_SIZE_LINK, _mapSize.x != _mapSize.y); - - WindowMapgenSetPressedTab(w); - - // Push width (Y) and height (X) to the common formatter arguments for the map size spinners to use - auto ft = Formatter::Common(); - ft.Add(_mapSize.y - 2); - ft.Add(_mapSize.x - 2); -} - -static void WindowMapgenDrawDropdownButton(WindowBase* w, DrawPixelInfo* dpi, WidgetIndex widgetIndex, ImageId image) -{ - const auto& widget = w->widgets[widgetIndex]; - ScreenCoordsXY pos = { w->windowPos.x + widget.left, w->windowPos.y + widget.top }; - if (WidgetIsDisabled(*w, widgetIndex)) - { - // Draw greyed out (light border bottom right shadow) - auto colour = w->colours[widget.colour]; - colour = ColourMapA[NOT_TRANSLUCENT(colour)].lighter; - GfxDrawSpriteSolid(dpi, image, pos + ScreenCoordsXY{ 1, 1 }, colour); - - // Draw greyed out (dark) - colour = w->colours[widget.colour]; - colour = ColourMapA[NOT_TRANSLUCENT(colour)].mid_light; - GfxDrawSpriteSolid(dpi, image, pos, colour); - } - else - { - GfxDrawSprite(dpi, image, pos); - } -} - -static void WindowMapgenDrawDropdownButtons( - WindowBase* w, DrawPixelInfo* dpi, WidgetIndex floorWidgetIndex, WidgetIndex edgeWidgetIndex) -{ - auto& objManager = GetContext()->GetObjectManager(); - const auto surfaceObj = static_cast( - objManager.GetLoadedObject(ObjectType::TerrainSurface, _floorTexture)); - ImageId surfaceImage; - if (surfaceObj != nullptr) - { - surfaceImage = ImageId(surfaceObj->IconImageId); - if (surfaceObj->Colour != 255) + // Enable heightmap widgets if one is loaded + if (newPage == WINDOW_MAPGEN_PAGE_HEIGHTMAP && _heightmapLoaded) { - surfaceImage = surfaceImage.WithPrimary(surfaceObj->Colour); + SetWidgetEnabled(WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP, true); + SetWidgetEnabled(WIDX_HEIGHTMAP_STRENGTH, _heightmapSmoothMap); + SetWidgetEnabled(WIDX_HEIGHTMAP_STRENGTH_UP, _heightmapSmoothMap); + SetWidgetEnabled(WIDX_HEIGHTMAP_STRENGTH_DOWN, _heightmapSmoothMap); + SetWidgetEnabled(WIDX_HEIGHTMAP_NORMALIZE, true); + SetWidgetEnabled(WIDX_HEIGHTMAP_SMOOTH_TILES, true); + SetWidgetEnabled(WIDX_HEIGHTMAP_HIGH, true); + SetWidgetEnabled(WIDX_HEIGHTMAP_HIGH_UP, true); + SetWidgetEnabled(WIDX_HEIGHTMAP_HIGH_DOWN, true); + SetWidgetEnabled(WIDX_HEIGHTMAP_LOW, true); + SetWidgetEnabled(WIDX_HEIGHTMAP_LOW_UP, true); + SetWidgetEnabled(WIDX_HEIGHTMAP_LOW_DOWN, true); + SetWidgetEnabled(WIDX_HEIGHTMAP_WATER_LEVEL, true); + SetWidgetEnabled(WIDX_HEIGHTMAP_WATER_LEVEL_UP, true); + SetWidgetEnabled(WIDX_HEIGHTMAP_WATER_LEVEL_DOWN, true); + } + + InitScrollWidgets(); + Invalidate(); + } + + void SetPressedTab() + { + int32_t i; + for (i = 0; i < WINDOW_MAPGEN_PAGE_COUNT; i++) + pressed_widgets &= ~(1 << (WIDX_TAB_1 + i)); + pressed_widgets |= 1LL << (WIDX_TAB_1 + page); + } + + void DrawTabImage(DrawPixelInfo& dpi, int32_t newPage, int32_t spriteIndex) + { + WidgetIndex widgetIndex = WIDX_TAB_1 + newPage; + + if (!WidgetIsDisabled(*this, widgetIndex)) + { + if (page == newPage) + { + int32_t frame = frame_no / TabAnimationDivisor[page]; + spriteIndex += (frame % TabAnimationFrames[page]); + } + + GfxDrawSprite( + &dpi, ImageId(spriteIndex), windowPos + ScreenCoordsXY{ widgets[widgetIndex].left, widgets[widgetIndex].top }); } } - ImageId edgeImage; - const auto edgeObj = static_cast(objManager.GetLoadedObject(ObjectType::TerrainEdge, _wallTexture)); - if (edgeObj != nullptr) + void DrawTabImages(DrawPixelInfo& dpi) { - edgeImage = ImageId(edgeObj->IconImageId); + DrawTabImage(dpi, WINDOW_MAPGEN_PAGE_BASE, SPR_G2_TAB_LAND); + DrawTabImage(dpi, WINDOW_MAPGEN_PAGE_RANDOM, SPR_G2_TAB_TREE); + DrawTabImage(dpi, WINDOW_MAPGEN_PAGE_SIMPLEX, SPR_G2_TAB_PENCIL); + DrawTabImage(dpi, WINDOW_MAPGEN_PAGE_HEIGHTMAP, SPR_TAB_GRAPH_0); } - WindowMapgenDrawDropdownButton(w, dpi, floorWidgetIndex, surfaceImage); - WindowMapgenDrawDropdownButton(w, dpi, edgeWidgetIndex, edgeImage); -} + void ChangeMapSize(int32_t sizeOffset) + { + if (_mapWidthAndHeightLinked) + _resizeDirection = ResizeDirection::Both; -static void WindowMapgenBasePaint(WindowBase* w, DrawPixelInfo* dpi) -{ - WindowDrawWidgets(*w, dpi); - WindowMapgenDrawTabImages(dpi, w); - WindowMapgenDrawDropdownButtons(w, dpi, WIDX_FLOOR_TEXTURE, WIDX_WALL_TEXTURE); + if (_resizeDirection != ResizeDirection::X) + _mapSize.y = std::clamp(_mapSize.y + sizeOffset, MINIMUM_MAP_SIZE_TECHNICAL, MAXIMUM_MAP_SIZE_TECHNICAL); + if (_resizeDirection != ResizeDirection::Y) + _mapSize.x = std::clamp(_mapSize.x + sizeOffset, MINIMUM_MAP_SIZE_TECHNICAL, MAXIMUM_MAP_SIZE_TECHNICAL); + } - const auto textColour = w->colours[1]; + void InputMapSize(WidgetIndex callingWidget, int32_t currentValue) + { + Formatter ft; + ft.Add(MINIMUM_MAP_SIZE_PRACTICAL); + ft.Add(MAXIMUM_MAP_SIZE_PRACTICAL); - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ 4, w->widgets[WIDX_MAP_SIZE_Y].top + 1 }, STR_MAP_SIZE, {}, { textColour }); - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ 4, w->widgets[WIDX_BASE_HEIGHT].top + 1 }, STR_BASE_HEIGHT_LABEL, {}, - { textColour }); - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ 4, w->widgets[WIDX_WATER_LEVEL].top + 1 }, STR_WATER_LEVEL_LABEL, {}, - { textColour }); - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ 4, w->widgets[WIDX_FLOOR_TEXTURE].top + 1 }, STR_TERRAIN_LABEL, {}, - { textColour }); + // Practical map size is 2 lower than the technical map size + currentValue -= 2; + WindowTextInputOpen(this, callingWidget, STR_MAP_SIZE_2, STR_ENTER_MAP_SIZE, ft, STR_FORMAT_INTEGER, currentValue, 4); + } - auto ft = Formatter(); - ft.Add((_baseHeight - 12) / 2); - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ w->widgets[WIDX_BASE_HEIGHT].left + 1, w->widgets[WIDX_BASE_HEIGHT].top + 1 }, - STR_COMMA16, ft, { w->colours[1] }); + void SharedMouseUp(WidgetIndex widgetIndex) + { + switch (widgetIndex) + { + case WIDX_CLOSE: + Close(); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + SetPage(widgetIndex - WIDX_TAB_1); + break; + } + } - ft = Formatter(); - ft.Add((_waterLevel - 12) / 2); - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ w->widgets[WIDX_WATER_LEVEL].left + 1, w->widgets[WIDX_WATER_LEVEL].top + 1 }, - STR_COMMA16, ft, { w->colours[1] }); -} +#pragma region Base page + + void BaseMouseUp(WidgetIndex widgetIndex) + { + SharedMouseUp(widgetIndex); + + MapGenSettings mapgenSettings; + Formatter ft; + switch (widgetIndex) + { + case WIDX_MAP_GENERATE: + mapgenSettings.mapSize = _mapSize; + mapgenSettings.height = _baseHeight + 2; + mapgenSettings.water_level = _waterLevel + 2; + mapgenSettings.floor = _floorTexture; + mapgenSettings.wall = _wallTexture; + + MapGenGenerateBlank(&mapgenSettings); + GfxInvalidateScreen(); + break; + case WIDX_MAP_SIZE_Y: + _resizeDirection = ResizeDirection::Y; + InputMapSize(WIDX_MAP_SIZE_Y, _mapSize.y); + break; + case WIDX_MAP_SIZE_X: + _resizeDirection = ResizeDirection::X; + InputMapSize(WIDX_MAP_SIZE_X, _mapSize.x); + break; + case WIDX_MAP_SIZE_LINK: + _mapWidthAndHeightLinked = !_mapWidthAndHeightLinked; + break; + case WIDX_BASE_HEIGHT: + ft.Add((BASESIZE_MIN - 12) / 2); + ft.Add((BASESIZE_MAX - 12) / 2); + WindowTextInputOpen( + this, WIDX_BASE_HEIGHT, STR_BASE_HEIGHT, STR_ENTER_BASE_HEIGHT, ft, STR_FORMAT_INTEGER, + (_baseHeight - 12) / 2, 3); + break; + case WIDX_WATER_LEVEL: + ft.Add((WATERLEVEL_MIN - 12) / 2); + ft.Add((WATERLEVEL_MAX - 12) / 2); + WindowTextInputOpen( + this, WIDX_WATER_LEVEL, STR_WATER_LEVEL, STR_ENTER_WATER_LEVEL, ft, STR_FORMAT_INTEGER, + (_waterLevel - 12) / 2, 3); + break; + } + } + + void BaseMouseDown(WidgetIndex widgetIndex, Widget* widget) + { + switch (widgetIndex) + { + case WIDX_MAP_SIZE_Y_UP: + _resizeDirection = ResizeDirection::Y; + ChangeMapSize(+1); + Invalidate(); + break; + case WIDX_MAP_SIZE_Y_DOWN: + _resizeDirection = ResizeDirection::Y; + ChangeMapSize(-1); + Invalidate(); + break; + case WIDX_MAP_SIZE_X_UP: + _resizeDirection = ResizeDirection::X; + ChangeMapSize(+1); + Invalidate(); + break; + case WIDX_MAP_SIZE_X_DOWN: + _resizeDirection = ResizeDirection::X; + ChangeMapSize(-1); + Invalidate(); + break; + case WIDX_BASE_HEIGHT_UP: + _baseHeight = std::min(_baseHeight + 2, BASESIZE_MAX); + Invalidate(); + break; + case WIDX_BASE_HEIGHT_DOWN: + _baseHeight = std::max(_baseHeight - 2, BASESIZE_MIN); + Invalidate(); + break; + case WIDX_WATER_LEVEL_UP: + _waterLevel = std::min(_waterLevel + 2, WATERLEVEL_MAX); + Invalidate(); + break; + case WIDX_WATER_LEVEL_DOWN: + _waterLevel = std::max(_waterLevel - 2, WATERLEVEL_MIN); + Invalidate(); + break; + case WIDX_FLOOR_TEXTURE: + LandTool::ShowSurfaceStyleDropdown(this, widget, _floorTexture); + break; + case WIDX_WALL_TEXTURE: + LandTool::ShowEdgeStyleDropdown(this, widget, _wallTexture); + break; + } + } + + void BaseDropdown(WidgetIndex widgetIndex, int32_t dropdownIndex) + { + int32_t type; + + switch (widgetIndex) + { + case WIDX_FLOOR_TEXTURE: + if (dropdownIndex == -1) + dropdownIndex = gDropdownHighlightedIndex; + + type = (dropdownIndex == -1) ? _floorTexture : dropdownIndex; + + if (gLandToolTerrainSurface == type) + { + gLandToolTerrainSurface = OBJECT_ENTRY_INDEX_NULL; + } + else + { + gLandToolTerrainSurface = type; + _floorTexture = type; + } + Invalidate(); + break; + case WIDX_WALL_TEXTURE: + if (dropdownIndex == -1) + dropdownIndex = gDropdownHighlightedIndex; + + type = (dropdownIndex == -1) ? _wallTexture : dropdownIndex; + + if (gLandToolTerrainEdge == type) + { + gLandToolTerrainEdge = OBJECT_ENTRY_INDEX_NULL; + } + else + { + gLandToolTerrainEdge = type; + _wallTexture = type; + } + Invalidate(); + break; + } + } + + void BaseUpdate() + { + // Tab animation + if (++frame_no >= TabAnimationLoops[page]) + frame_no = 0; + InvalidateWidget(WIDX_TAB_1); + } + + void TextInput(WidgetIndex widgetIndex, std::string_view text) + { + int32_t value; + char* end; + + const auto strText = u8string(text); + value = strtol(strText.c_str(), &end, 10); + + if (*end != '\0') + { + return; + } + + switch (widgetIndex) + { + case WIDX_MAP_SIZE_Y: + case WIDX_MAP_SIZE_X: + case WIDX_SIMPLEX_MAP_SIZE_Y: + case WIDX_SIMPLEX_MAP_SIZE_X: + // The practical size is 2 lower than the technical size + value += 2; + if (_resizeDirection == ResizeDirection::Y || _mapWidthAndHeightLinked) + _mapSize.y = value; + if (_resizeDirection == ResizeDirection::X || _mapWidthAndHeightLinked) + _mapSize.x = value; + break; + case WIDX_BASE_HEIGHT: + _baseHeight = std::clamp((value * 2) + 12, BASESIZE_MIN, BASESIZE_MAX); + break; + case WIDX_WATER_LEVEL: + _waterLevel = std::clamp((value * 2) + 12, WATERLEVEL_MIN, WATERLEVEL_MAX); + break; + } + + Invalidate(); + } + + void BasePrepareDraw() + { + if (widgets != PageWidgets[WINDOW_MAPGEN_PAGE_BASE]) + { + widgets = PageWidgets[WINDOW_MAPGEN_PAGE_BASE]; + InitScrollWidgets(); + } + + // Only allow linking the map size when X and Y are the same + SetWidgetPressed(WIDX_MAP_SIZE_LINK, _mapWidthAndHeightLinked); + SetWidgetDisabled(WIDX_MAP_SIZE_LINK, _mapSize.x != _mapSize.y); + + SetPressedTab(); + + // Push width (Y) and height (X) to the common formatter arguments for the map size spinners to use + auto ft = Formatter::Common(); + ft.Add(_mapSize.y - 2); + ft.Add(_mapSize.x - 2); + } + + void DrawDropdownButton(DrawPixelInfo& dpi, WidgetIndex widgetIndex, ImageId image) + { + const auto& widget = widgets[widgetIndex]; + ScreenCoordsXY pos = { windowPos.x + widget.left, windowPos.y + widget.top }; + if (IsWidgetDisabled(widgetIndex)) + { + // Draw greyed out (light border bottom right shadow) + auto colour = colours[widget.colour]; + colour = ColourMapA[NOT_TRANSLUCENT(colour)].lighter; + GfxDrawSpriteSolid(&dpi, image, pos + ScreenCoordsXY{ 1, 1 }, colour); + + // Draw greyed out (dark) + colour = colours[widget.colour]; + colour = ColourMapA[NOT_TRANSLUCENT(colour)].mid_light; + GfxDrawSpriteSolid(&dpi, image, pos, colour); + } + else + { + GfxDrawSprite(&dpi, image, pos); + } + } + + void DrawDropdownButtons(DrawPixelInfo& dpi, WidgetIndex floorWidgetIndex, WidgetIndex edgeWidgetIndex) + { + auto& objManager = GetContext()->GetObjectManager(); + const auto surfaceObj = static_cast( + objManager.GetLoadedObject(ObjectType::TerrainSurface, _floorTexture)); + ImageId surfaceImage; + if (surfaceObj != nullptr) + { + surfaceImage = ImageId(surfaceObj->IconImageId); + if (surfaceObj->Colour != 255) + { + surfaceImage = surfaceImage.WithPrimary(surfaceObj->Colour); + } + } + + ImageId edgeImage; + const auto edgeObj = static_cast(objManager.GetLoadedObject(ObjectType::TerrainEdge, _wallTexture)); + if (edgeObj != nullptr) + { + edgeImage = ImageId(edgeObj->IconImageId); + } + + DrawDropdownButton(dpi, floorWidgetIndex, surfaceImage); + DrawDropdownButton(dpi, edgeWidgetIndex, edgeImage); + } + + void BaseDraw(DrawPixelInfo& dpi) + { + DrawWidgets(dpi); + DrawTabImages(dpi); + DrawDropdownButtons(dpi, WIDX_FLOOR_TEXTURE, WIDX_WALL_TEXTURE); + + const auto textColour = colours[1]; + + DrawTextBasic(dpi, windowPos + ScreenCoordsXY{ 4, widgets[WIDX_MAP_SIZE_Y].top + 1 }, STR_MAP_SIZE, {}, { textColour }); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ 4, widgets[WIDX_BASE_HEIGHT].top + 1 }, STR_BASE_HEIGHT_LABEL, {}, { textColour }); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ 4, widgets[WIDX_WATER_LEVEL].top + 1 }, STR_WATER_LEVEL_LABEL, {}, { textColour }); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ 4, widgets[WIDX_FLOOR_TEXTURE].top + 1 }, STR_TERRAIN_LABEL, {}, { textColour }); + + auto ft = Formatter(); + ft.Add((_baseHeight - 12) / 2); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ widgets[WIDX_BASE_HEIGHT].left + 1, widgets[WIDX_BASE_HEIGHT].top + 1 }, + STR_COMMA16, ft, { colours[1] }); + + ft = Formatter(); + ft.Add((_waterLevel - 12) / 2); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ widgets[WIDX_WATER_LEVEL].left + 1, widgets[WIDX_WATER_LEVEL].top + 1 }, + STR_COMMA16, ft, { colours[1] }); + } #pragma endregion #pragma region Random page -static void WindowMapgenRandomMouseup(WindowBase* w, WidgetIndex widgetIndex) -{ - WindowMapgenSharedMouseup(w, widgetIndex); - - MapGenSettings mapgenSettings; - - switch (widgetIndex) + void RandomMouseUp(WidgetIndex widgetIndex) { - case WIDX_RANDOM_GENERATE: - mapgenSettings.mapSize = _mapSize; - mapgenSettings.height = _baseHeight + 2; - mapgenSettings.water_level = _waterLevel + 2; - mapgenSettings.floor = _randomTerrain ? -1 : _floorTexture; - mapgenSettings.wall = _randomTerrain ? -1 : _wallTexture; - mapgenSettings.trees = _placeTrees; + SharedMouseUp(widgetIndex); - mapgenSettings.simplex_low = UtilRand() % 4; - mapgenSettings.simplex_high = 12 + (UtilRand() % (32 - 12)); - mapgenSettings.simplex_base_freq = 1.75f; - mapgenSettings.simplex_octaves = 6; + MapGenSettings mapgenSettings; - MapGenGenerate(&mapgenSettings); - GfxInvalidateScreen(); - break; - case WIDX_RANDOM_TERRAIN: - _randomTerrain = !_randomTerrain; - break; - case WIDX_RANDOM_PLACE_TREES: - _placeTrees ^= 1; - break; - } -} + switch (widgetIndex) + { + case WIDX_RANDOM_GENERATE: + mapgenSettings.mapSize = _mapSize; + mapgenSettings.height = _baseHeight + 2; + mapgenSettings.water_level = _waterLevel + 2; + mapgenSettings.floor = _randomTerrain ? -1 : _floorTexture; + mapgenSettings.wall = _randomTerrain ? -1 : _wallTexture; + mapgenSettings.trees = _placeTrees; -static void WindowMapgenRandomMousedown(WindowBase* w, WidgetIndex widgetIndex, Widget* widget) -{ -} + mapgenSettings.simplex_low = UtilRand() % 4; + mapgenSettings.simplex_high = 12 + (UtilRand() % (32 - 12)); + mapgenSettings.simplex_base_freq = 1.75f; + mapgenSettings.simplex_octaves = 6; -static void WindowMapgenRandomUpdate(WindowBase* w) -{ - // Tab animation - if (++w->frame_no >= TabAnimationLoops[w->page]) - w->frame_no = 0; - WidgetInvalidate(*w, WIDX_TAB_2); -} - -static void WindowMapgenRandomInvalidate(WindowBase* w) -{ - if (w->widgets != PageWidgets[WINDOW_MAPGEN_PAGE_RANDOM]) - { - w->widgets = PageWidgets[WINDOW_MAPGEN_PAGE_RANDOM]; - WindowInitScrollWidgets(*w); + MapGenGenerate(&mapgenSettings); + GfxInvalidateScreen(); + break; + case WIDX_RANDOM_TERRAIN: + _randomTerrain = !_randomTerrain; + break; + case WIDX_RANDOM_PLACE_TREES: + _placeTrees ^= 1; + break; + } } - w->pressed_widgets = 0; - if (_randomTerrain) - w->pressed_widgets |= 1uLL << WIDX_RANDOM_TERRAIN; - if (_placeTrees) - w->pressed_widgets |= 1uLL << WIDX_RANDOM_PLACE_TREES; + void RandomUpdate() + { + // Tab animation + if (++frame_no >= TabAnimationLoops[page]) + frame_no = 0; + InvalidateWidget(WIDX_TAB_2); + } - WindowMapgenSetPressedTab(w); -} + void RandomPrepareDraw() + { + if (widgets != PageWidgets[WINDOW_MAPGEN_PAGE_RANDOM]) + { + widgets = PageWidgets[WINDOW_MAPGEN_PAGE_RANDOM]; + InitScrollWidgets(); + } -static void WindowMapgenRandomPaint(WindowBase* w, DrawPixelInfo* dpi) -{ - WindowDrawWidgets(*w, dpi); - WindowMapgenDrawTabImages(dpi, w); -} + pressed_widgets = 0; + if (_randomTerrain) + pressed_widgets |= 1uLL << WIDX_RANDOM_TERRAIN; + if (_placeTrees) + pressed_widgets |= 1uLL << WIDX_RANDOM_PLACE_TREES; + + SetPressedTab(); + } + + void RandomDraw(DrawPixelInfo& dpi) + { + DrawWidgets(dpi); + DrawTabImages(dpi); + } #pragma endregion #pragma region Simplex page -static void WindowMapgenSimplexMouseup(WindowBase* w, WidgetIndex widgetIndex) -{ - WindowMapgenSharedMouseup(w, widgetIndex); - - MapGenSettings mapgenSettings; - - switch (widgetIndex) + void SimplexMouseUp(WidgetIndex widgetIndex) { - case WIDX_SIMPLEX_MAP_SIZE_Y: - _resizeDirection = ResizeDirection::Y; - WindowMapgenInputMapSize(w, WIDX_SIMPLEX_MAP_SIZE_Y, _mapSize.y); - break; - case WIDX_SIMPLEX_MAP_SIZE_X: - _resizeDirection = ResizeDirection::X; - WindowMapgenInputMapSize(w, WIDX_SIMPLEX_MAP_SIZE_X, _mapSize.x); - break; - case WIDX_SIMPLEX_MAP_SIZE_LINK: - _mapWidthAndHeightLinked = !_mapWidthAndHeightLinked; - break; - case WIDX_SIMPLEX_GENERATE: - mapgenSettings.mapSize = _mapSize; + SharedMouseUp(widgetIndex); - mapgenSettings.height = _baseHeight; - mapgenSettings.water_level = _waterLevel + MINIMUM_WATER_HEIGHT; - mapgenSettings.floor = _randomTerrain ? -1 : _floorTexture; - mapgenSettings.wall = _randomTerrain ? -1 : _wallTexture; - mapgenSettings.trees = _placeTrees; + MapGenSettings mapgenSettings; - mapgenSettings.simplex_low = _simplex_low; - mapgenSettings.simplex_high = _simplex_high; - mapgenSettings.simplex_base_freq = (static_cast(_simplex_base_freq)) / 100.00f; - mapgenSettings.simplex_octaves = _simplex_octaves; + switch (widgetIndex) + { + case WIDX_SIMPLEX_MAP_SIZE_Y: + _resizeDirection = ResizeDirection::Y; + InputMapSize(WIDX_SIMPLEX_MAP_SIZE_Y, _mapSize.y); + break; + case WIDX_SIMPLEX_MAP_SIZE_X: + _resizeDirection = ResizeDirection::X; + InputMapSize(WIDX_SIMPLEX_MAP_SIZE_X, _mapSize.x); + break; + case WIDX_SIMPLEX_MAP_SIZE_LINK: + _mapWidthAndHeightLinked = !_mapWidthAndHeightLinked; + break; + case WIDX_SIMPLEX_GENERATE: + mapgenSettings.mapSize = _mapSize; - MapGenGenerate(&mapgenSettings); - GfxInvalidateScreen(); - break; - } -} + mapgenSettings.height = _baseHeight; + mapgenSettings.water_level = _waterLevel + MINIMUM_WATER_HEIGHT; + mapgenSettings.floor = _randomTerrain ? -1 : _floorTexture; + mapgenSettings.wall = _randomTerrain ? -1 : _wallTexture; + mapgenSettings.trees = _placeTrees; -static void WindowMapgenSimplexMousedown(WindowBase* w, WidgetIndex widgetIndex, Widget* widget) -{ - switch (widgetIndex) - { - case WIDX_SIMPLEX_LOW_UP: - _simplex_low = std::min(_simplex_low + 1, 24); - w->Invalidate(); - break; - case WIDX_SIMPLEX_LOW_DOWN: - _simplex_low = std::max(_simplex_low - 1, 0); - w->Invalidate(); - break; - case WIDX_SIMPLEX_HIGH_UP: - _simplex_high = std::min(_simplex_high + 1, 36); - w->Invalidate(); - break; - case WIDX_SIMPLEX_HIGH_DOWN: - _simplex_high = std::max(_simplex_high - 1, 0); - w->Invalidate(); - break; - case WIDX_SIMPLEX_BASE_FREQ_UP: - _simplex_base_freq = std::min(_simplex_base_freq + 5, 1000); - w->Invalidate(); - break; - case WIDX_SIMPLEX_BASE_FREQ_DOWN: - _simplex_base_freq = std::max(_simplex_base_freq - 5, 0); - w->Invalidate(); - break; - case WIDX_SIMPLEX_OCTAVES_UP: - _simplex_octaves = std::min(_simplex_octaves + 1, 10); - w->Invalidate(); - break; - case WIDX_SIMPLEX_OCTAVES_DOWN: - _simplex_octaves = std::max(_simplex_octaves - 1, 1); - w->Invalidate(); - break; - case WIDX_SIMPLEX_MAP_SIZE_Y_UP: - _resizeDirection = ResizeDirection::Y; - WindowMapgenChangeMapSize(+1); - w->Invalidate(); - break; - case WIDX_SIMPLEX_MAP_SIZE_Y_DOWN: - _resizeDirection = ResizeDirection::Y; - WindowMapgenChangeMapSize(-1); - w->Invalidate(); - break; - case WIDX_SIMPLEX_MAP_SIZE_X_UP: - _resizeDirection = ResizeDirection::X; - WindowMapgenChangeMapSize(+1); - w->Invalidate(); - break; - case WIDX_SIMPLEX_MAP_SIZE_X_DOWN: - _resizeDirection = ResizeDirection::X; - WindowMapgenChangeMapSize(-1); - w->Invalidate(); - break; - case WIDX_SIMPLEX_WATER_LEVEL_UP: - _waterLevel = std::min(_waterLevel + MINIMUM_WATER_HEIGHT, MINIMUM_WATER_HEIGHT + MAXIMUM_WATER_HEIGHT); - w->Invalidate(); - break; - case WIDX_SIMPLEX_WATER_LEVEL_DOWN: - _waterLevel = std::max(_waterLevel - MINIMUM_WATER_HEIGHT, 0); - w->Invalidate(); - break; - case WIDX_SIMPLEX_RANDOM_TERRAIN_CHECKBOX: - _randomTerrain = !_randomTerrain; - w->Invalidate(); - break; - case WIDX_SIMPLEX_FLOOR_TEXTURE: - LandTool::ShowSurfaceStyleDropdown(w, widget, _floorTexture); - break; - case WIDX_SIMPLEX_WALL_TEXTURE: - LandTool::ShowEdgeStyleDropdown(w, widget, _wallTexture); - break; - case WIDX_SIMPLEX_PLACE_TREES_CHECKBOX: - _placeTrees ^= 1; - w->Invalidate(); - break; - } -} + mapgenSettings.simplex_low = _simplex_low; + mapgenSettings.simplex_high = _simplex_high; + mapgenSettings.simplex_base_freq = (static_cast(_simplex_base_freq)) / 100.00f; + mapgenSettings.simplex_octaves = _simplex_octaves; -static void WindowMapgenSimplexDropdown(WindowBase* w, WidgetIndex widgetIndex, int32_t dropdownIndex) -{ - int32_t type; - - switch (widgetIndex) - { - case WIDX_SIMPLEX_FLOOR_TEXTURE: - if (dropdownIndex == -1) - dropdownIndex = gDropdownHighlightedIndex; - - type = (dropdownIndex == -1) ? _floorTexture : dropdownIndex; - - if (gLandToolTerrainSurface == type) - { - gLandToolTerrainSurface = OBJECT_ENTRY_INDEX_NULL; - } - else - { - gLandToolTerrainSurface = type; - _floorTexture = type; - } - w->Invalidate(); - break; - case WIDX_SIMPLEX_WALL_TEXTURE: - if (dropdownIndex == -1) - dropdownIndex = gDropdownHighlightedIndex; - - type = (dropdownIndex == -1) ? _wallTexture : dropdownIndex; - - if (gLandToolTerrainEdge == type) - { - gLandToolTerrainEdge = OBJECT_ENTRY_INDEX_NULL; - } - else - { - gLandToolTerrainEdge = type; - _wallTexture = type; - } - w->Invalidate(); - break; - } -} - -static void WindowMapgenSimplexUpdate(WindowBase* w) -{ - // Tab animation - if (++w->frame_no >= TabAnimationLoops[w->page]) - w->frame_no = 0; - WidgetInvalidate(*w, WIDX_TAB_3); -} - -static void WindowMapgenSimplexInvalidate(WindowBase* w) -{ - if (w->widgets != PageWidgets[WINDOW_MAPGEN_PAGE_SIMPLEX]) - { - w->widgets = PageWidgets[WINDOW_MAPGEN_PAGE_SIMPLEX]; - WindowInitScrollWidgets(*w); + MapGenGenerate(&mapgenSettings); + GfxInvalidateScreen(); + break; + } } - // Only allow linking the map size when X and Y are the same - WidgetSetPressed(*w, WIDX_SIMPLEX_MAP_SIZE_LINK, _mapWidthAndHeightLinked); - WidgetSetDisabled(*w, WIDX_SIMPLEX_MAP_SIZE_LINK, _mapSize.x != _mapSize.y); - - WidgetSetCheckboxValue(*w, WIDX_SIMPLEX_RANDOM_TERRAIN_CHECKBOX, _randomTerrain != 0); - WidgetSetCheckboxValue(*w, WIDX_SIMPLEX_PLACE_TREES_CHECKBOX, _placeTrees != 0); - - // Only allow floor and wall texture options if random terrain is disabled - if (!_randomTerrain) + void SimplexMouseDown(WidgetIndex widgetIndex, Widget* widget) { - WidgetSetEnabled(*w, WIDX_SIMPLEX_FLOOR_TEXTURE, true); - WidgetSetEnabled(*w, WIDX_SIMPLEX_WALL_TEXTURE, true); - } - else - { - WidgetSetEnabled(*w, WIDX_SIMPLEX_FLOOR_TEXTURE, false); - WidgetSetEnabled(*w, WIDX_SIMPLEX_WALL_TEXTURE, false); + switch (widgetIndex) + { + case WIDX_SIMPLEX_LOW_UP: + _simplex_low = std::min(_simplex_low + 1, 24); + Invalidate(); + break; + case WIDX_SIMPLEX_LOW_DOWN: + _simplex_low = std::max(_simplex_low - 1, 0); + Invalidate(); + break; + case WIDX_SIMPLEX_HIGH_UP: + _simplex_high = std::min(_simplex_high + 1, 36); + Invalidate(); + break; + case WIDX_SIMPLEX_HIGH_DOWN: + _simplex_high = std::max(_simplex_high - 1, 0); + Invalidate(); + break; + case WIDX_SIMPLEX_BASE_FREQ_UP: + _simplex_base_freq = std::min(_simplex_base_freq + 5, 1000); + Invalidate(); + break; + case WIDX_SIMPLEX_BASE_FREQ_DOWN: + _simplex_base_freq = std::max(_simplex_base_freq - 5, 0); + Invalidate(); + break; + case WIDX_SIMPLEX_OCTAVES_UP: + _simplex_octaves = std::min(_simplex_octaves + 1, 10); + Invalidate(); + break; + case WIDX_SIMPLEX_OCTAVES_DOWN: + _simplex_octaves = std::max(_simplex_octaves - 1, 1); + Invalidate(); + break; + case WIDX_SIMPLEX_MAP_SIZE_Y_UP: + _resizeDirection = ResizeDirection::Y; + ChangeMapSize(+1); + Invalidate(); + break; + case WIDX_SIMPLEX_MAP_SIZE_Y_DOWN: + _resizeDirection = ResizeDirection::Y; + ChangeMapSize(-1); + Invalidate(); + break; + case WIDX_SIMPLEX_MAP_SIZE_X_UP: + _resizeDirection = ResizeDirection::X; + ChangeMapSize(+1); + Invalidate(); + break; + case WIDX_SIMPLEX_MAP_SIZE_X_DOWN: + _resizeDirection = ResizeDirection::X; + ChangeMapSize(-1); + Invalidate(); + break; + case WIDX_SIMPLEX_WATER_LEVEL_UP: + _waterLevel = std::min(_waterLevel + MINIMUM_WATER_HEIGHT, MINIMUM_WATER_HEIGHT + MAXIMUM_WATER_HEIGHT); + Invalidate(); + break; + case WIDX_SIMPLEX_WATER_LEVEL_DOWN: + _waterLevel = std::max(_waterLevel - MINIMUM_WATER_HEIGHT, 0); + Invalidate(); + break; + case WIDX_SIMPLEX_RANDOM_TERRAIN_CHECKBOX: + _randomTerrain = !_randomTerrain; + Invalidate(); + break; + case WIDX_SIMPLEX_FLOOR_TEXTURE: + LandTool::ShowSurfaceStyleDropdown(this, widget, _floorTexture); + break; + case WIDX_SIMPLEX_WALL_TEXTURE: + LandTool::ShowEdgeStyleDropdown(this, widget, _wallTexture); + break; + case WIDX_SIMPLEX_PLACE_TREES_CHECKBOX: + _placeTrees ^= 1; + Invalidate(); + break; + } } - WindowMapgenSetPressedTab(w); + void SimplexDropdown(WidgetIndex widgetIndex, int32_t dropdownIndex) + { + int32_t type; - // Push width (Y) and height (X) to the common formatter arguments for the map size spinners to use - auto ft = Formatter::Common(); - ft.Add(_mapSize.y - 2); - ft.Add(_mapSize.x - 2); -} + switch (widgetIndex) + { + case WIDX_SIMPLEX_FLOOR_TEXTURE: + if (dropdownIndex == -1) + dropdownIndex = gDropdownHighlightedIndex; -static void WindowMapgenSimplexPaint(WindowBase* w, DrawPixelInfo* dpi) -{ - WindowDrawWidgets(*w, dpi); - WindowMapgenDrawTabImages(dpi, w); - WindowMapgenDrawDropdownButtons(w, dpi, WIDX_SIMPLEX_FLOOR_TEXTURE, WIDX_SIMPLEX_WALL_TEXTURE); + type = (dropdownIndex == -1) ? _floorTexture : dropdownIndex; - const uint8_t textColour = w->colours[1]; + if (gLandToolTerrainSurface == type) + { + gLandToolTerrainSurface = OBJECT_ENTRY_INDEX_NULL; + } + else + { + gLandToolTerrainSurface = type; + _floorTexture = type; + } + Invalidate(); + break; + case WIDX_SIMPLEX_WALL_TEXTURE: + if (dropdownIndex == -1) + dropdownIndex = gDropdownHighlightedIndex; - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ 5, w->widgets[WIDX_SIMPLEX_LOW].top + 1 }, STR_MAPGEN_SIMPLEX_NOISE_LOW_, {}, - { textColour }); - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ 5, w->widgets[WIDX_SIMPLEX_HIGH].top + 1 }, STR_MAPGEN_SIMPLEX_NOISE_HIGH, {}, - { textColour }); - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ 5, w->widgets[WIDX_SIMPLEX_BASE_FREQ].top + 1 }, - STR_MAPGEN_SIMPLEX_NOISE_BASE_FREQUENCY, {}, { textColour }); - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ 5, w->widgets[WIDX_SIMPLEX_OCTAVES].top + 1 }, STR_MAPGEN_SIMPLEX_NOISE_OCTAVES, - {}, { textColour }); - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ 5, w->widgets[WIDX_SIMPLEX_MAP_SIZE_Y].top + 1 }, STR_MAP_SIZE, {}, - { textColour }); - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ 5, w->widgets[WIDX_SIMPLEX_WATER_LEVEL].top + 1 }, STR_WATER_LEVEL_LABEL, {}, - { textColour }); + type = (dropdownIndex == -1) ? _wallTexture : dropdownIndex; - auto ft = Formatter(); - ft.Add(_simplex_low); - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ w->widgets[WIDX_SIMPLEX_LOW].left + 1, w->widgets[WIDX_SIMPLEX_LOW].top + 1 }, - STR_COMMA16, ft, { textColour }); - ft = Formatter(); - ft.Add(_simplex_high); - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ w->widgets[WIDX_SIMPLEX_HIGH].left + 1, w->widgets[WIDX_SIMPLEX_HIGH].top + 1 }, - STR_COMMA16, ft, { textColour }); - ft = Formatter(); - ft.Add(_simplex_base_freq); - DrawTextBasic( - *dpi, - w->windowPos - + ScreenCoordsXY{ w->widgets[WIDX_SIMPLEX_BASE_FREQ].left + 1, w->widgets[WIDX_SIMPLEX_BASE_FREQ].top + 1 }, - STR_WINDOW_COLOUR_2_COMMA2DP32, ft, { textColour }); - ft = Formatter(); - ft.Add(_simplex_octaves); - DrawTextBasic( - *dpi, - w->windowPos + ScreenCoordsXY{ w->widgets[WIDX_SIMPLEX_OCTAVES].left + 1, w->widgets[WIDX_SIMPLEX_OCTAVES].top + 1 }, - STR_COMMA16, ft, { textColour }); - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ 5, w->widgets[WIDX_SIMPLEX_RANDOM_TERRAIN_CHECKBOX].top + 1 }, STR_TERRAIN_LABEL, - {}, { textColour }); - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ 5, w->widgets[WIDX_SIMPLEX_PLACE_TREES_CHECKBOX].top + 1 }, - STR_MAPGEN_OPTION_PLACE_TREES, {}, { textColour }); + if (gLandToolTerrainEdge == type) + { + gLandToolTerrainEdge = OBJECT_ENTRY_INDEX_NULL; + } + else + { + gLandToolTerrainEdge = type; + _wallTexture = type; + } + Invalidate(); + break; + } + } - ft = Formatter(); - ft.Add((_waterLevel - 12) / 2); - DrawTextBasic( - *dpi, - w->windowPos - + ScreenCoordsXY{ w->widgets[WIDX_SIMPLEX_WATER_LEVEL].left + 1, w->widgets[WIDX_SIMPLEX_WATER_LEVEL].top + 1 }, - STR_COMMA16, ft, { textColour }); -} + void SimplexUpdate() + { + // Tab animation + if (++frame_no >= TabAnimationLoops[page]) + frame_no = 0; + InvalidateWidget(WIDX_TAB_3); + } + + void SimplexPrepareDraw() + { + if (widgets != PageWidgets[WINDOW_MAPGEN_PAGE_SIMPLEX]) + { + widgets = PageWidgets[WINDOW_MAPGEN_PAGE_SIMPLEX]; + InitScrollWidgets(); + } + + // Only allow linking the map size when X and Y are the same + SetWidgetPressed(WIDX_SIMPLEX_MAP_SIZE_LINK, _mapWidthAndHeightLinked); + SetWidgetDisabled(WIDX_SIMPLEX_MAP_SIZE_LINK, _mapSize.x != _mapSize.y); + + SetCheckboxValue(WIDX_SIMPLEX_RANDOM_TERRAIN_CHECKBOX, _randomTerrain != 0); + SetCheckboxValue(WIDX_SIMPLEX_PLACE_TREES_CHECKBOX, _placeTrees != 0); + + // Only allow floor and wall texture options if random terrain is disabled + if (!_randomTerrain) + { + SetWidgetEnabled(WIDX_SIMPLEX_FLOOR_TEXTURE, true); + SetWidgetEnabled(WIDX_SIMPLEX_WALL_TEXTURE, true); + } + else + { + SetWidgetEnabled(WIDX_SIMPLEX_FLOOR_TEXTURE, false); + SetWidgetEnabled(WIDX_SIMPLEX_WALL_TEXTURE, false); + } + + SetPressedTab(); + + // Push width (Y) and height (X) to the common formatter arguments for the map size spinners to use + auto ft = Formatter::Common(); + ft.Add(_mapSize.y - 2); + ft.Add(_mapSize.x - 2); + } + + void SimplexDraw(DrawPixelInfo& dpi) + { + DrawWidgets(dpi); + DrawTabImages(dpi); + DrawDropdownButtons(dpi, WIDX_SIMPLEX_FLOOR_TEXTURE, WIDX_SIMPLEX_WALL_TEXTURE); + + const uint8_t textColour = colours[1]; + + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ 5, widgets[WIDX_SIMPLEX_LOW].top + 1 }, STR_MAPGEN_SIMPLEX_NOISE_LOW_, {}, + { textColour }); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ 5, widgets[WIDX_SIMPLEX_HIGH].top + 1 }, STR_MAPGEN_SIMPLEX_NOISE_HIGH, {}, + { textColour }); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ 5, widgets[WIDX_SIMPLEX_BASE_FREQ].top + 1 }, + STR_MAPGEN_SIMPLEX_NOISE_BASE_FREQUENCY, {}, { textColour }); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ 5, widgets[WIDX_SIMPLEX_OCTAVES].top + 1 }, STR_MAPGEN_SIMPLEX_NOISE_OCTAVES, {}, + { textColour }); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ 5, widgets[WIDX_SIMPLEX_MAP_SIZE_Y].top + 1 }, STR_MAP_SIZE, {}, { textColour }); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ 5, widgets[WIDX_SIMPLEX_WATER_LEVEL].top + 1 }, STR_WATER_LEVEL_LABEL, {}, + { textColour }); + + auto ft = Formatter(); + ft.Add(_simplex_low); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ widgets[WIDX_SIMPLEX_LOW].left + 1, widgets[WIDX_SIMPLEX_LOW].top + 1 }, + STR_COMMA16, ft, { textColour }); + ft = Formatter(); + ft.Add(_simplex_high); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ widgets[WIDX_SIMPLEX_HIGH].left + 1, widgets[WIDX_SIMPLEX_HIGH].top + 1 }, + STR_COMMA16, ft, { textColour }); + ft = Formatter(); + ft.Add(_simplex_base_freq); + DrawTextBasic( + dpi, + windowPos + ScreenCoordsXY{ widgets[WIDX_SIMPLEX_BASE_FREQ].left + 1, widgets[WIDX_SIMPLEX_BASE_FREQ].top + 1 }, + STR_WINDOW_COLOUR_2_COMMA2DP32, ft, { textColour }); + ft = Formatter(); + ft.Add(_simplex_octaves); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ widgets[WIDX_SIMPLEX_OCTAVES].left + 1, widgets[WIDX_SIMPLEX_OCTAVES].top + 1 }, + STR_COMMA16, ft, { textColour }); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ 5, widgets[WIDX_SIMPLEX_RANDOM_TERRAIN_CHECKBOX].top + 1 }, STR_TERRAIN_LABEL, {}, + { textColour }); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ 5, widgets[WIDX_SIMPLEX_PLACE_TREES_CHECKBOX].top + 1 }, + STR_MAPGEN_OPTION_PLACE_TREES, {}, { textColour }); + + ft = Formatter(); + ft.Add((_waterLevel - 12) / 2); + DrawTextBasic( + dpi, + windowPos + ScreenCoordsXY{ widgets[WIDX_SIMPLEX_WATER_LEVEL].left + 1, widgets[WIDX_SIMPLEX_WATER_LEVEL].top + 1 }, + STR_COMMA16, ft, { textColour }); + } #pragma endregion #pragma region Heightmap page -static void WindowMapgenHeightmapMousedown(WindowBase* w, WidgetIndex widgetIndex, Widget* widget) -{ - switch (widgetIndex) + void HeightmapMouseDown(WidgetIndex widgetIndex, Widget* widget) { - case WIDX_HEIGHTMAP_STRENGTH_UP: - _heightmapSmoothStrength = std::min(_heightmapSmoothStrength + 1, MAX_SMOOTH_ITERATIONS); - WidgetInvalidate(*w, WIDX_HEIGHTMAP_STRENGTH); - break; - case WIDX_HEIGHTMAP_STRENGTH_DOWN: - _heightmapSmoothStrength = std::max(_heightmapSmoothStrength - 1, 1); - WidgetInvalidate(*w, WIDX_HEIGHTMAP_STRENGTH); - break; - case WIDX_HEIGHTMAP_LOW_UP: - _heightmapLow = std::min(_heightmapLow + 1, 142 - 1); - _heightmapHigh = std::max(_heightmapHigh, _heightmapLow + 1); - WidgetInvalidate(*w, WIDX_HEIGHTMAP_LOW); - break; - case WIDX_HEIGHTMAP_LOW_DOWN: - _heightmapLow = std::max(_heightmapLow - 1, 2); - WidgetInvalidate(*w, WIDX_HEIGHTMAP_LOW); - break; - case WIDX_HEIGHTMAP_HIGH_UP: - _heightmapHigh = std::min(_heightmapHigh + 1, 142); - WidgetInvalidate(*w, WIDX_HEIGHTMAP_HIGH); - break; - case WIDX_HEIGHTMAP_HIGH_DOWN: - _heightmapHigh = std::max(_heightmapHigh - 1, 2 + 1); - _heightmapLow = std::min(_heightmapLow, _heightmapHigh - 1); - WidgetInvalidate(*w, WIDX_HEIGHTMAP_HIGH); - break; - case WIDX_HEIGHTMAP_WATER_LEVEL_UP: - _waterLevel = std::min(_waterLevel + MINIMUM_WATER_HEIGHT, MINIMUM_WATER_HEIGHT + MAXIMUM_WATER_HEIGHT); - WidgetInvalidate(*w, WIDX_HEIGHTMAP_WATER_LEVEL); - break; - case WIDX_HEIGHTMAP_WATER_LEVEL_DOWN: - _waterLevel = std::max(_waterLevel - MINIMUM_WATER_HEIGHT, 0); - WidgetInvalidate(*w, WIDX_HEIGHTMAP_WATER_LEVEL); - break; - } -} - -static void WindowMapgenHeightmapGenerateMap() -{ - MapGenSettings mapgenSettings; - mapgenSettings.water_level = _waterLevel; - mapgenSettings.smooth = _heightmapSmoothTiles; - mapgenSettings.smooth_height_map = _heightmapSmoothMap; - mapgenSettings.smooth_strength = _heightmapSmoothStrength; - mapgenSettings.normalize_height = _heightmapNormalize; - mapgenSettings.simplex_low = _heightmapLow; - mapgenSettings.simplex_high = _heightmapHigh; - MapGenGenerateFromHeightmap(&mapgenSettings); - GfxInvalidateScreen(); -} - -static void WindowMapgenHeightmapLoadsaveCallback(int32_t result, const utf8* path) -{ - if (result == MODAL_RESULT_OK) - { - if (!MapGenLoadHeightmap(path)) + switch (widgetIndex) { - // TODO: Display error popup - return; + case WIDX_HEIGHTMAP_STRENGTH_UP: + _heightmapSmoothStrength = std::min(_heightmapSmoothStrength + 1, MAX_SMOOTH_ITERATIONS); + InvalidateWidget(WIDX_HEIGHTMAP_STRENGTH); + break; + case WIDX_HEIGHTMAP_STRENGTH_DOWN: + _heightmapSmoothStrength = std::max(_heightmapSmoothStrength - 1, 1); + InvalidateWidget(WIDX_HEIGHTMAP_STRENGTH); + break; + case WIDX_HEIGHTMAP_LOW_UP: + _heightmapLow = std::min(_heightmapLow + 1, 142 - 1); + _heightmapHigh = std::max(_heightmapHigh, _heightmapLow + 1); + InvalidateWidget(WIDX_HEIGHTMAP_LOW); + break; + case WIDX_HEIGHTMAP_LOW_DOWN: + _heightmapLow = std::max(_heightmapLow - 1, 2); + InvalidateWidget(WIDX_HEIGHTMAP_LOW); + break; + case WIDX_HEIGHTMAP_HIGH_UP: + _heightmapHigh = std::min(_heightmapHigh + 1, 142); + InvalidateWidget(WIDX_HEIGHTMAP_HIGH); + break; + case WIDX_HEIGHTMAP_HIGH_DOWN: + _heightmapHigh = std::max(_heightmapHigh - 1, 2 + 1); + _heightmapLow = std::min(_heightmapLow, _heightmapHigh - 1); + InvalidateWidget(WIDX_HEIGHTMAP_HIGH); + break; + case WIDX_HEIGHTMAP_WATER_LEVEL_UP: + _waterLevel = std::min(_waterLevel + MINIMUM_WATER_HEIGHT, MINIMUM_WATER_HEIGHT + MAXIMUM_WATER_HEIGHT); + InvalidateWidget(WIDX_HEIGHTMAP_WATER_LEVEL); + break; + case WIDX_HEIGHTMAP_WATER_LEVEL_DOWN: + _waterLevel = std::max(_waterLevel - MINIMUM_WATER_HEIGHT, 0); + InvalidateWidget(WIDX_HEIGHTMAP_WATER_LEVEL); + break; + } + } + + void HeightmapGenerateMap() + { + MapGenSettings mapgenSettings; + mapgenSettings.water_level = _waterLevel; + mapgenSettings.smooth = _heightmapSmoothTiles; + mapgenSettings.smooth_height_map = _heightmapSmoothMap; + mapgenSettings.smooth_strength = _heightmapSmoothStrength; + mapgenSettings.normalize_height = _heightmapNormalize; + mapgenSettings.simplex_low = _heightmapLow; + mapgenSettings.simplex_high = _heightmapHigh; + MapGenGenerateFromHeightmap(&mapgenSettings); + GfxInvalidateScreen(); + } + + void HeightmapMouseUp(WidgetIndex widgetIndex) + { + SharedMouseUp(widgetIndex); + + switch (widgetIndex) + { + case WIDX_CLOSE: + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + return; // Only widgets that change a setting need to regenerate the map + + // Page widgets + case WIDX_HEIGHTMAP_SELECT: + { + auto intent = Intent(WindowClass::Loadsave); + intent.PutExtra(INTENT_EXTRA_LOADSAVE_TYPE, LOADSAVETYPE_LOAD | LOADSAVETYPE_HEIGHTMAP); + intent.PutExtra(INTENT_EXTRA_CALLBACK, reinterpret_cast(HeightmapLoadsaveCallback)); + ContextOpenIntent(&intent); + return; + } + case WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP: + _heightmapSmoothMap = !_heightmapSmoothMap; + SetCheckboxValue(WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP, _heightmapSmoothMap); + SetWidgetEnabled(WIDX_HEIGHTMAP_STRENGTH, _heightmapSmoothMap); + SetWidgetEnabled(WIDX_HEIGHTMAP_STRENGTH_UP, _heightmapSmoothMap); + SetWidgetEnabled(WIDX_HEIGHTMAP_STRENGTH_DOWN, _heightmapSmoothMap); + InvalidateWidget(WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP); + InvalidateWidget(WIDX_HEIGHTMAP_STRENGTH); + break; + case WIDX_HEIGHTMAP_NORMALIZE: + _heightmapNormalize = !_heightmapNormalize; + SetCheckboxValue(WIDX_HEIGHTMAP_NORMALIZE, _heightmapNormalize); + InvalidateWidget(WIDX_HEIGHTMAP_NORMALIZE); + break; + case WIDX_HEIGHTMAP_SMOOTH_TILES: + _heightmapSmoothTiles = !_heightmapSmoothTiles; + SetCheckboxValue(WIDX_HEIGHTMAP_SMOOTH_TILES, _heightmapSmoothTiles); + InvalidateWidget(WIDX_HEIGHTMAP_SMOOTH_TILES); + break; } - // The window needs to be open while using the map - WindowBase* const w = ContextOpenWindow(WindowClass::Mapgen); - _heightmapLoaded = true; - WindowMapgenSetPage(w, WINDOW_MAPGEN_PAGE_HEIGHTMAP); - - WindowMapgenHeightmapGenerateMap(); + // Always regenerate the map after one of the page widgets has been changed + HeightmapGenerateMap(); } -} -static void WindowMapgenHeightmapMouseup(WindowBase* w, WidgetIndex widgetIndex) -{ - WindowMapgenSharedMouseup(w, widgetIndex); - - switch (widgetIndex) + void HeightmapPrepareDraw() { - case WIDX_CLOSE: - case WIDX_TAB_1: - case WIDX_TAB_2: - case WIDX_TAB_3: - case WIDX_TAB_4: - return; // Only widgets that change a setting need to regenerate the map - - // Page widgets - case WIDX_HEIGHTMAP_SELECT: + if (widgets != PageWidgets[WINDOW_MAPGEN_PAGE_HEIGHTMAP]) { - auto intent = Intent(WindowClass::Loadsave); - intent.PutExtra(INTENT_EXTRA_LOADSAVE_TYPE, LOADSAVETYPE_LOAD | LOADSAVETYPE_HEIGHTMAP); - intent.PutExtra(INTENT_EXTRA_CALLBACK, reinterpret_cast(WindowMapgenHeightmapLoadsaveCallback)); - ContextOpenIntent(&intent); - return; + widgets = PageWidgets[WINDOW_MAPGEN_PAGE_HEIGHTMAP]; + InitScrollWidgets(); } - case WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP: - _heightmapSmoothMap = !_heightmapSmoothMap; - WidgetSetCheckboxValue(*w, WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP, _heightmapSmoothMap); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_STRENGTH, _heightmapSmoothMap); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_STRENGTH_UP, _heightmapSmoothMap); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_STRENGTH_DOWN, _heightmapSmoothMap); - WidgetInvalidate(*w, WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP); - WidgetInvalidate(*w, WIDX_HEIGHTMAP_STRENGTH); - break; - case WIDX_HEIGHTMAP_NORMALIZE: - _heightmapNormalize = !_heightmapNormalize; - WidgetSetCheckboxValue(*w, WIDX_HEIGHTMAP_NORMALIZE, _heightmapNormalize); - WidgetInvalidate(*w, WIDX_HEIGHTMAP_NORMALIZE); - break; - case WIDX_HEIGHTMAP_SMOOTH_TILES: - _heightmapSmoothTiles = !_heightmapSmoothTiles; - WidgetSetCheckboxValue(*w, WIDX_HEIGHTMAP_SMOOTH_TILES, _heightmapSmoothTiles); - WidgetInvalidate(*w, WIDX_HEIGHTMAP_SMOOTH_TILES); - break; + + SetCheckboxValue(WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP, _heightmapSmoothMap); + SetCheckboxValue(WIDX_HEIGHTMAP_NORMALIZE, _heightmapNormalize); + SetCheckboxValue(WIDX_HEIGHTMAP_SMOOTH_TILES, _heightmapSmoothTiles); + + SetPressedTab(); } - // Always regenerate the map after one of the page widgets has been changed - WindowMapgenHeightmapGenerateMap(); -} - -static void WindowMapgenHeightmapInvalidate(WindowBase* w) -{ - if (w->widgets != PageWidgets[WINDOW_MAPGEN_PAGE_HEIGHTMAP]) + void HeightmapDraw(DrawPixelInfo& dpi) { - w->widgets = PageWidgets[WINDOW_MAPGEN_PAGE_HEIGHTMAP]; - WindowInitScrollWidgets(*w); + DrawWidgets(dpi); + DrawTabImages(dpi); + + const colour_t enabledColour = colours[1]; + const colour_t disabledColour = enabledColour | COLOUR_FLAG_INSET; + + // Smooth strength label and value + const colour_t strengthColour = _heightmapSmoothMap ? enabledColour : disabledColour; + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ 5, widgets[WIDX_HEIGHTMAP_STRENGTH].top + 1 }, STR_MAPGEN_SMOOTH_STRENGTH, {}, + { strengthColour }); + + auto ft = Formatter(); + ft.Add(_heightmapSmoothStrength); + DrawTextBasic( + dpi, + windowPos + ScreenCoordsXY{ widgets[WIDX_HEIGHTMAP_STRENGTH].left + 1, widgets[WIDX_HEIGHTMAP_STRENGTH].top + 1 }, + STR_COMMA16, ft, { strengthColour }); + + // Low label and value + const colour_t labelColour = _heightmapLoaded ? enabledColour : disabledColour; + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ 5, widgets[WIDX_HEIGHTMAP_LOW].top + 1 }, STR_MAPGEN_SIMPLEX_NOISE_LOW_, {}, + { labelColour }); + + ft = Formatter(); + ft.Add(_heightmapLow); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ widgets[WIDX_HEIGHTMAP_LOW].left + 1, widgets[WIDX_HEIGHTMAP_LOW].top + 1 }, + STR_COMMA16, ft, { labelColour }); + + // High label and value + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ 5, widgets[WIDX_HEIGHTMAP_HIGH].top + 1 }, STR_MAPGEN_SIMPLEX_NOISE_HIGH, {}, + { labelColour }); + + ft = Formatter(); + ft.Add(_heightmapHigh); + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ widgets[WIDX_HEIGHTMAP_HIGH].left + 1, widgets[WIDX_HEIGHTMAP_HIGH].top + 1 }, + STR_COMMA16, ft, { labelColour }); + + // Water level label and value + DrawTextBasic( + dpi, windowPos + ScreenCoordsXY{ 5, widgets[WIDX_HEIGHTMAP_WATER_LEVEL].top + 1 }, STR_WATER_LEVEL_LABEL, {}, + { labelColour }); + + ft = Formatter(); + ft.Add(_waterLevel); + DrawTextBasic( + dpi, + windowPos + + ScreenCoordsXY{ widgets[WIDX_HEIGHTMAP_WATER_LEVEL].left + 1, widgets[WIDX_HEIGHTMAP_WATER_LEVEL].top + 1 }, + STR_COMMA16, ft, { labelColour }); } - WidgetSetCheckboxValue(*w, WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP, _heightmapSmoothMap); - WidgetSetCheckboxValue(*w, WIDX_HEIGHTMAP_NORMALIZE, _heightmapNormalize); - WidgetSetCheckboxValue(*w, WIDX_HEIGHTMAP_SMOOTH_TILES, _heightmapSmoothTiles); - - WindowMapgenSetPressedTab(w); -} - -static void WindowMapgenHeightmapPaint(WindowBase* w, DrawPixelInfo* dpi) -{ - WindowDrawWidgets(*w, dpi); - WindowMapgenDrawTabImages(dpi, w); - - const colour_t enabledColour = w->colours[1]; - const colour_t disabledColour = enabledColour | COLOUR_FLAG_INSET; - - // Smooth strength label and value - const colour_t strengthColour = _heightmapSmoothMap ? enabledColour : disabledColour; - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ 5, w->widgets[WIDX_HEIGHTMAP_STRENGTH].top + 1 }, STR_MAPGEN_SMOOTH_STRENGTH, {}, - { strengthColour }); - - auto ft = Formatter(); - ft.Add(_heightmapSmoothStrength); - DrawTextBasic( - *dpi, - w->windowPos - + ScreenCoordsXY{ w->widgets[WIDX_HEIGHTMAP_STRENGTH].left + 1, w->widgets[WIDX_HEIGHTMAP_STRENGTH].top + 1 }, - STR_COMMA16, ft, { strengthColour }); - - // Low label and value - const colour_t labelColour = _heightmapLoaded ? enabledColour : disabledColour; - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ 5, w->widgets[WIDX_HEIGHTMAP_LOW].top + 1 }, STR_MAPGEN_SIMPLEX_NOISE_LOW_, {}, - { labelColour }); - - ft = Formatter(); - ft.Add(_heightmapLow); - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ w->widgets[WIDX_HEIGHTMAP_LOW].left + 1, w->widgets[WIDX_HEIGHTMAP_LOW].top + 1 }, - STR_COMMA16, ft, { labelColour }); - - // High label and value - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ 5, w->widgets[WIDX_HEIGHTMAP_HIGH].top + 1 }, STR_MAPGEN_SIMPLEX_NOISE_HIGH, {}, - { labelColour }); - - ft = Formatter(); - ft.Add(_heightmapHigh); - DrawTextBasic( - *dpi, - w->windowPos + ScreenCoordsXY{ w->widgets[WIDX_HEIGHTMAP_HIGH].left + 1, w->widgets[WIDX_HEIGHTMAP_HIGH].top + 1 }, - STR_COMMA16, ft, { labelColour }); - - // Water level label and value - DrawTextBasic( - *dpi, w->windowPos + ScreenCoordsXY{ 5, w->widgets[WIDX_HEIGHTMAP_WATER_LEVEL].top + 1 }, STR_WATER_LEVEL_LABEL, {}, - { labelColour }); - - ft = Formatter(); - ft.Add(_waterLevel); - DrawTextBasic( - *dpi, - w->windowPos - + ScreenCoordsXY{ w->widgets[WIDX_HEIGHTMAP_WATER_LEVEL].left + 1, w->widgets[WIDX_HEIGHTMAP_WATER_LEVEL].top + 1 }, - STR_COMMA16, ft, { labelColour }); -} - #pragma endregion -#pragma region Common - -static void WindowMapgenSetPage(WindowBase* w, int32_t page) -{ - w->page = page; - w->frame_no = 0; - w->RemoveViewport(); - - w->hold_down_widgets = HoldDownWidgets[page]; - w->event_handlers = PageEvents[page]; - w->widgets = PageWidgets[page]; - w->disabled_widgets = PageDisabledWidgets[page]; - w->pressed_widgets = PressedWidgets[page]; - - // Enable heightmap widgets if one is loaded - if (page == WINDOW_MAPGEN_PAGE_HEIGHTMAP && _heightmapLoaded) +public: + void OnOpen() override { - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP, true); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_STRENGTH, _heightmapSmoothMap); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_STRENGTH_UP, _heightmapSmoothMap); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_STRENGTH_DOWN, _heightmapSmoothMap); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_NORMALIZE, true); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_SMOOTH_TILES, true); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_HIGH, true); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_HIGH_UP, true); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_HIGH_DOWN, true); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_LOW, true); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_LOW_UP, true); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_LOW_DOWN, true); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_WATER_LEVEL, true); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_WATER_LEVEL_UP, true); - WidgetSetEnabled(*w, WIDX_HEIGHTMAP_WATER_LEVEL_DOWN, true); + number = 0; + frame_no = 0; + + page = WINDOW_MAPGEN_PAGE_BASE; + Invalidate(); + widgets = PageWidgets[WINDOW_MAPGEN_PAGE_BASE]; + hold_down_widgets = HoldDownWidgets[WINDOW_MAPGEN_PAGE_BASE]; + pressed_widgets = PressedWidgets[WINDOW_MAPGEN_PAGE_BASE]; + disabled_widgets = PageDisabledWidgets[WINDOW_MAPGEN_PAGE_BASE]; + InitScrollWidgets(); + + _heightmapLoaded = false; } - WindowInitScrollWidgets(*w); - w->Invalidate(); -} - -static void WindowMapgenSetPressedTab(WindowBase* w) -{ - int32_t i; - for (i = 0; i < WINDOW_MAPGEN_PAGE_COUNT; i++) - w->pressed_widgets &= ~(1 << (WIDX_TAB_1 + i)); - w->pressed_widgets |= 1LL << (WIDX_TAB_1 + w->page); -} - -static void WindowMapgenDrawTabImage(DrawPixelInfo* dpi, WindowBase* w, int32_t page, int32_t spriteIndex) -{ - WidgetIndex widgetIndex = WIDX_TAB_1 + page; - - if (!WidgetIsDisabled(*w, widgetIndex)) + void OnClose() override { - if (w->page == page) + MapGenUnloadHeightmap(); + } + + void OnMouseUp(WidgetIndex widgetIndex) override + { + switch (page) { - int32_t frame = w->frame_no / TabAnimationDivisor[w->page]; - spriteIndex += (frame % TabAnimationFrames[w->page]); + case WINDOW_MAPGEN_PAGE_BASE: + return BaseMouseUp(widgetIndex); + case WINDOW_MAPGEN_PAGE_RANDOM: + return RandomMouseUp(widgetIndex); + case WINDOW_MAPGEN_PAGE_SIMPLEX: + return SimplexMouseUp(widgetIndex); + case WINDOW_MAPGEN_PAGE_HEIGHTMAP: + return HeightmapMouseUp(widgetIndex); } - - GfxDrawSprite( - dpi, ImageId(spriteIndex), - w->windowPos + ScreenCoordsXY{ w->widgets[widgetIndex].left, w->widgets[widgetIndex].top }); } -} -static void WindowMapgenDrawTabImages(DrawPixelInfo* dpi, WindowBase* w) + void OnMouseDown(WidgetIndex widgetIndex) override + { + switch (page) + { + case WINDOW_MAPGEN_PAGE_BASE: + return BaseMouseDown(widgetIndex, &widgets[widgetIndex]); + case WINDOW_MAPGEN_PAGE_SIMPLEX: + return SimplexMouseDown(widgetIndex, &widgets[widgetIndex]); + case WINDOW_MAPGEN_PAGE_HEIGHTMAP: + return HeightmapMouseDown(widgetIndex, &widgets[widgetIndex]); + } + } + + void OnDropdown(WidgetIndex widgetIndex, int32_t selectedIndex) override + { + switch (page) + { + case WINDOW_MAPGEN_PAGE_BASE: + return BaseDropdown(widgetIndex, selectedIndex); + case WINDOW_MAPGEN_PAGE_SIMPLEX: + return SimplexDropdown(widgetIndex, selectedIndex); + } + } + + void OnUpdate() override + { + switch (page) + { + case WINDOW_MAPGEN_PAGE_BASE: + return BaseUpdate(); + case WINDOW_MAPGEN_PAGE_RANDOM: + return RandomUpdate(); + case WINDOW_MAPGEN_PAGE_SIMPLEX: + return SimplexUpdate(); + } + } + + void OnPrepareDraw() override + { + switch (page) + { + case WINDOW_MAPGEN_PAGE_BASE: + return BasePrepareDraw(); + case WINDOW_MAPGEN_PAGE_RANDOM: + return RandomPrepareDraw(); + case WINDOW_MAPGEN_PAGE_SIMPLEX: + return SimplexPrepareDraw(); + case WINDOW_MAPGEN_PAGE_HEIGHTMAP: + return HeightmapPrepareDraw(); + } + } + + void OnDraw(DrawPixelInfo& dpi) override + { + switch (page) + { + case WINDOW_MAPGEN_PAGE_BASE: + return BaseDraw(dpi); + case WINDOW_MAPGEN_PAGE_RANDOM: + return RandomDraw(dpi); + case WINDOW_MAPGEN_PAGE_SIMPLEX: + return SimplexDraw(dpi); + case WINDOW_MAPGEN_PAGE_HEIGHTMAP: + return HeightmapDraw(dpi); + } + } + + void OnTextInput(WidgetIndex widgetIndex, std::string_view text) override + { + switch (page) + { + case WINDOW_MAPGEN_PAGE_BASE: + return TextInput(widgetIndex, text); + case WINDOW_MAPGEN_PAGE_SIMPLEX: + return TextInput(widgetIndex, text); + } + } + + void AfterLoadingHeightMap(int32_t result, const utf8* path) + { + if (result == MODAL_RESULT_OK) + { + if (!MapGenLoadHeightmap(path)) + { + // TODO: Display error popup + return; + } + + // The window needs to be open while using the map + _heightmapLoaded = true; + SetPage(WINDOW_MAPGEN_PAGE_HEIGHTMAP); + + HeightmapGenerateMap(); + } + } +}; + +WindowBase* WindowMapgenOpen() { - WindowMapgenDrawTabImage(dpi, w, WINDOW_MAPGEN_PAGE_BASE, SPR_G2_TAB_LAND); - WindowMapgenDrawTabImage(dpi, w, WINDOW_MAPGEN_PAGE_RANDOM, SPR_G2_TAB_TREE); - WindowMapgenDrawTabImage(dpi, w, WINDOW_MAPGEN_PAGE_SIMPLEX, SPR_G2_TAB_PENCIL); - WindowMapgenDrawTabImage(dpi, w, WINDOW_MAPGEN_PAGE_HEIGHTMAP, SPR_TAB_GRAPH_0); + return WindowFocusOrCreate(WindowClass::Mapgen, WW, WH, WF_10 | WF_AUTO_POSITION | WF_CENTRE_SCREEN); } -#pragma endregion +static void HeightmapLoadsaveCallback(int32_t result, const utf8* path) +{ + auto* w = static_cast(WindowMapgenOpen()); + w->AfterLoadingHeightMap(result, path); +}