diff options
Diffstat (limited to 'addons/voxel-core/controls/tiles_viewer/tiles_viewer.gd')
-rw-r--r-- | addons/voxel-core/controls/tiles_viewer/tiles_viewer.gd | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/addons/voxel-core/controls/tiles_viewer/tiles_viewer.gd b/addons/voxel-core/controls/tiles_viewer/tiles_viewer.gd new file mode 100644 index 0000000..2bea836 --- /dev/null +++ b/addons/voxel-core/controls/tiles_viewer/tiles_viewer.gd @@ -0,0 +1,199 @@ +tool +extends TextureRect +# Shows tiles of VoxelSet and allows for the selection of Tile(s) + + + +## Signals +# Emitted when a uv position has been selected +signal selected_uv(uv) +# Emitted when a uv position has been unselected +signal unselected_uv(uv) + + + +## Exported Variables +# Maximum number of uv positions that can be selected at any one time +export(int, -1, 256) var selection_max := 0 setget set_selection_max + +# Color to applyed to border of hovered uv position(s) +export var hovered_color := Color(1, 1, 1, 0.6) setget set_hovered_color + +# Color to applyed to border of selected uv position(s) +export var selected_color := Color.white setget set_selection_color + +# Color to applyed to border of invalid uv position(s) +export var invalid_color := Color.red setget set_invalid_color + +# VoxelSet being used +export(Resource) var voxel_set = null setget set_voxel_set + + + +## Private Variables +# Stores last uv position hovered +var _last_uv_hovered := -Vector2.ONE + +# Selected uv positions +var _selections := [] + + + +## Built-In Virtual Methods +func _gui_input(event : InputEvent): + if event is InputEventMouse: + _last_uv_hovered = world_to_uv(event.position) + if selection_max != 0 and event is InputEventMouseButton: + if is_valid_uv(_last_uv_hovered) and event.button_index == BUTTON_LEFT and not event.is_pressed(): + if _selections.has(_last_uv_hovered): + unselect(_last_uv_hovered) + else: + select(_last_uv_hovered) + update() + + +func _draw(): + if is_instance_valid(voxel_set) and voxel_set.uv_ready(): + texture = voxel_set.tiles + if selection_max != 0: + for selection in _selections: + draw_rect(Rect2( + selection * voxel_set.tile_size, + voxel_set.tile_size), + selected_color, false, 3) + + if _last_uv_hovered == -Vector2.ONE: + hint_tooltip = "" + else: + hint_tooltip = str(_last_uv_hovered) + draw_rect(Rect2( + _last_uv_hovered * voxel_set.tile_size, + voxel_set.tile_size), + hovered_color if is_valid_uv(_last_uv_hovered) else invalid_color, + false, 3) + + + +## Public Methods +# Sets selection_max, shrinks _selections to new maximum if needed and calls on update by default +func set_selection_max(value : int, update := true) -> void: + selection_max = clamp(value, -1, 256) + unselect_shrink() + if update: + self.update() + + +# Sets hovered_color, and calls on update by default +func set_hovered_color(value : Color, update := true) -> void: + hovered_color = value + if update: + self.update() + + +# Sets selected_color, and calls on update by default +func set_selection_color(value : Color, update := true) -> void: + selected_color = value + if update: + self.update() + + +# Sets invalid_color, and calls on update by default +func set_invalid_color(value : Color, update := true) -> void: + invalid_color = value + if update: + self.update() + + +# Sets voxel_set, calls update_mesh if needed and not told otherwise +func set_voxel_set(value : Resource, update := true) -> void: + if not (typeof(value) == TYPE_NIL or value is VoxelSet): + printerr("Invalid Resource given expected VoxelSet") + return + + if is_instance_valid(voxel_set): + if voxel_set.is_connected("requested_refresh", self, "update"): + voxel_set.disconnect("requested_refresh", self, "update") + + voxel_set = value + if is_instance_valid(voxel_set): + if not voxel_set.is_connected("requested_refresh", self, "update"): + voxel_set.connect("requested_refresh", self, "update") + + if update: + self.update() + + +# Returns true if uv is selected +func has_selected(uv : Vector2) -> bool: + return _selections.has(uv) + + +# Returns uv selected at given index +func get_selected(index : int) -> Vector2: + return _selections[index] + + +# Returns array of selected faces +func get_selections() -> Array: + return _selections.duplicate() + + +# Returns number of faces selected +func get_selected_size() -> int: + return _selections.size() + + +# Returns world position as uv position +func world_to_uv(world : Vector2) -> Vector2: + return (world / voxel_set.tile_size).floor() if is_instance_valid(voxel_set) and voxel_set.uv_ready() else -Vector2.ONE + + +# Returns true if uv position is valid +func is_valid_uv(uv : Vector2) -> bool: + if is_instance_valid(voxel_set) and voxel_set.uv_ready(): + var bounds = voxel_set.tiles.get_size() / voxel_set.tile_size + return uv.x >= 0 and uv.y >= 0 and uv.x < bounds.x and uv.y < bounds.y + return false + + +# Returns true if world position is valid uv position +func is_valid_world(world : Vector2) -> bool: + return is_valid_uv(world_to_uv(world)) + + +# Selects given uv position, and emits selected_uv +func select(uv : Vector2, emit := true) -> void: + # TODO UV within bounds + if selection_max != 0: + unselect_shrink(selection_max - 1) + _selections.append(uv) + if emit: + emit_signal("selected_uv", uv) + + +# Unselects given uv position, and emits unselected_uv +func unselect(uv : Vector2, emit := true) -> void: + if _selections.has(uv): + _selections.erase(uv) + if emit: + emit_signal("unselected_uv", uv) + + +# Unselects all uv position +func unselect_all() -> void: + while not _selections.empty(): + unselect(_selections.back()) + + +# Unselects all uv position until given size is met +func unselect_shrink(size := selection_max, emit := true) -> void: + if size >= 0: + while _selections.size() > size: + unselect(_selections.back(), emit) + + + +## Private Methods +func _on_TilesViewer_mouse_exited(): + _last_uv_hovered = -Vector2.ONE + update() |