316 lines
7.4 KiB
GDScript
316 lines
7.4 KiB
GDScript
tool
|
|
extends Container
|
|
|
|
|
|
onready var h_scroll_bar : HScrollBar = $HScrollBar
|
|
onready var v_scroll_bar : VScrollBar = $VScrollBar
|
|
|
|
|
|
export(Texture) var texture : Texture setget set_texture
|
|
export(int, 1, 8) var zoom := 1 setget set_zoom
|
|
export(Vector2) var offset := Vector2.ZERO setget set_offset
|
|
export(bool)var zoom_to_fit := true
|
|
|
|
|
|
var frames = []
|
|
var selected_frames := [] setget set_selected_frames
|
|
|
|
var frame_border_color := Color.red
|
|
var frame_border_visibility := true
|
|
|
|
var selection_border_color := Color.yellow
|
|
var selection_border_visibility := true
|
|
|
|
var border_width := 2
|
|
|
|
var texture_background_color := Color.green
|
|
var texture_background_visibility := true
|
|
|
|
var background_color := Color.blue
|
|
|
|
var _full_rect := Rect2(Vector2.ZERO, rect_size)
|
|
var _render_rect : Rect2
|
|
var _texture_size : Vector2
|
|
var _min_offset : Vector2
|
|
var _max_offset : Vector2
|
|
var _zoom_pivot : Vector2
|
|
|
|
var _updating_scroll_bars := false
|
|
var _panning := false
|
|
|
|
|
|
signal zoom_changed(new_zoom)
|
|
|
|
|
|
func _ready() -> void:
|
|
h_scroll_bar.value = .5
|
|
v_scroll_bar.value = .5
|
|
|
|
connect("resized", self, "_on_resized")
|
|
h_scroll_bar.connect("value_changed", self, "_on_HScrollBar_value_changed")
|
|
v_scroll_bar.connect("value_changed", self, "_on_VScrollBar_value_changed")
|
|
|
|
update()
|
|
|
|
|
|
func _draw() -> void:
|
|
draw_rect(_full_rect, background_color)
|
|
|
|
if not texture:
|
|
return
|
|
|
|
if texture_background_visibility:
|
|
draw_rect(_render_rect, texture_background_color)
|
|
|
|
draw_texture_rect(texture, _render_rect, false)
|
|
|
|
if frame_border_visibility:
|
|
for frame_idx in range(frames.size()):
|
|
if (not selection_border_visibility) or (not frame_idx in selected_frames):
|
|
_draw_frame_border(frame_idx)
|
|
|
|
if selection_border_visibility:
|
|
for frame_idx in selected_frames:
|
|
_draw_frame_border(frame_idx, true)
|
|
|
|
|
|
func _draw_frame_border(frame_idx : int, selected := false) -> void:
|
|
var sprite_region = frames[frame_idx].frame
|
|
|
|
var frame_rect := _render_rect
|
|
frame_rect.position += Vector2(sprite_region.x, sprite_region.y) * zoom
|
|
frame_rect.size = Vector2(sprite_region.w, sprite_region.h) * zoom
|
|
|
|
var border_color
|
|
|
|
if frame_idx in selected_frames:
|
|
border_color = selection_border_color
|
|
else:
|
|
border_color = frame_border_color
|
|
|
|
draw_rect(frame_rect, border_color, false, border_width)
|
|
|
|
|
|
func _gui_input(event: InputEvent) -> void:
|
|
if event is InputEventMouseButton:
|
|
match event.button_index:
|
|
BUTTON_MIDDLE:
|
|
_panning = event.pressed
|
|
|
|
if _panning:
|
|
mouse_default_cursor_shape = CURSOR_DRAG
|
|
else:
|
|
mouse_default_cursor_shape = CURSOR_ARROW
|
|
BUTTON_WHEEL_UP, BUTTON_WHEEL_DOWN:
|
|
if event.pressed:
|
|
_zoom_pivot = get_local_mouse_position()
|
|
|
|
if event.button_index == BUTTON_WHEEL_UP:
|
|
self.zoom += 1
|
|
else:
|
|
self.zoom -= 1
|
|
|
|
_zoom_pivot = _full_rect.size / 2
|
|
elif event is InputEventMouseMotion:
|
|
if _panning:
|
|
self.offset += event.relative
|
|
|
|
|
|
func load_settings(settings : Dictionary) -> void:
|
|
frame_border_color = settings.frame_border.color
|
|
frame_border_visibility = settings.frame_border.visibility
|
|
|
|
selection_border_color = settings.selection_border.color
|
|
selection_border_visibility = settings.selection_border.visibility
|
|
|
|
texture_background_color = settings.texture_background.color
|
|
texture_background_visibility = settings.texture_background.visibility
|
|
|
|
background_color = settings.inspector_background.color
|
|
|
|
update()
|
|
|
|
|
|
func _update_offset_limits() -> void:
|
|
var full_rect_width := _full_rect.size.x
|
|
var render_rect_width := _render_rect.size.x
|
|
|
|
if render_rect_width <= full_rect_width:
|
|
_min_offset.x = 0
|
|
_max_offset.x = full_rect_width - render_rect_width
|
|
else:
|
|
_min_offset.x = -(render_rect_width - full_rect_width)
|
|
_max_offset.x = 0
|
|
|
|
var full_rect_height := _full_rect.size.y
|
|
var render_rect_height := _render_rect.size.y
|
|
|
|
if render_rect_height <= full_rect_height:
|
|
_min_offset.y = 0
|
|
_max_offset.y = full_rect_height - render_rect_height
|
|
else:
|
|
_min_offset.y = -(render_rect_height - full_rect_height)
|
|
_max_offset.y = 0
|
|
|
|
|
|
func _update_scrollbars() ->void:
|
|
_updating_scroll_bars = true
|
|
|
|
if h_scroll_bar:
|
|
var full_width:= _full_rect.size.x
|
|
var render_width:= _render_rect.size.x
|
|
|
|
if render_width > full_width:
|
|
var h_page := full_width / render_width
|
|
|
|
h_scroll_bar.page = h_page
|
|
h_scroll_bar.max_value = 1 + h_page
|
|
|
|
var value := inverse_lerp(_max_offset.x, _min_offset.x, offset.x)
|
|
h_scroll_bar.value = value
|
|
|
|
h_scroll_bar.show()
|
|
else:
|
|
h_scroll_bar.hide()
|
|
|
|
if v_scroll_bar:
|
|
var full_height:= _full_rect.size.y
|
|
var render_height:= _render_rect.size.y
|
|
|
|
if render_height > full_height:
|
|
var v_page := full_height / render_height
|
|
|
|
v_scroll_bar.page = v_page
|
|
v_scroll_bar.max_value = 1 + v_page
|
|
|
|
var value := inverse_lerp(_max_offset.y, _min_offset.y, offset.y)
|
|
v_scroll_bar.value = value
|
|
|
|
v_scroll_bar.show()
|
|
else:
|
|
v_scroll_bar.hide()
|
|
|
|
_updating_scroll_bars = false
|
|
|
|
|
|
# Setters and Getters
|
|
func set_offset(new_offset : Vector2) -> void:
|
|
new_offset.x = clamp(new_offset.x, _min_offset.x, _max_offset.x)
|
|
new_offset.y = clamp(new_offset.y, _min_offset.y, _max_offset.y)
|
|
|
|
if new_offset == offset:
|
|
return
|
|
|
|
offset = new_offset
|
|
|
|
_render_rect.position = offset
|
|
|
|
if not _updating_scroll_bars:
|
|
_update_scrollbars()
|
|
|
|
update()
|
|
|
|
|
|
func set_selected_frames(selection : Array) -> void:
|
|
selected_frames = selection
|
|
|
|
update()
|
|
|
|
|
|
func set_texture(new_texture) -> void:
|
|
texture = new_texture
|
|
|
|
if texture == null:
|
|
return
|
|
|
|
_texture_size = texture.get_size()
|
|
var full_rect_size := _full_rect.size
|
|
|
|
if zoom_to_fit:
|
|
var ratio : Vector2
|
|
|
|
ratio.x = floor(full_rect_size.x / _texture_size.x)
|
|
ratio.y = floor(full_rect_size.y / _texture_size.y)
|
|
|
|
self.zoom = min(ratio.x, ratio.y)
|
|
else:
|
|
self.zoom = 1
|
|
|
|
_update_offset_limits()
|
|
|
|
self.offset = (_max_offset - _min_offset) / 2
|
|
|
|
|
|
func set_zoom(new_zoom : int) -> void:
|
|
zoom = clamp(new_zoom, 1, 8)
|
|
|
|
var new_render_rect_size := _texture_size * zoom
|
|
var relative_pivot := _zoom_pivot - offset
|
|
|
|
var pivot_weight : Vector2
|
|
|
|
if _render_rect.size.x and _render_rect.size.y:
|
|
pivot_weight.x = relative_pivot.x / _render_rect.size.x
|
|
pivot_weight.y = relative_pivot.y / _render_rect.size.y
|
|
|
|
var render_rect_size_diff := new_render_rect_size - _render_rect.size
|
|
var offset_diff := render_rect_size_diff * pivot_weight
|
|
|
|
_render_rect.size = new_render_rect_size
|
|
|
|
_update_offset_limits()
|
|
|
|
_update_scrollbars()
|
|
|
|
self.offset = offset - offset_diff
|
|
|
|
emit_signal("zoom_changed", zoom)
|
|
|
|
|
|
# Signal Callbacks
|
|
func _on_resized() -> void:
|
|
_full_rect.size = rect_size
|
|
|
|
_zoom_pivot = _full_rect.size / 2
|
|
|
|
_update_offset_limits()
|
|
|
|
_update_scrollbars()
|
|
|
|
self.offset = offset
|
|
|
|
var rect := Rect2()
|
|
|
|
rect.position.x = 0
|
|
rect.position.y = (rect_size.y - h_scroll_bar.rect_size.y)
|
|
rect.size.x = (rect_size.x - v_scroll_bar.rect_size.x)
|
|
rect.size.y = h_scroll_bar.rect_size.y
|
|
|
|
fit_child_in_rect(h_scroll_bar, rect)
|
|
|
|
rect.position.x = (rect_size.x - v_scroll_bar.rect_size.x)
|
|
rect.position.y = 0
|
|
rect.size.x = v_scroll_bar.rect_size.x
|
|
rect.size.y = (rect_size.y - h_scroll_bar.rect_size.y)
|
|
|
|
fit_child_in_rect(v_scroll_bar, rect)
|
|
|
|
|
|
|
|
func _on_HScrollBar_value_changed(value : float) -> void:
|
|
if _updating_scroll_bars:
|
|
return
|
|
|
|
_updating_scroll_bars = true
|
|
self.offset.x = lerp(_max_offset.x, _min_offset.x, value)
|
|
_updating_scroll_bars = false
|
|
|
|
|
|
func _on_VScrollBar_value_changed(value : float) -> void:
|
|
if _updating_scroll_bars:
|
|
return
|
|
|
|
_updating_scroll_bars = true
|
|
self.offset.y = lerp(_max_offset.y, _min_offset.y, value)
|
|
_updating_scroll_bars = false
|