@tool class_name TerrainEditingControls extends VBoxContainer enum ToolMode { HEIGHT, FLATTEN, PAINT, ERASE } enum ToolShape { CORNER, CIRCLE, SQUARE } @onready var tool_mode_buttons : Array[Button] = [ $Height, $Flatten, $Paint, $Erase ] @onready var tool_shape_buttons : Array[Button] = [ $Corner, $Circle, $Square ] @onready var paint_texture_buttons : Array[Button] = [ $Grass, $Dirt, $Rock, $Sand ] @onready var draw_size_label : Label = $SizeLabel @onready var draw_size_slider : Slider = $SizeSlider @onready var raise_lower_toggle : Button = $RaiseLower @onready var connected_toggle : Button = $Connected @onready var corner_texture_default : Texture2D = preload("icons/corner.png") @onready var corner_texture_tile : Texture2D = preload("icons/corner_tile.png") ## Gets or sets the currently active tool mode. var tool_mode : ToolMode: get: return index_of_pressed(tool_mode_buttons) set(value): set_pressed(tool_mode_buttons, value); tool_mode_changed() ## Gets or sets the currently selected tool shape. var tool_shape : ToolShape: get: return index_of_pressed(tool_shape_buttons) set(value): set_pressed(tool_shape_buttons, value); tool_shape_changed() ## Gets or sets the currently selected texture to paint with. var texture : int: get: return index_of_pressed(paint_texture_buttons) + 1 set(value): set_pressed(paint_texture_buttons, value - 1) ## Gets or sets the current draw size for CIRCLE or SQUARE shapes. var draw_size : int: get: return roundi(-draw_size_slider.value) set(value): draw_size_slider.value = -value ## Gets whether the raise/lower button is currently active. var is_raise : bool: get: return raise_lower_toggle.button_pressed ## Gets whether the raise/lower button is currently active. var is_connected : bool: get: return connected_toggle.button_pressed func _ready() -> void: # Update 'tool_mode', 'tool_shape' or 'texture' when any of the buttons are pressed. for i in len(tool_mode_buttons ): tool_mode_buttons [i].pressed.connect(func(): tool_mode = i ) for i in len(tool_shape_buttons ): tool_shape_buttons [i].pressed.connect(func(): tool_shape = i ) for i in len(paint_texture_buttons): paint_texture_buttons[i].pressed.connect(func(): texture = i + 1) # Update 'draw_size_label' whenever the slider changes. draw_size_slider.value_changed.connect(func(_value): draw_size_label.text = str(draw_size)) func tool_mode_changed() -> void: var is_height := (tool_mode == ToolMode.HEIGHT) var is_flatten := (tool_mode == ToolMode.FLATTEN) var is_paint := (tool_mode == ToolMode.PAINT) var is_erase := (tool_mode == ToolMode.ERASE) # In 'PAINT' and 'ERASE' mode, 'CORNER' affects a single tile regardless of 'draw_size'. # This changes the button's icon to a small square to communicate that. tool_shape_buttons[0].icon = corner_texture_tile if is_paint or is_erase else corner_texture_default # Enable texture buttons only in 'PAINT' mode. for button in paint_texture_buttons: button.disabled = !is_paint # Enable raise/lower toggle only in 'HEIGHT' mode. raise_lower_toggle.disabled = !is_height # Enable connected toggle only in 'HEIGHT' or 'FLATTEN' mode. connected_toggle.disabled = !(is_height or is_flatten) func tool_shape_changed() -> void: var is_corner := (tool_shape == ToolShape.CORNER) draw_size_slider.editable = !is_corner; ## Returns the index of the first pressed (toggled on) button. func index_of_pressed(buttons: Array[Button]) -> int: for i in len(buttons): var button := buttons[i] if button.button_pressed: return i return 0 ## Sets the pressed state (toggled on) of the button ## with the specified index, unsetting all others. func set_pressed(buttons: Array[Button], value: int) -> void: for i in len(buttons): var button := buttons[i] var is_pressed := (value == i) button.button_pressed = is_pressed button.flat = !is_pressed