GraphicsEditor/addons/Godoxel/Editor.gd

833 lines
23 KiB
GDScript

tool
extends Control
enum Tools {
PAINT,
BRUSH,
BUCKET,
RAINBOW,
LINE,
RECT,
DARKEN,
BRIGHTEN
COLORPICKER,
CUT,
PASTECUT,
}
# Keyboard shortcuts
const K_UNDO = KEY_Z
const K_REDO = KEY_Y
const K_PENCIL = KEY_Q
const K_BRUSH = KEY_W
const K_BUCKET = KEY_F
const K_RAINBOW = KEY_R
const K_LINE = KEY_L
const K_DARK = KEY_D
const K_BRIGHT = KEY_B
const K_CUT = KEY_C
const K_PICK = KEY_P
var layer_buttons: Control
var paint_canvas_container_node
var paint_canvas: GECanvas
var canvas_background: TextureRect
var grids_node
var colors_grid
var selected_color = Color(1, 1, 1, 1) setget set_selected_color
var util = preload("res://addons/Godoxel/Util.gd")
var textinfo
var allow_drawing = true
var mouse_in_region = false
var mouse_on_top = false
var _middle_mouse_pressed_pos = null
var _middle_mouse_pressed_start_pos = null
var _left_mouse_pressed_start_pos = Vector2()
var _previous_tool
var brush_mode
var _layer_button_ref = {}
var _total_added_layers = 1
var selected_brush_prefab = 0
var _last_drawn_pixel = Vector2.ZERO
var _last_preview_draw_cell_pos = Vector2.ZERO
var _selection_cells = []
var _selection_colors = []
var _cut_pos = Vector2.ZERO
var _cut_size = Vector2.ZERO
var _actions_history = [] # for undo
var _redo_history = []
var _current_action
var _last_mouse_pos_canvas_area = Vector2.ZERO
var _picked_color = false
var mouse_position = Vector2()
var canvas_position = Vector2()
var canvas_mouse_position = Vector2()
var cell_mouse_position = Vector2()
var cell_color = Color()
var last_mouse_position = Vector2()
var last_canvas_position = Vector2()
var last_canvas_mouse_position = Vector2()
var last_cell_mouse_position = Vector2()
var last_cell_color = Color()
const current_layer_highlight = Color(0.354706, 0.497302, 0.769531)
const other_layer_highlight = Color(0.180392, 0.176471, 0.176471)
const locked_layer_highlight = Color(0.098039, 0.094118, 0.094118)
var big_grid_pixels = 4 # 1 grid-box is big_grid_pixels big
func _ready():
#--------------------
#Setup nodes
#--------------------
paint_canvas_container_node = find_node("PaintCanvasContainer")
textinfo = find_node("DebugTextDisplay")
selected_color = find_node("ColorPicker").color
colors_grid = find_node("Colors")
paint_canvas = paint_canvas_container_node.find_node("Canvas")
layer_buttons = find_node("LayerButtons")
canvas_background = find_node("CanvasBackground")
set_process(true)
#--------------------
#connect nodes
#--------------------
if not colors_grid.is_connected("color_change_request", self, "change_color"):
colors_grid.connect("color_change_request", self, "change_color")
if not is_connected("visibility_changed", self, "_on_Editor_visibility_changed"):
connect("visibility_changed", self, "_on_Editor_visibility_changed")
find_node("CanvasBackground").material.set_shader_param(
"pixel_size", 8 * pow(0.5, big_grid_pixels)/paint_canvas.pixel_size)
# ready
set_brush(Tools.PAINT)
_layer_button_ref[layer_buttons.get_child(0).name] = layer_buttons.get_child(0) #ugly
_connect_layer_buttons()
highlight_layer(paint_canvas.get_active_layer().name)
find_node("BrushSizeLabel").text = str(int(find_node("BrushSize").value))
paint_canvas.update()
func _input(event):
if is_any_menu_open():
return
if not is_visible_in_tree():
return
if paint_canvas_container_node == null or paint_canvas == null:
return
if event is InputEventKey and event.is_pressed() and not event.is_echo():
_handle_shortcuts(event.scancode)
if is_mouse_in_canvas():
_handle_zoom(event)
if paint_canvas.is_active_layer_locked():
return
if brush_mode == Tools.CUT:
if event is InputEventMouseButton:
if event.button_index == BUTTON_LEFT:
if not event.pressed:
commit_action()
if (paint_canvas.mouse_in_region and paint_canvas.mouse_on_top):
if event is InputEventMouseButton:
match brush_mode:
Tools.BUCKET:
if event.button_index == BUTTON_LEFT:
if event.pressed:
if _current_action == null:
_current_action = get_action()
do_action([cell_mouse_position, last_cell_mouse_position, selected_color])
Tools.COLORPICKER:
if event.button_index == BUTTON_LEFT:
if event.pressed:
if paint_canvas.get_pixel(cell_mouse_position.x, cell_mouse_position.y).a == 0:
return
selected_color = paint_canvas.get_pixel(cell_mouse_position.x, cell_mouse_position.y)
_picked_color = true
find_node("Colors").add_color_prefab(selected_color)
elif _picked_color:
set_brush(_previous_tool)
elif event.button_index == BUTTON_RIGHT:
if event.pressed:
set_brush(_previous_tool)
Tools.PASTECUT:
if event.button_index == BUTTON_RIGHT:
if event.pressed:
commit_action()
set_brush(Tools.PAINT)
func _process(delta):
if not is_visible_in_tree():
return
if paint_canvas_container_node == null or paint_canvas == null:
return
if is_any_menu_open():
return
if is_mouse_in_canvas():
_handle_scroll()
#Update commonly used variables
var grid_size = paint_canvas.pixel_size
mouse_position = get_global_mouse_position() #paint_canvas.get_local_mouse_position()
canvas_position = paint_canvas.rect_global_position
canvas_mouse_position = Vector2(mouse_position.x - canvas_position.x, mouse_position.y - canvas_position.y)
if is_mouse_in_canvas():
cell_mouse_position = Vector2(
floor(canvas_mouse_position.x / grid_size),
floor(canvas_mouse_position.y / grid_size))
cell_color = paint_canvas.get_pixel(cell_mouse_position.x, cell_mouse_position.y)
update_text_info()
# if not is_mouse_in_canvas():
# paint_canvas.tool_layer.clear()
# paint_canvas.update()
# paint_canvas.tool_layer.update_texture()
# else:
if is_mouse_in_canvas():
if not paint_canvas.is_active_layer_locked():
if is_position_in_canvas(get_global_mouse_position()) or \
is_position_in_canvas(_last_mouse_pos_canvas_area):
brush_process()
else:
print(cell_mouse_position, " not in ", paint_canvas_container_node.rect_size)
print("not in canvas")
_draw_tool_brush()
#Update last variables with the current variables
last_mouse_position = mouse_position
last_canvas_position = canvas_position
last_canvas_mouse_position = canvas_mouse_position
last_cell_mouse_position = cell_mouse_position
last_cell_color = cell_color
_last_mouse_pos_canvas_area = get_global_mouse_position() #paint_canvas_container_node.get_local_mouse_position()
func _handle_shortcuts(scancode):
match scancode:
K_UNDO:
undo_action()
K_REDO:
redo_action()
K_PENCIL:
set_brush(Tools.PAINT)
K_BRUSH:
set_brush(Tools.BRUSH)
K_BUCKET:
set_brush(Tools.BUCKET)
K_RAINBOW:
set_brush(Tools.RAINBOW)
K_LINE:
set_brush(Tools.LINE)
K_DARK:
set_brush(Tools.DARKEN)
K_BRIGHT:
set_brush(Tools.BRIGHTEN)
K_CUT:
set_brush(Tools.CUT)
K_PICK:
set_brush(Tools.COLORPICKER)
func _draw_tool_brush():
paint_canvas.tool_layer.clear()
match brush_mode:
Tools.PASTECUT:
for idx in range(_selection_cells.size()):
var pixel = _selection_cells[idx]
# if pixel.x < 0 or pixel.y < 0:
# print(pixel)
var color = _selection_colors[idx]
pixel -= _cut_pos + _cut_size / 2
pixel += cell_mouse_position
paint_canvas._set_pixel_v(paint_canvas.tool_layer, pixel, color)
Tools.BRUSH:
var pixels = BrushPrefabs.get_brush(selected_brush_prefab, find_node("BrushSize").value)
for pixel in pixels:
paint_canvas._set_pixel(paint_canvas.tool_layer,
cell_mouse_position.x + pixel.x, cell_mouse_position.y + pixel.y, selected_color)
Tools.RAINBOW:
paint_canvas._set_pixel(paint_canvas.tool_layer,
cell_mouse_position.x, cell_mouse_position.y, Color(0.46875, 0.446777, 0.446777, 0.196078))
Tools.COLORPICKER:
paint_canvas._set_pixel(paint_canvas.tool_layer,
cell_mouse_position.x, cell_mouse_position.y, Color(0.866667, 0.847059, 0.847059, 0.196078))
_:
paint_canvas._set_pixel(paint_canvas.tool_layer,
cell_mouse_position.x, cell_mouse_position.y, selected_color)
paint_canvas.update()
#TODO add here brush prefab drawing
paint_canvas.tool_layer.update_texture()
func _handle_scroll():
if Input.is_mouse_button_pressed(BUTTON_MIDDLE):
if _middle_mouse_pressed_start_pos == null:
_middle_mouse_pressed_start_pos = paint_canvas.rect_position
_middle_mouse_pressed_pos = get_global_mouse_position()
paint_canvas.rect_position = _middle_mouse_pressed_start_pos
paint_canvas.rect_position += get_global_mouse_position() - _middle_mouse_pressed_pos
elif _middle_mouse_pressed_start_pos != null:
_middle_mouse_pressed_start_pos = null
const max_zoom_out = 1
const max_zoom_in = 50
func _handle_zoom(event):
if not event is InputEventMouseButton:
return
if event.is_pressed():
if event.button_index == BUTTON_WHEEL_UP:
var px = min(paint_canvas.pixel_size * 2, max_zoom_in)
if px == paint_canvas.pixel_size:
return
paint_canvas.set_pixel_size(px)
find_node("CanvasBackground").material.set_shader_param(
"pixel_size", 8 * pow(0.5, big_grid_pixels)/paint_canvas.pixel_size)
paint_canvas.rect_position -= paint_canvas.get_local_mouse_position()
paint_canvas.rect_position.x = clamp(paint_canvas.rect_position.x, -paint_canvas.rect_size.x * 0.8, rect_size.x)
paint_canvas.rect_position.y = clamp(paint_canvas.rect_position.y, -paint_canvas.rect_size.y * 0.8, rect_size.y)
elif event.button_index == BUTTON_WHEEL_DOWN:
var px = max(paint_canvas.pixel_size / 2.0, max_zoom_out)
if px == paint_canvas.pixel_size:
return
paint_canvas.set_pixel_size(px)
find_node("CanvasBackground").material.set_shader_param(
# 4 2 1
"pixel_size", 8 * pow(0.5, big_grid_pixels)/paint_canvas.pixel_size)
paint_canvas.rect_position += paint_canvas.get_local_mouse_position() / 2
paint_canvas.rect_position.x = clamp(paint_canvas.rect_position.x, -paint_canvas.rect_size.x * 0.8, rect_size.x)
paint_canvas.rect_position.y = clamp(paint_canvas.rect_position.y, -paint_canvas.rect_size.y * 0.8, rect_size.y)
func _handle_cut():
if Input.is_mouse_button_pressed(BUTTON_RIGHT):
paint_canvas.clear_preview_layer()
set_brush(_previous_tool)
return
if Input.is_mouse_button_pressed(BUTTON_LEFT):
for pixel_pos in GEUtils.get_pixels_in_line(cell_mouse_position, last_cell_mouse_position):
for idx in range(_selection_cells.size()):
var pixel = _selection_cells[idx]
var color = _selection_colors[idx]
pixel -= _cut_pos + _cut_size / 2
pixel += pixel_pos
paint_canvas.set_pixel_v(pixel, color)
else:
if _last_preview_draw_cell_pos == cell_mouse_position:
return
paint_canvas.clear_preview_layer()
for idx in range(_selection_cells.size()):
var pixel = _selection_cells[idx]
var color = _selection_colors[idx]
pixel -= _cut_pos + _cut_size / 2
pixel += cell_mouse_position
paint_canvas.set_preview_pixel_v(pixel, color)
_last_preview_draw_cell_pos = cell_mouse_position
func brush_process():
if Input.is_mouse_button_pressed(BUTTON_LEFT):
if _current_action == null:
_current_action = get_action()
if brush_mode == Tools.COLORPICKER:
_current_action = null
match brush_mode:
Tools.PAINT:
do_action([cell_mouse_position, last_cell_mouse_position, selected_color])
Tools.BRUSH:
do_action([cell_mouse_position, last_cell_mouse_position, selected_color,
selected_brush_prefab, find_node("BrushSize").value])
Tools.LINE:
do_action([cell_mouse_position, last_cell_mouse_position, selected_color])
Tools.RECT:
do_action([cell_mouse_position, last_cell_mouse_position, selected_color])
Tools.DARKEN:
do_action([cell_mouse_position, last_cell_mouse_position, selected_color])
Tools.BRIGHTEN:
do_action([cell_mouse_position, last_cell_mouse_position, selected_color])
Tools.COLORPICKER:
pass
Tools.CUT:
do_action([cell_mouse_position, last_cell_mouse_position, selected_color])
Tools.PASTECUT:
do_action([cell_mouse_position, last_cell_mouse_position,
_selection_cells, _selection_colors,
_cut_pos, _cut_size])
Tools.RAINBOW:
do_action([cell_mouse_position, last_cell_mouse_position])
paint_canvas.update()
elif Input.is_mouse_button_pressed(BUTTON_RIGHT):
paint_canvas.update()
if _current_action == null:
_current_action = get_action()
match brush_mode:
Tools.PAINT:
do_action([cell_mouse_position, last_cell_mouse_position, Color.transparent])
Tools.BRUSH:
do_action([cell_mouse_position, last_cell_mouse_position, Color.transparent,
selected_brush_prefab, find_node("BrushSize").value])
else:
if _current_action and _current_action.can_commit():
commit_action()
paint_canvas.update()
func update_text_info():
var text = ""
var cell_color_text = cell_color
cell_color_text = Color(0, 0, 0, 0)
text += \
str("FPS %s\t" + \
"Mouse Position %s\t" + \
"Canvas Mouse Position %s \t" + \
"Canvas Position %s\t\n" + \
"Cell Position %s \t" + \
"Cell Color %s\t") % [
str(Engine.get_frames_per_second()),
str(mouse_position),
str(canvas_mouse_position),
str(canvas_position),
str(cell_mouse_position),
str(cell_color_text),
]
find_node("DebugTextDisplay").display_text(text)
func _on_Save_pressed():
get_node("SaveFileDialog").show()
#---------------------------------------
# Actions
#---------------------------------------
func do_action(data: Array):
if _current_action == null:
#print("clear redo")
_redo_history.clear()
_current_action.do_action(paint_canvas, data)
func commit_action():
if not _current_action:
return
#print("commit action")
var commit_data = _current_action.commit_action(paint_canvas)
var action = get_action()
action.action_data = _current_action.action_data.duplicate(true)
_actions_history.push_back(action)
_redo_history.clear()
match brush_mode:
Tools.CUT:
_cut_pos = _current_action.mouse_start_pos
_cut_size = _current_action.mouse_end_pos - _current_action.mouse_start_pos
_selection_cells = _current_action.action_data.redo.cells.duplicate()
_selection_colors = _current_action.action_data.redo.colors.duplicate()
set_brush(Tools.PASTECUT)
_:
_current_action = null
func redo_action():
if _redo_history.empty():
print("nothing to redo")
return
var action = _redo_history.pop_back()
if not action:
return
_actions_history.append(action)
action.redo_action(paint_canvas)
paint_canvas.update()
#print("redo action")
func undo_action():
var action = _actions_history.pop_back()
if not action:
return
_redo_history.append(action)
action.undo_action(paint_canvas)
update()
paint_canvas.update()
#print("undo action")
func get_action():
match brush_mode:
Tools.PAINT:
return GEPencil.new()
Tools.BRUSH:
return GEBrush.new()
Tools.LINE:
return GELine.new()
Tools.RAINBOW:
return GERainbow.new()
Tools.BUCKET:
return GEBucket.new()
Tools.RECT:
return GERect.new()
Tools.DARKEN:
return GEDarken.new()
Tools.BRIGHTEN:
return GEBrighten.new()
Tools.CUT:
return GECut.new()
Tools.PASTECUT:
return GEPasteCut.new()
_:
#print("no tool!")
return null
############################################
# Brushes
############################################
func set_selected_color(color):
selected_color = color
func set_brush(new_mode):
if brush_mode == new_mode:
return
_previous_tool = brush_mode
brush_mode = new_mode
_current_action = get_action()
match _previous_tool:
Tools.CUT:
paint_canvas.clear_preview_layer()
Tools.PASTECUT:
_selection_cells.clear()
_selection_colors.clear()
Tools.BUCKET:
_current_action = null
#print("Selected: ", Tools.keys()[brush_mode])
func change_color(new_color):
if new_color.a == 0:
return
selected_color = new_color
find_node("ColorPicker").color = selected_color
func _on_ColorPicker_color_changed(color):
selected_color = color
func _on_PaintTool_pressed():
set_brush(Tools.PAINT)
func _on_BucketTool_pressed():
set_brush(Tools.BUCKET)
func _on_RainbowTool_pressed():
set_brush(Tools.RAINBOW)
func _on_BrushTool_pressed():
set_brush(Tools.BRUSH)
func _on_LineTool_pressed():
set_brush(Tools.LINE)
func _on_RectTool_pressed():
set_brush(Tools.RECT)
func _on_DarkenTool_pressed():
set_brush(Tools.DARKEN)
func _on_BrightenTool_pressed():
set_brush(Tools.BRIGHTEN)
func _on_ColorPickerTool_pressed():
set_brush(Tools.COLORPICKER)
func _on_CutTool_pressed():
set_brush(Tools.CUT)
func _on_Editor_visibility_changed():
pause_mode = not visible
############################################
# Layer
############################################
func highlight_layer(layer_name: String):
for button in layer_buttons.get_children():
if paint_canvas.find_layer_by_name(button.name).locked:
button.get("custom_styles/panel").set("bg_color", locked_layer_highlight)
elif button.name == layer_name:
button.get("custom_styles/panel").set("bg_color", current_layer_highlight)
else:
button.get("custom_styles/panel").set("bg_color", other_layer_highlight)
func toggle_layer_visibility(button, layer_name: String):
#print("toggling: ", layer_name)
paint_canvas.toggle_layer_visibility(layer_name)
func select_layer(layer_name: String):
#print("select layer: ", layer_name)
paint_canvas.select_layer(layer_name)
highlight_layer(layer_name)
func lock_layer(button, layer_name: String):
paint_canvas.toggle_lock_layer(layer_name)
highlight_layer(paint_canvas.get_active_layer().name)
func add_new_layer():
var new_layer_button = layer_buttons.get_child(0).duplicate()
new_layer_button.set("custom_styles/panel", layer_buttons.get_child(0).get("custom_styles/panel").duplicate())
layer_buttons.add_child_below_node(
layer_buttons.get_child(layer_buttons.get_child_count() - 1), new_layer_button, true)
_total_added_layers += 1
new_layer_button.find_node("Select").text = "Layer " + str(_total_added_layers)
_layer_button_ref[new_layer_button.name] = new_layer_button
_connect_layer_buttons()
var layer: GELayer = paint_canvas.add_new_layer(new_layer_button.name)
highlight_layer(paint_canvas.get_active_layer().name)
#print("added layer: ", layer.name)
return layer
func remove_active_layer():
if layer_buttons.get_child_count() <= 1:
return
var layer_name = paint_canvas.active_layer.name
paint_canvas.remove_layer(layer_name)
layer_buttons.remove_child(_layer_button_ref[layer_name])
_layer_button_ref[layer_name].queue_free()
_layer_button_ref.erase(layer_name)
highlight_layer(paint_canvas.get_active_layer().name)
func duplicate_active_layer():
var new_layer_button = layer_buttons.get_child(0).duplicate()
new_layer_button.set("custom_styles/panel", layer_buttons.get_child(0).get("custom_styles/panel").duplicate())
layer_buttons.add_child_below_node(
layer_buttons.get_child(layer_buttons.get_child_count() - 1), new_layer_button, true)
_total_added_layers += 1 # for keeping track...
new_layer_button.find_node("Select").text = "Layer " + str(_total_added_layers)
var new_layer = paint_canvas.duplicate_layer(paint_canvas.active_layer.name, new_layer_button.name)
new_layer.update_texture()
_layer_button_ref[new_layer.name] = new_layer_button
new_layer_button.find_node("Select").connect("pressed", self, "select_layer", [new_layer_button.name])
new_layer_button.find_node("Visible").connect("pressed", self, "toggle_layer_visibility",
[new_layer_button.find_node("Visible"), new_layer_button.name])
new_layer_button.find_node("Up").connect("pressed", self, "move_down", [new_layer_button])
new_layer_button.find_node("Down").connect("pressed", self, "move_up", [new_layer_button])
new_layer_button.find_node("Lock").connect("pressed", self, "lock_layer", [new_layer_button, new_layer_button.name])
# update highlight
highlight_layer(paint_canvas.get_active_layer().name)
#print("added layer: ", new_layer.name, " (total:", layer_buttons.get_child_count(), ")")
func move_up(layer_btn):
var new_idx = min(layer_btn.get_index() + 1, layer_buttons.get_child_count())
#print("move_up: ", layer_btn.name, " from ", layer_btn.get_index(), " to ", new_idx)
layer_buttons.move_child(layer_btn, new_idx)
paint_canvas.move_layer_back(layer_btn.name)
func move_down(layer_btn):
var new_idx = max(layer_btn.get_index() - 1, 0)
#print("move_down: ", layer_btn.name, " from ", layer_btn.get_index(), " to ", new_idx)
layer_buttons.move_child(layer_btn, new_idx)
paint_canvas.move_layer_forward(layer_btn.name)
func _connect_layer_buttons():
for layer_btn in layer_buttons.get_children():
if layer_btn.find_node("Select").is_connected("pressed", self, "select_layer"):
continue
layer_btn.find_node("Select").connect("pressed", self, "select_layer", [layer_btn.name])
layer_btn.find_node("Visible").connect("pressed", self, "toggle_layer_visibility",
[layer_btn.find_node("Visible"), layer_btn.name])
layer_btn.find_node("Up").connect("pressed", self, "move_down", [layer_btn])
layer_btn.find_node("Down").connect("pressed", self, "move_up", [layer_btn])
layer_btn.find_node("Lock").connect("pressed", self, "lock_layer",
[layer_btn, layer_btn.name])
func _on_Button_pressed():
add_new_layer()
func _on_PaintCanvasContainer_mouse_entered():
if mouse_on_top == true:
return
mouse_on_top = true
paint_canvas.tool_layer.clear()
paint_canvas.update()
paint_canvas.tool_layer.update_texture()
func _on_PaintCanvasContainer_mouse_exited():
if mouse_on_top == false:
return
mouse_on_top = false
paint_canvas.tool_layer.clear()
paint_canvas.update()
paint_canvas.tool_layer.update_texture()
func _on_ColorPicker_popup_closed():
find_node("Colors").add_color_prefab(find_node("ColorPicker").color)
############################################
# MISC
############################################
func is_position_in_canvas(pos):
if Rect2(paint_canvas_container_node.rect_global_position,
paint_canvas_container_node.rect_global_position + paint_canvas_container_node.rect_size).has_point(pos):
return true
return false
func is_mouse_in_canvas() -> bool:
if is_position_in_canvas(get_global_mouse_position()):
return true #mouse_on_top # check if mouse is inside canvas
else:
return false
func is_any_menu_open() -> bool:
return $ChangeCanvasSize.visible or \
$ChangeGridSizeDialog.visible or \
$Settings.visible or \
$LoadFileDialog.visible or \
$SaveFileDialog.visible or \
find_node("Navbar").is_any_menu_open()
func _on_LockAlpha_pressed():
var checked = find_node("LockAlpha").pressed
paint_canvas.active_layer.toggle_alpha_locked()
for i in range(find_node("Layer").get_popup().get_item_count()):
if find_node("Layer").get_popup().get_item_text(i) == "Toggle Alpha Locked":
find_node("Layer").get_popup().set_item_checked(i, not find_node("Layer").get_popup().is_item_checked(i))
func _on_BrushRect_pressed():
if brush_mode != Tools.BRUSH:
set_brush(Tools.BRUSH)
selected_brush_prefab = BrushPrefabs.Type.RECT
func _on_BrushCircle_pressed():
if brush_mode != Tools.BRUSH:
set_brush(Tools.BRUSH)
selected_brush_prefab = BrushPrefabs.Type.CIRCLE
func _on_BrushVLine_pressed():
if brush_mode != Tools.BRUSH:
set_brush(Tools.BRUSH)
selected_brush_prefab = BrushPrefabs.Type.V_LINE
func _on_BrushHLine_pressed():
if brush_mode != Tools.BRUSH:
set_brush(Tools.BRUSH)
selected_brush_prefab = BrushPrefabs.Type.H_LINE
func _on_BrushSize_value_changed(value: float):
find_node("BrushSizeLabel").text = str(int(value))
func _on_XSymmetry_pressed():
paint_canvas.symmetry_x = not paint_canvas.symmetry_x
func _on_YSymmetry_pressed():
paint_canvas.symmetry_y = not paint_canvas.symmetry_y