mirror of
https://github.com/tonytins/CozyPixelStudio.git
synced 2025-06-25 17:24:44 -04:00
Refactoring tools (#281)
* Refactoring tools * Remove unused code * Fixed some inferring errors and added translations * Attempt to fix some Script Errors found in the CI workflow * Fix bucket crash. * Fix static type convert. Co-authored-by: OverloadedOrama <35376950+OverloadedOrama@users.noreply.github.com>
This commit is contained in:
parent
e1724148fc
commit
4a668f71f5
42 changed files with 2489 additions and 2389 deletions
|
@ -1,336 +1,6 @@
|
|||
extends Node
|
||||
|
||||
|
||||
var drawer := Drawer.new()
|
||||
var mouse_press_pixels := [] # Cleared after mouse release
|
||||
var mouse_press_pressure_values := [] # Cleared after mouse release
|
||||
|
||||
|
||||
func reset() -> void:
|
||||
drawer.reset()
|
||||
mouse_press_pixels.clear()
|
||||
mouse_press_pressure_values.clear()
|
||||
|
||||
|
||||
func draw_pixel_blended(sprite : Image, pos : Vector2, color : Color, pen_pressure : float, current_mouse_button := -1, current_action := -1) -> void:
|
||||
var x_min = Global.current_project.x_min
|
||||
var x_max = Global.current_project.x_max
|
||||
var y_min = Global.current_project.y_min
|
||||
var y_max = Global.current_project.y_max
|
||||
|
||||
# Check if Tiling is enabled and whether mouse is in TilingPreviews
|
||||
if Global.tile_mode and point_in_rectangle(pos,Vector2( - Global.current_project.size.x - 1 , - Global.current_project.size.y -1 ), Vector2(2 * Global.current_project.size.x, 2 * Global.current_project.size.y)):
|
||||
pos = pos.posmodv(Global.current_project.size)
|
||||
|
||||
if !point_in_rectangle(pos, Vector2(x_min - 1, y_min - 1), Vector2(x_max, y_max)):
|
||||
return
|
||||
|
||||
var pos_floored := pos.floor()
|
||||
var current_pixel_color = sprite.get_pixelv(pos)
|
||||
var saved_pixel_index := mouse_press_pixels.find(pos_floored)
|
||||
if current_action == Global.Tools.PENCIL && color.a < 1:
|
||||
color = blend_colors(color, current_pixel_color)
|
||||
|
||||
if current_pixel_color != color && (saved_pixel_index == -1 || pen_pressure > mouse_press_pressure_values[saved_pixel_index]):
|
||||
if current_action == Global.Tools.LIGHTENDARKEN:
|
||||
var ld : int = Global.ld_modes[current_mouse_button]
|
||||
var ld_amount : float = Global.ld_amounts[current_mouse_button]
|
||||
if ld == Global.Lighten_Darken_Mode.LIGHTEN:
|
||||
color = current_pixel_color.lightened(ld_amount)
|
||||
else:
|
||||
color = current_pixel_color.darkened(ld_amount)
|
||||
|
||||
if saved_pixel_index == -1:
|
||||
mouse_press_pixels.append(pos_floored)
|
||||
mouse_press_pressure_values.append(pen_pressure)
|
||||
else:
|
||||
mouse_press_pressure_values[saved_pixel_index] = pen_pressure
|
||||
drawer.set_pixel(sprite, pos, color)
|
||||
|
||||
|
||||
func draw_brush(sprite : Image, pos : Vector2, color : Color, current_mouse_button : int, pen_pressure : float, current_action := -1) -> void:
|
||||
if Global.can_draw && Global.has_focus:
|
||||
var x_min = Global.current_project.x_min
|
||||
var x_max = Global.current_project.x_max
|
||||
var y_min = Global.current_project.y_min
|
||||
var y_max = Global.current_project.y_max
|
||||
|
||||
if Global.pressure_sensitivity_mode == Global.Pressure_Sensitivity.ALPHA:
|
||||
if current_action == Global.Tools.PENCIL:
|
||||
color.a *= pen_pressure
|
||||
elif current_action == Global.Tools.ERASER: # This is not working
|
||||
color.a *= (1.0 - pen_pressure)
|
||||
|
||||
var brush_size : int = Global.brush_sizes[current_mouse_button]
|
||||
var brush_type : int = Global.current_brush_types[current_mouse_button]
|
||||
|
||||
var horizontal_mirror : bool = Global.horizontal_mirror[current_mouse_button]
|
||||
var vertical_mirror : bool = Global.vertical_mirror[current_mouse_button]
|
||||
var pixel_perfect : bool = Global.pixel_perfect[current_mouse_button]
|
||||
|
||||
drawer.pixel_perfect = pixel_perfect if brush_size == 1 else false
|
||||
drawer.h_mirror = horizontal_mirror
|
||||
drawer.v_mirror = vertical_mirror
|
||||
|
||||
if brush_type == Global.Brush_Types.PIXEL || current_action == Global.Tools.LIGHTENDARKEN:
|
||||
var start_pos_x = floor(pos.x - (brush_size >> 1))
|
||||
var start_pos_y = floor(pos.y - (brush_size >> 1))
|
||||
var end_pos_x = floor(start_pos_x + brush_size)
|
||||
var end_pos_y = floor(start_pos_y + brush_size)
|
||||
|
||||
for cur_pos_x in range(start_pos_x, end_pos_x):
|
||||
for cur_pos_y in range(start_pos_y, end_pos_y):
|
||||
draw_pixel_blended(sprite, Vector2(cur_pos_x, cur_pos_y), color, pen_pressure, current_mouse_button, current_action)
|
||||
Global.canvas.sprite_changed_this_frame = true
|
||||
|
||||
elif brush_type == Global.Brush_Types.CIRCLE || brush_type == Global.Brush_Types.FILLED_CIRCLE:
|
||||
plot_circle(sprite, pos.x, pos.y, brush_size, color, pen_pressure, brush_type == Global.Brush_Types.FILLED_CIRCLE)
|
||||
Global.canvas.sprite_changed_this_frame = true
|
||||
|
||||
else:
|
||||
var brush_index : int = Global.custom_brush_indexes[current_mouse_button]
|
||||
var custom_brush_image : Image
|
||||
if brush_type != Global.Brush_Types.RANDOM_FILE:
|
||||
custom_brush_image = Global.brush_images[current_mouse_button]
|
||||
else: # Handle random brush
|
||||
var brush_button = Global.file_brush_container.get_child(brush_index + 3)
|
||||
var random_index = randi() % brush_button.random_brushes.size()
|
||||
custom_brush_image = Image.new()
|
||||
custom_brush_image.copy_from(brush_button.random_brushes[random_index])
|
||||
var custom_brush_size = custom_brush_image.get_size()
|
||||
custom_brush_image.resize(custom_brush_size.x * brush_size, custom_brush_size.y * brush_size, Image.INTERPOLATE_NEAREST)
|
||||
custom_brush_image = Global.blend_image_with_color(custom_brush_image, color, Global.interpolate_spinboxes[current_mouse_button].value / 100)
|
||||
custom_brush_image.lock()
|
||||
|
||||
var custom_brush_size := custom_brush_image.get_size() - Vector2.ONE
|
||||
pos = pos.floor()
|
||||
# #Check if Tiling is enabled and whether mouse is in TilingPreviews
|
||||
if Global.tile_mode and point_in_rectangle(pos,Vector2( - Global.current_project.size.x - 1 , - Global.current_project.size.y -1 ), Vector2(2 * Global.current_project.size.x, 2 * Global.current_project.size.y)):
|
||||
pos = pos.posmodv(Global.current_project.size)
|
||||
|
||||
var dst := rectangle_center(pos, custom_brush_size)
|
||||
var src_rect := Rect2(Vector2.ZERO, custom_brush_size + Vector2.ONE)
|
||||
# Rectangle with the same size as the brush, but at cursor's position
|
||||
var pos_rect := Rect2(dst, custom_brush_size + Vector2.ONE)
|
||||
|
||||
# The selection rectangle
|
||||
# If there's no rectangle, the whole canvas is considered a selection
|
||||
var selection_rect := Rect2()
|
||||
selection_rect.position = Vector2(x_min, y_min)
|
||||
selection_rect.end = Vector2(x_max, y_max)
|
||||
# Intersection of the position rectangle and selection
|
||||
var pos_rect_clipped := pos_rect.clip(selection_rect)
|
||||
# If the size is 0, that means that the brush wasn't positioned inside the selection
|
||||
if pos_rect_clipped.size == Vector2.ZERO:
|
||||
return
|
||||
|
||||
# Re-position src_rect and dst based on the clipped position
|
||||
var pos_difference := (pos_rect.position - pos_rect_clipped.position).abs()
|
||||
# Obviously, if pos_rect and pos_rect_clipped are the same, pos_difference is Vector2.ZERO
|
||||
src_rect.position = pos_difference
|
||||
dst += pos_difference
|
||||
src_rect.end -= pos_rect.end - pos_rect_clipped.end
|
||||
# If the selection rectangle is smaller than the brush, ...
|
||||
# ... make sure pixels aren't being drawn outside the selection by adjusting src_rect's size
|
||||
src_rect.size.x = min(src_rect.size.x, selection_rect.size.x)
|
||||
src_rect.size.y = min(src_rect.size.y, selection_rect.size.y)
|
||||
|
||||
# Handle mirroring
|
||||
var mirror_x = x_max + x_min - pos.x - (pos.x - dst.x)
|
||||
var mirror_y = y_max + y_min - pos.y - (pos.y - dst.y)
|
||||
if int(pos_rect_clipped.size.x) % 2 != 0:
|
||||
mirror_x -= 1
|
||||
if int(pos_rect_clipped.size.y) % 2 != 0:
|
||||
mirror_y -= 1
|
||||
# Use custom blend function cause of godot's issue #31124
|
||||
if color.a > 0: # If it's the pencil
|
||||
sprite.blend_rect(custom_brush_image, src_rect, dst)
|
||||
if horizontal_mirror:
|
||||
sprite.blend_rect(custom_brush_image, src_rect, Vector2(mirror_x, dst.y))
|
||||
if vertical_mirror:
|
||||
sprite.blend_rect(custom_brush_image, src_rect, Vector2(dst.x, mirror_y))
|
||||
if horizontal_mirror && vertical_mirror:
|
||||
sprite.blend_rect(custom_brush_image, src_rect, Vector2(mirror_x, mirror_y))
|
||||
|
||||
else: # if it's transparent - if it's the eraser
|
||||
var custom_brush := Image.new()
|
||||
if brush_type == Global.Brush_Types.CUSTOM:
|
||||
custom_brush.copy_from(Global.current_project.brushes[brush_index])
|
||||
else:
|
||||
custom_brush.copy_from(Global.file_brushes[brush_index])
|
||||
custom_brush_size = custom_brush.get_size()
|
||||
custom_brush.resize(custom_brush_size.x * brush_size, custom_brush_size.y * brush_size, Image.INTERPOLATE_NEAREST)
|
||||
var custom_brush_blended = Global.blend_image_with_color(custom_brush, color, 1)
|
||||
|
||||
sprite.blit_rect_mask(custom_brush_blended, custom_brush, src_rect, dst)
|
||||
if horizontal_mirror:
|
||||
sprite.blit_rect_mask(custom_brush_blended, custom_brush, src_rect, Vector2(mirror_x, dst.y))
|
||||
if vertical_mirror:
|
||||
sprite.blit_rect_mask(custom_brush_blended, custom_brush, src_rect, Vector2(dst.x, mirror_y))
|
||||
if horizontal_mirror && vertical_mirror:
|
||||
sprite.blit_rect_mask(custom_brush_blended, custom_brush, src_rect, Vector2(mirror_x, mirror_y))
|
||||
|
||||
sprite.lock()
|
||||
Global.canvas.sprite_changed_this_frame = true
|
||||
|
||||
Global.canvas.previous_mouse_pos_for_lines = pos.floor() + Vector2(0.5, 0.5)
|
||||
Global.canvas.previous_mouse_pos_for_lines.x = clamp(Global.canvas.previous_mouse_pos_for_lines.x, Global.canvas.location.x, Global.canvas.location.x + Global.current_project.size.x)
|
||||
Global.canvas.previous_mouse_pos_for_lines.y = clamp(Global.canvas.previous_mouse_pos_for_lines.y, Global.canvas.location.y, Global.canvas.location.y + Global.current_project.size.y)
|
||||
if Global.canvas.is_making_line:
|
||||
Global.canvas.line_pos[0] = Global.canvas.previous_mouse_pos_for_lines
|
||||
|
||||
|
||||
# Bresenham's Algorithm
|
||||
# Thanks to https://godotengine.org/qa/35276/tile-based-line-drawing-algorithm-efficiency
|
||||
func fill_gaps(sprite : Image, end_pos : Vector2, start_pos : Vector2, color : Color, current_mouse_button : int, pen_pressure : float, current_action := -1) -> void:
|
||||
var previous_mouse_pos_floored = start_pos.floor()
|
||||
var mouse_pos_floored = end_pos.floor()
|
||||
var dx := int(abs(mouse_pos_floored.x - previous_mouse_pos_floored.x))
|
||||
var dy := int(-abs(mouse_pos_floored.y - previous_mouse_pos_floored.y))
|
||||
var err := dx + dy
|
||||
var e2 := err << 1 # err * 2
|
||||
var sx = 1 if previous_mouse_pos_floored.x < mouse_pos_floored.x else -1
|
||||
var sy = 1 if previous_mouse_pos_floored.y < mouse_pos_floored.y else -1
|
||||
var x = previous_mouse_pos_floored.x
|
||||
var y = previous_mouse_pos_floored.y
|
||||
while !(x == mouse_pos_floored.x && y == mouse_pos_floored.y):
|
||||
draw_brush(sprite, Vector2(x, y), color, current_mouse_button, pen_pressure, current_action)
|
||||
e2 = err << 1
|
||||
if e2 >= dy:
|
||||
err += dy
|
||||
x += sx
|
||||
if e2 <= dx:
|
||||
err += dx
|
||||
y += sy
|
||||
|
||||
|
||||
# Algorithm based on http://members.chello.at/easyfilter/bresenham.html
|
||||
func plot_circle(sprite : Image, xm : int, ym : int, r : int, color : Color, pen_pressure : float, fill := false) -> void:
|
||||
var radius := r # Used later for filling
|
||||
var x := -r
|
||||
var y := 0
|
||||
var err := 2 - r * 2 # II. Quadrant
|
||||
while x < 0:
|
||||
var quadrant_1 := Vector2(xm - x, ym + y)
|
||||
var quadrant_2 := Vector2(xm - y, ym - x)
|
||||
var quadrant_3 := Vector2(xm + x, ym - y)
|
||||
var quadrant_4 := Vector2(xm + y, ym + x)
|
||||
draw_pixel_blended(sprite, quadrant_1, color, pen_pressure)
|
||||
draw_pixel_blended(sprite, quadrant_2, color, pen_pressure)
|
||||
draw_pixel_blended(sprite, quadrant_3, color, pen_pressure)
|
||||
draw_pixel_blended(sprite, quadrant_4, color, pen_pressure)
|
||||
|
||||
r = err
|
||||
if r <= y:
|
||||
y += 1
|
||||
err += y * 2 + 1
|
||||
if r > x || err > y:
|
||||
x += 1
|
||||
err += x * 2 + 1
|
||||
|
||||
if fill:
|
||||
for j in range (-radius, radius + 1):
|
||||
for i in range (-radius, radius + 1):
|
||||
if i * i + j * j <= radius * radius:
|
||||
var draw_pos := Vector2(i + xm, j + ym)
|
||||
draw_pixel_blended(sprite, draw_pos, color, Global.canvas.pen_pressure)
|
||||
|
||||
|
||||
# Thanks to https://en.wikipedia.org/wiki/Flood_fill
|
||||
func flood_fill(sprite : Image, pos : Vector2, target_color : Color, replace_color : Color) -> void:
|
||||
var x_min = Global.current_project.x_min
|
||||
var x_max = Global.current_project.x_max
|
||||
var y_min = Global.current_project.y_min
|
||||
var y_max = Global.current_project.y_max
|
||||
pos = pos.floor()
|
||||
var pixel = sprite.get_pixelv(pos)
|
||||
if target_color == replace_color:
|
||||
return
|
||||
elif pixel != target_color:
|
||||
return
|
||||
else:
|
||||
|
||||
if !point_in_rectangle(pos, Vector2(x_min - 1, y_min - 1), Vector2(x_max, y_max)):
|
||||
return
|
||||
|
||||
var q = [pos]
|
||||
for n in q:
|
||||
# If the difference in colors is very small, break the loop (thanks @azagaya on GitHub!)
|
||||
if target_color == replace_color:
|
||||
break
|
||||
var west : Vector2 = n
|
||||
var east : Vector2 = n
|
||||
while west.x >= x_min && sprite.get_pixelv(west) == target_color:
|
||||
west += Vector2.LEFT
|
||||
while east.x < x_max && sprite.get_pixelv(east) == target_color:
|
||||
east += Vector2.RIGHT
|
||||
for px in range(west.x + 1, east.x):
|
||||
var p := Vector2(px, n.y)
|
||||
# Draw
|
||||
sprite.set_pixelv(p, replace_color)
|
||||
replace_color = sprite.get_pixelv(p)
|
||||
var north := p + Vector2.UP
|
||||
var south := p + Vector2.DOWN
|
||||
if north.y >= y_min && sprite.get_pixelv(north) == target_color:
|
||||
q.append(north)
|
||||
if south.y < y_max && sprite.get_pixelv(south) == target_color:
|
||||
q.append(south)
|
||||
|
||||
Global.canvas.sprite_changed_this_frame = true
|
||||
|
||||
|
||||
func pattern_fill(sprite : Image, pos : Vector2, pattern : Image, target_color : Color, var offset : Vector2) -> void:
|
||||
var x_min = Global.current_project.x_min
|
||||
var x_max = Global.current_project.x_max
|
||||
var y_min = Global.current_project.y_min
|
||||
var y_max = Global.current_project.y_max
|
||||
pos = pos.floor()
|
||||
if !point_in_rectangle(pos, Vector2(x_min - 1, y_min - 1), Vector2(x_max, y_max)):
|
||||
return
|
||||
|
||||
pattern.lock()
|
||||
var pattern_size := pattern.get_size()
|
||||
var q = [pos]
|
||||
|
||||
for n in q:
|
||||
var west : Vector2 = n
|
||||
var east : Vector2 = n
|
||||
while west.x >= x_min && sprite.get_pixelv(west) == target_color:
|
||||
west += Vector2.LEFT
|
||||
while east.x < x_max && sprite.get_pixelv(east) == target_color:
|
||||
east += Vector2.RIGHT
|
||||
|
||||
for px in range(west.x + 1, east.x):
|
||||
var p := Vector2(px, n.y)
|
||||
var xx : int = int(px + offset.x) % int(pattern_size.x)
|
||||
var yy : int = int(n.y + offset.y) % int(pattern_size.y)
|
||||
var pattern_color : Color = pattern.get_pixel(xx, yy)
|
||||
if pattern_color == target_color:
|
||||
continue
|
||||
sprite.set_pixelv(p, pattern_color)
|
||||
|
||||
var north := p + Vector2.UP
|
||||
var south := p + Vector2.DOWN
|
||||
if north.y >= y_min && sprite.get_pixelv(north) == target_color:
|
||||
q.append(north)
|
||||
if south.y < y_max && sprite.get_pixelv(south) == target_color:
|
||||
q.append(south)
|
||||
|
||||
pattern.unlock()
|
||||
Global.canvas.sprite_changed_this_frame = true
|
||||
|
||||
|
||||
func blend_colors(color_1 : Color, color_2 : Color) -> Color:
|
||||
var color := Color()
|
||||
color.a = color_1.a + color_2.a * (1 - color_1.a) # Blend alpha
|
||||
if color.a != 0:
|
||||
# Blend colors
|
||||
color.r = (color_1.r * color_1.a + color_2.r * color_2.a * (1-color_1.a)) / color.a
|
||||
color.g = (color_1.g * color_1.a + color_2.g * color_2.a * (1-color_1.a)) / color.a
|
||||
color.b = (color_1.b * color_1.a + color_2.b * color_2.a * (1-color_1.a)) / color.a
|
||||
return color
|
||||
|
||||
|
||||
func scale3X(sprite : Image, tol : float = 50) -> Image:
|
||||
var scaled = Image.new()
|
||||
scaled.create(sprite.get_width()*3, sprite.get_height()*3, false, Image.FORMAT_RGBA8)
|
||||
|
@ -829,13 +499,3 @@ func adjust_hsv(img: Image, id : int, delta : float) -> void:
|
|||
img.set_pixel(i,j,c)
|
||||
|
||||
img.unlock()
|
||||
|
||||
|
||||
# Checks if a point is inside a rectangle
|
||||
func point_in_rectangle(p : Vector2, coord1 : Vector2, coord2 : Vector2) -> bool:
|
||||
return p.x > coord1.x && p.y > coord1.y && p.x < coord2.x && p.y < coord2.y
|
||||
|
||||
|
||||
# Returns the position in the middle of a rectangle
|
||||
func rectangle_center(rect_position : Vector2, rect_size : Vector2) -> Vector2:
|
||||
return (rect_position - rect_size / 2).floor()
|
||||
|
|
|
@ -3,15 +3,8 @@ extends Node
|
|||
|
||||
enum Grid_Types {CARTESIAN, ISOMETRIC, ALL}
|
||||
enum Pressure_Sensitivity {NONE, ALPHA, SIZE, ALPHA_AND_SIZE}
|
||||
enum Brush_Types {PIXEL, CIRCLE, FILLED_CIRCLE, FILE, RANDOM_FILE, CUSTOM}
|
||||
enum Direction {UP, DOWN, LEFT, RIGHT}
|
||||
enum Mouse_Button {LEFT, RIGHT}
|
||||
enum Tools {PENCIL, ERASER, BUCKET, LIGHTENDARKEN, RECTSELECT, COLORPICKER, ZOOM}
|
||||
enum Theme_Types {DARK, BLUE, CARAMEL, LIGHT}
|
||||
enum Fill_Area {SAME_COLOR_AREA, SAME_COLOR_PIXELS}
|
||||
enum Fill_With {COLOR, PATTERN}
|
||||
enum Lighten_Darken_Mode {LIGHTEN, DARKEN}
|
||||
enum Zoom_Mode {ZOOM_IN, ZOOM_OUT}
|
||||
|
||||
# Stuff for arrowkey-based canvas movements nyaa ^.^
|
||||
const low_speed_move_rate := 150.0
|
||||
|
@ -44,8 +37,8 @@ var pressure_sensitivity_mode = Pressure_Sensitivity.NONE
|
|||
var open_last_project := false
|
||||
var smooth_zoom := true
|
||||
var cursor_image = preload("res://assets/graphics/cursor_icons/cursor.png")
|
||||
var left_cursor_tool_texture : ImageTexture
|
||||
var right_cursor_tool_texture : ImageTexture
|
||||
var left_cursor_tool_texture := ImageTexture.new()
|
||||
var right_cursor_tool_texture := ImageTexture.new()
|
||||
|
||||
var image_clipboard : Image
|
||||
var play_only_tags := true
|
||||
|
@ -68,27 +61,11 @@ var autosave_interval := 5.0
|
|||
var enable_autosave := true
|
||||
|
||||
# Tools & options
|
||||
var current_tools := [Tools.PENCIL, Tools.ERASER]
|
||||
var show_left_tool_icon := true
|
||||
var show_right_tool_icon := true
|
||||
var left_square_indicator_visible := true
|
||||
var right_square_indicator_visible := false
|
||||
|
||||
var fill_areas := [Fill_Area.SAME_COLOR_AREA, Fill_Area.SAME_COLOR_AREA]
|
||||
var fill_with := [Fill_With.COLOR, Fill_With.COLOR]
|
||||
var fill_pattern_offsets := [Vector2.ZERO, Vector2.ZERO]
|
||||
|
||||
var ld_modes := [Lighten_Darken_Mode.LIGHTEN, Lighten_Darken_Mode.LIGHTEN]
|
||||
var ld_amounts := [0.1, 0.1]
|
||||
|
||||
var color_picker_for := [Mouse_Button.LEFT, Mouse_Button.RIGHT]
|
||||
|
||||
var zoom_modes := [Zoom_Mode.ZOOM_IN, Zoom_Mode.ZOOM_OUT]
|
||||
|
||||
var horizontal_mirror := [false, false]
|
||||
var vertical_mirror := [false, false]
|
||||
var pixel_perfect := [false, false]
|
||||
|
||||
# View menu options
|
||||
var tile_mode := false
|
||||
var draw_grid := false
|
||||
|
@ -102,25 +79,6 @@ var onion_skinning_past_rate := 1.0
|
|||
var onion_skinning_future_rate := 1.0
|
||||
var onion_skinning_blue_red := false
|
||||
|
||||
# Brushes
|
||||
var file_brushes := []
|
||||
var brush_sizes := [1, 1]
|
||||
var current_brush_types := [Brush_Types.PIXEL, Brush_Types.PIXEL]
|
||||
var brush_images := [Image.new(), Image.new()]
|
||||
var brush_textures := [ImageTexture.new(), ImageTexture.new()]
|
||||
|
||||
var brush_type_window_position : int = Mouse_Button.LEFT
|
||||
var left_circle_points := []
|
||||
var right_circle_points := []
|
||||
|
||||
var brushes_from_files := 0
|
||||
var custom_brush_indexes := [-1, -1]
|
||||
|
||||
# Patterns
|
||||
var patterns := []
|
||||
var pattern_window_position : int = Mouse_Button.LEFT
|
||||
var pattern_images := [Image.new(), Image.new()]
|
||||
|
||||
# Palettes
|
||||
var palettes := {}
|
||||
|
||||
|
@ -158,41 +116,11 @@ var export_dialog : AcceptDialog
|
|||
var preferences_dialog : AcceptDialog
|
||||
var unsaved_changes_dialog : ConfirmationDialog
|
||||
|
||||
var color_pickers := []
|
||||
|
||||
var color_switch_button : BaseButton
|
||||
|
||||
var tool_options_containers := []
|
||||
|
||||
var brush_type_containers := []
|
||||
var brush_type_buttons := []
|
||||
var brushes_popup : Popup
|
||||
var file_brush_container : GridContainer
|
||||
var project_brush_container : GridContainer
|
||||
var patterns_popup : Popup
|
||||
|
||||
var brush_size_edits := []
|
||||
var brush_size_sliders := []
|
||||
|
||||
var pixel_perfect_containers := []
|
||||
|
||||
var color_interpolation_containers := []
|
||||
var interpolate_spinboxes := []
|
||||
var interpolate_sliders := []
|
||||
|
||||
var fill_area_containers := []
|
||||
var fill_pattern_containers := []
|
||||
|
||||
var ld_containers := []
|
||||
var ld_amount_sliders := []
|
||||
var ld_amount_spinboxes := []
|
||||
|
||||
var colorpicker_containers := []
|
||||
|
||||
var zoom_containers := []
|
||||
|
||||
var mirror_containers := []
|
||||
|
||||
var animation_timeline : Panel
|
||||
|
||||
var animation_timer : Timer
|
||||
|
@ -251,21 +179,6 @@ func _ready() -> void:
|
|||
right_cursor = find_node_by_name(root, "RightCursor")
|
||||
canvas = find_node_by_name(root, "Canvas")
|
||||
|
||||
var pencil_cursor_image = preload("res://assets/graphics/cursor_icons/pencil_cursor.png")
|
||||
var eraser_cursor_image = preload("res://assets/graphics/cursor_icons/eraser_cursor.png")
|
||||
|
||||
left_cursor_tool_texture = ImageTexture.new()
|
||||
if pencil_cursor_image is Image:
|
||||
left_cursor_tool_texture.create_from_image(pencil_cursor_image)
|
||||
elif pencil_cursor_image is ImageTexture:
|
||||
left_cursor_tool_texture.create_from_image(pencil_cursor_image.get_data())
|
||||
|
||||
right_cursor_tool_texture = ImageTexture.new()
|
||||
if eraser_cursor_image is Image:
|
||||
right_cursor_tool_texture.create_from_image(eraser_cursor_image)
|
||||
elif eraser_cursor_image is ImageTexture:
|
||||
right_cursor_tool_texture.create_from_image(eraser_cursor_image.get_data())
|
||||
|
||||
tabs = find_node_by_name(root, "Tabs")
|
||||
main_viewport = find_node_by_name(root, "ViewportContainer")
|
||||
second_viewport = find_node_by_name(root, "ViewportContainer2")
|
||||
|
@ -294,58 +207,11 @@ func _ready() -> void:
|
|||
preferences_dialog = find_node_by_name(root, "PreferencesDialog")
|
||||
unsaved_changes_dialog = find_node_by_name(root, "UnsavedCanvasDialog")
|
||||
|
||||
tool_options_containers.append(find_node_by_name(root, "LeftToolOptions"))
|
||||
tool_options_containers.append(find_node_by_name(root, "RightToolOptions"))
|
||||
|
||||
color_pickers.append(find_node_by_name(root, "LeftColorPickerButton"))
|
||||
color_pickers.append(find_node_by_name(root, "RightColorPickerButton"))
|
||||
color_switch_button = find_node_by_name(root, "ColorSwitch")
|
||||
|
||||
brush_type_containers.append(find_node_by_name(tool_options_containers[0], "LeftBrushType"))
|
||||
brush_type_containers.append(find_node_by_name(tool_options_containers[1], "RightBrushType"))
|
||||
brush_type_buttons.append(find_node_by_name(brush_type_containers[0], "LeftBrushTypeButton"))
|
||||
brush_type_buttons.append(find_node_by_name(brush_type_containers[1], "RightBrushTypeButton"))
|
||||
brushes_popup = find_node_by_name(root, "BrushesPopup")
|
||||
file_brush_container = find_node_by_name(brushes_popup, "FileBrushContainer")
|
||||
project_brush_container = find_node_by_name(brushes_popup, "ProjectBrushContainer")
|
||||
patterns_popup = find_node_by_name(root, "PatternsPopup")
|
||||
|
||||
brush_size_edits.append(find_node_by_name(root, "LeftBrushSizeEdit"))
|
||||
brush_size_sliders.append(find_node_by_name(root, "LeftBrushSizeSlider"))
|
||||
brush_size_edits.append(find_node_by_name(root, "RightBrushSizeEdit"))
|
||||
brush_size_sliders.append(find_node_by_name(root, "RightBrushSizeSlider"))
|
||||
|
||||
pixel_perfect_containers.append(find_node_by_name(root, "LeftBrushPixelPerfectMode"))
|
||||
pixel_perfect_containers.append(find_node_by_name(root, "RightBrushPixelPerfectMode"))
|
||||
|
||||
color_interpolation_containers.append(find_node_by_name(root, "LeftColorInterpolation"))
|
||||
color_interpolation_containers.append(find_node_by_name(root, "RightColorInterpolation"))
|
||||
interpolate_spinboxes.append(find_node_by_name(root, "LeftInterpolateFactor"))
|
||||
interpolate_sliders.append(find_node_by_name(root, "LeftInterpolateSlider"))
|
||||
interpolate_spinboxes.append(find_node_by_name(root, "RightInterpolateFactor"))
|
||||
interpolate_sliders.append(find_node_by_name(root, "RightInterpolateSlider"))
|
||||
|
||||
fill_area_containers.append(find_node_by_name(root, "LeftFillArea"))
|
||||
fill_pattern_containers.append(find_node_by_name(root, "LeftFillPattern"))
|
||||
fill_area_containers.append(find_node_by_name(root, "RightFillArea"))
|
||||
fill_pattern_containers.append(find_node_by_name(root, "RightFillPattern"))
|
||||
|
||||
ld_containers.append(find_node_by_name(root, "LeftLDOptions"))
|
||||
ld_amount_sliders.append(find_node_by_name(root, "LeftLDAmountSlider"))
|
||||
ld_amount_spinboxes.append(find_node_by_name(root, "LeftLDAmountSpinbox"))
|
||||
ld_containers.append(find_node_by_name(root, "RightLDOptions"))
|
||||
ld_amount_sliders.append(find_node_by_name(root, "RightLDAmountSlider"))
|
||||
ld_amount_spinboxes.append(find_node_by_name(root, "RightLDAmountSpinbox"))
|
||||
|
||||
colorpicker_containers.append(find_node_by_name(root, "LeftColorPickerOptions"))
|
||||
colorpicker_containers.append(find_node_by_name(root, "RightColorPickerOptions"))
|
||||
|
||||
zoom_containers.append(find_node_by_name(root, "LeftZoomOptions"))
|
||||
zoom_containers.append(find_node_by_name(root, "RightZoomOptions"))
|
||||
|
||||
mirror_containers.append(find_node_by_name(root, "LeftMirrorButtons"))
|
||||
mirror_containers.append(find_node_by_name(root, "RightMirrorButtons"))
|
||||
|
||||
animation_timeline = find_node_by_name(root, "AnimationTimeline")
|
||||
|
||||
layers_container = find_node_by_name(animation_timeline, "LayersContainer")
|
||||
|
@ -605,143 +471,6 @@ Hold %s to make a line""") % [InputMap.get_action_list("left_eraser_tool")[0].as
|
|||
(%s)""") % InputMap.get_action_list("go_to_last_frame")[0].as_text()
|
||||
|
||||
|
||||
func create_brush_button(brush_img : Image, brush_type := Brush_Types.CUSTOM, hint_tooltip := "") -> void:
|
||||
var brush_container
|
||||
var brush_button = load("res://src/UI/BrushButton.tscn").instance()
|
||||
brush_button.brush_type = brush_type
|
||||
if brush_type == Brush_Types.FILE || brush_type == Brush_Types.RANDOM_FILE:
|
||||
brush_button.custom_brush_index = file_brushes.size() - 1
|
||||
brush_container = file_brush_container
|
||||
else:
|
||||
brush_button.custom_brush_index = current_project.brushes.size() - 1
|
||||
brush_container = project_brush_container
|
||||
var brush_tex := ImageTexture.new()
|
||||
brush_tex.create_from_image(brush_img, 0)
|
||||
brush_button.get_child(0).texture = brush_tex
|
||||
brush_button.hint_tooltip = hint_tooltip
|
||||
brush_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||
if brush_type == Brush_Types.RANDOM_FILE:
|
||||
brush_button.random_brushes.append(brush_img)
|
||||
brush_container.add_child(brush_button)
|
||||
|
||||
|
||||
func create_pattern_button(image : Image, hint_tooltip := "") -> void:
|
||||
var pattern_button : BaseButton = load("res://src/UI/PatternButton.tscn").instance()
|
||||
pattern_button.image = image
|
||||
var pattern_tex := ImageTexture.new()
|
||||
pattern_tex.create_from_image(image, 0)
|
||||
pattern_button.get_child(0).texture = pattern_tex
|
||||
pattern_button.hint_tooltip = hint_tooltip
|
||||
pattern_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||
patterns_popup.get_node("ScrollContainer/PatternContainer").add_child(pattern_button)
|
||||
|
||||
|
||||
func remove_brush_buttons() -> void:
|
||||
current_brush_types[0] = Brush_Types.PIXEL
|
||||
current_brush_types[1] = Brush_Types.PIXEL
|
||||
for child in project_brush_container.get_children():
|
||||
child.queue_free()
|
||||
|
||||
|
||||
func undo_custom_brush(_brush_button : BaseButton = null) -> void:
|
||||
general_undo()
|
||||
var action_name : String = current_project.undo_redo.get_current_action_name()
|
||||
if action_name == "Delete Custom Brush":
|
||||
project_brush_container.add_child(_brush_button)
|
||||
project_brush_container.move_child(_brush_button, _brush_button.custom_brush_index)
|
||||
_brush_button.get_node("DeleteButton").visible = false
|
||||
|
||||
|
||||
func redo_custom_brush(_brush_button : BaseButton = null) -> void:
|
||||
general_redo()
|
||||
var action_name : String = current_project.undo_redo.get_current_action_name()
|
||||
if action_name == "Delete Custom Brush":
|
||||
project_brush_container.remove_child(_brush_button)
|
||||
|
||||
|
||||
func update_custom_brush(mouse_button : int) -> void:
|
||||
var brush_type : int = current_brush_types[mouse_button]
|
||||
if brush_type == Brush_Types.PIXEL:
|
||||
var pixel = preload("res://assets/graphics/pixel_image.png")
|
||||
if pixel is Image:
|
||||
brush_type_buttons[mouse_button].get_child(0).texture.create_from_image(pixel, 0)
|
||||
elif pixel is ImageTexture:
|
||||
brush_type_buttons[mouse_button].get_child(0).texture.create_from_image(pixel.get_data(), 0)
|
||||
elif brush_type == Brush_Types.CIRCLE:
|
||||
var pixel = preload("res://assets/graphics/circle_9x9.png")
|
||||
if pixel is Image:
|
||||
brush_type_buttons[mouse_button].get_child(0).texture.create_from_image(pixel, 0)
|
||||
elif pixel is ImageTexture:
|
||||
brush_type_buttons[mouse_button].get_child(0).texture.create_from_image(pixel.get_data(), 0)
|
||||
|
||||
left_circle_points = plot_circle(brush_sizes[0])
|
||||
right_circle_points = plot_circle(brush_sizes[1])
|
||||
elif brush_type == Brush_Types.FILLED_CIRCLE:
|
||||
var pixel = preload("res://assets/graphics/circle_filled_9x9.png")
|
||||
if pixel is Image:
|
||||
brush_type_buttons[mouse_button].get_child(0).texture.create_from_image(pixel, 0)
|
||||
elif pixel is ImageTexture:
|
||||
brush_type_buttons[mouse_button].get_child(0).texture.create_from_image(pixel.get_data(), 0)
|
||||
|
||||
left_circle_points = plot_circle(brush_sizes[0])
|
||||
right_circle_points = plot_circle(brush_sizes[1])
|
||||
else:
|
||||
var custom_brush := Image.new()
|
||||
if brush_type == Brush_Types.FILE or brush_type == Brush_Types.RANDOM_FILE:
|
||||
custom_brush.copy_from(file_brushes[custom_brush_indexes[mouse_button]])
|
||||
else:
|
||||
custom_brush.copy_from(current_project.brushes[custom_brush_indexes[mouse_button]])
|
||||
var custom_brush_size = custom_brush.get_size()
|
||||
custom_brush.resize(custom_brush_size.x * brush_sizes[mouse_button], custom_brush_size.y * brush_sizes[mouse_button], Image.INTERPOLATE_NEAREST)
|
||||
brush_images[mouse_button] = blend_image_with_color(custom_brush, color_pickers[mouse_button].color, interpolate_spinboxes[mouse_button].value / 100)
|
||||
brush_textures[mouse_button].create_from_image(brush_images[mouse_button], 0)
|
||||
|
||||
brush_type_buttons[mouse_button].get_child(0).texture = brush_textures[mouse_button]
|
||||
|
||||
|
||||
func blend_image_with_color(image : Image, color : Color, interpolate_factor : float) -> Image:
|
||||
var blended_image := Image.new()
|
||||
blended_image.copy_from(image)
|
||||
var size := image.get_size()
|
||||
blended_image.lock()
|
||||
for xx in size.x:
|
||||
for yy in size.y:
|
||||
if color.a > 0: # If it's the pencil
|
||||
var current_color := blended_image.get_pixel(xx, yy)
|
||||
if current_color.a > 0:
|
||||
var new_color := current_color.linear_interpolate(color, interpolate_factor)
|
||||
new_color.a = current_color.a
|
||||
blended_image.set_pixel(xx, yy, new_color)
|
||||
else: # If color is transparent - if it's the eraser
|
||||
blended_image.set_pixel(xx, yy, Color(0, 0, 0, 0))
|
||||
return blended_image
|
||||
|
||||
|
||||
# Algorithm based on http://members.chello.at/easyfilter/bresenham.html
|
||||
# This is not used for drawing, rather for finding the points required
|
||||
# for the mouse cursor/position indicator
|
||||
func plot_circle(r : int) -> Array:
|
||||
var circle_points := []
|
||||
var xm := 0
|
||||
var ym := 0
|
||||
var x := -r
|
||||
var y := 0
|
||||
var err := 2 - r * 2
|
||||
while x < 0:
|
||||
circle_points.append(Vector2(xm - x, ym + y))
|
||||
circle_points.append(Vector2(xm - y, ym - x))
|
||||
circle_points.append(Vector2(xm + x, ym - y))
|
||||
circle_points.append(Vector2(xm + y, ym + x))
|
||||
r = err
|
||||
if r <= y:
|
||||
y += 1
|
||||
err += y * 2 + 1
|
||||
if r > x || err > y:
|
||||
x += 1
|
||||
err += x * 2 + 1
|
||||
return circle_points
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
config_cache.set_value("window", "screen", OS.current_screen)
|
||||
config_cache.set_value("window", "maximized", OS.window_maximized || OS.window_fullscreen)
|
||||
|
|
|
@ -105,18 +105,7 @@ func add_randomised_brush(fpaths : Array, tooltip_name : String) -> void:
|
|||
|
||||
if len(loaded_images) > 0: # actually have images
|
||||
# to use.
|
||||
# take initial image...
|
||||
var first_image : Image = loaded_images.pop_front()
|
||||
|
||||
# The index which this random brush will be at
|
||||
var next_random_brush_index : int = Global.file_brush_container.get_child_count()
|
||||
|
||||
Global.file_brushes.append(first_image)
|
||||
Global.create_brush_button(first_image, Global.Brush_Types.RANDOM_FILE, tooltip_name)
|
||||
# # Process the rest
|
||||
for remaining_image in loaded_images:
|
||||
var brush_button = Global.file_brush_container.get_child(next_random_brush_index)
|
||||
brush_button.random_brushes.append(remaining_image)
|
||||
Brushes.add_file_brush(loaded_images, tooltip_name)
|
||||
|
||||
# Add a plain brush from the given path to the list of brushes.
|
||||
# Taken, again, from find_brushes
|
||||
|
@ -127,8 +116,7 @@ func add_plain_brush(path: String, tooltip_name: String) -> void:
|
|||
return
|
||||
# do the standard conversion thing...
|
||||
image.convert(Image.FORMAT_RGBA8)
|
||||
Global.file_brushes.append(image)
|
||||
Global.create_brush_button(image, Global.Brush_Types.FILE, tooltip_name)
|
||||
Brushes.add_file_brush([image], tooltip_name)
|
||||
|
||||
|
||||
# Import brushes, in priority order, from the paths in question in priority order
|
||||
|
@ -214,8 +202,6 @@ func import_brushes(priority_ordered_search_path: Array) -> void:
|
|||
# Mark this as a processed relpath
|
||||
processed_subdir_paths[nonrandomised_subdir][relative_path] = true
|
||||
|
||||
Global.brushes_from_files = Global.file_brushes.size()
|
||||
|
||||
|
||||
func import_patterns(priority_ordered_search_path: Array) -> void:
|
||||
for path in priority_ordered_search_path:
|
||||
|
@ -235,25 +221,7 @@ func import_patterns(priority_ordered_search_path: Array) -> void:
|
|||
var err := image.load(path.plus_file(pattern))
|
||||
if err == OK:
|
||||
image.convert(Image.FORMAT_RGBA8)
|
||||
Global.patterns.append(image)
|
||||
Global.create_pattern_button(image, pattern)
|
||||
|
||||
if Global.patterns.size() > 0:
|
||||
var image_size = Global.patterns[0].get_size()
|
||||
|
||||
Global.pattern_images[0] = Global.patterns[0]
|
||||
var pattern_left_tex := ImageTexture.new()
|
||||
pattern_left_tex.create_from_image(Global.pattern_images[0], 0)
|
||||
Global.fill_pattern_containers[0].get_child(0).get_child(0).texture = pattern_left_tex
|
||||
Global.fill_pattern_containers[0].get_child(2).get_child(1).max_value = image_size.x - 1
|
||||
Global.fill_pattern_containers[0].get_child(3).get_child(1).max_value = image_size.y - 1
|
||||
|
||||
Global.pattern_images[1] = Global.patterns[0]
|
||||
var pattern_right_tex := ImageTexture.new()
|
||||
pattern_right_tex.create_from_image(Global.pattern_images[1], 0)
|
||||
Global.fill_pattern_containers[1].get_child(0).get_child(0).texture = pattern_right_tex
|
||||
Global.fill_pattern_containers[1].get_child(2).get_child(1).max_value = image_size.x - 1
|
||||
Global.fill_pattern_containers[1].get_child(3).get_child(1).max_value = image_size.y - 1
|
||||
Global.patterns_popup.add(image)
|
||||
|
||||
|
||||
func import_gpl(path : String, text : String) -> Palette:
|
||||
|
|
|
@ -93,7 +93,7 @@ func open_pxo_file(path : String, untitled_backup : bool = false) -> void:
|
|||
var image := Image.new()
|
||||
image.create_from_data(b_width, b_height, false, Image.FORMAT_RGBA8, buffer)
|
||||
new_project.brushes.append(image)
|
||||
Global.create_brush_button(image)
|
||||
Brushes.add_project_brush(image)
|
||||
|
||||
file.close()
|
||||
if !empty_project:
|
||||
|
@ -232,19 +232,13 @@ func open_old_pxo_file(file : File, new_project : Project, first_line : String)
|
|||
guide_line = file.get_line()
|
||||
|
||||
# Load tool options
|
||||
Global.color_pickers[0].color = file.get_var()
|
||||
Global.color_pickers[1].color = file.get_var()
|
||||
Global.brush_sizes[0] = file.get_8()
|
||||
Global.brush_size_edits[0].value = Global.brush_sizes[0]
|
||||
Global.brush_sizes[1] = file.get_8()
|
||||
Global.brush_size_edits[1].value = Global.brush_sizes[1]
|
||||
file.get_var()
|
||||
file.get_var()
|
||||
file.get_8()
|
||||
file.get_8()
|
||||
if file_major_version == 0 and file_minor_version < 7:
|
||||
var left_palette = file.get_var()
|
||||
var right_palette = file.get_var()
|
||||
for color in left_palette:
|
||||
Global.color_pickers[0].get_picker().add_preset(color)
|
||||
for color in right_palette:
|
||||
Global.color_pickers[1].get_picker().add_preset(color)
|
||||
file.get_var()
|
||||
file.get_var()
|
||||
|
||||
# Load custom brushes
|
||||
var brush_line := file.get_line()
|
||||
|
@ -255,7 +249,7 @@ func open_old_pxo_file(file : File, new_project : Project, first_line : String)
|
|||
var image := Image.new()
|
||||
image.create_from_data(b_width, b_height, false, Image.FORMAT_RGBA8, buffer)
|
||||
new_project.brushes.append(image)
|
||||
Global.create_brush_button(image)
|
||||
Brushes.add_project_brush(image)
|
||||
brush_line = file.get_line()
|
||||
|
||||
if file_major_version >= 0 and file_minor_version > 6:
|
||||
|
|
201
src/Autoload/Tools.gd
Normal file
201
src/Autoload/Tools.gd
Normal file
|
@ -0,0 +1,201 @@
|
|||
extends Node
|
||||
|
||||
|
||||
class Slot:
|
||||
|
||||
var name : String
|
||||
var kname : String
|
||||
var tool_node : Node = null
|
||||
var button : int
|
||||
var color : Color
|
||||
|
||||
var pixel_perfect := false
|
||||
var horizontal_mirror := false
|
||||
var vertical_mirror := false
|
||||
|
||||
|
||||
func _init(slot_name : String) -> void:
|
||||
name = slot_name
|
||||
kname = name.replace(" ", "_").to_lower()
|
||||
load_config()
|
||||
|
||||
|
||||
func save_config() -> void:
|
||||
var config := {
|
||||
"pixel_perfect" : pixel_perfect,
|
||||
"horizontal_mirror" : horizontal_mirror,
|
||||
"vertical_mirror" : vertical_mirror,
|
||||
}
|
||||
Global.config_cache.set_value(kname, "slot", config)
|
||||
|
||||
|
||||
func load_config() -> void:
|
||||
var config = Global.config_cache.get_value(kname, "slot", {})
|
||||
pixel_perfect = config.get("pixel_perfect", pixel_perfect)
|
||||
horizontal_mirror = config.get("horizontal_mirror", horizontal_mirror)
|
||||
vertical_mirror = config.get("vertical_mirror", vertical_mirror)
|
||||
|
||||
|
||||
signal color_changed(color, button)
|
||||
|
||||
var _tools = {
|
||||
"RectSelect" : "res://src/Tools/RectSelect.tscn",
|
||||
"Zoom" : "res://src/Tools/Zoom.tscn",
|
||||
"ColorPicker" : "res://src/Tools/ColorPicker.tscn",
|
||||
"Pencil" : "res://src/Tools/Pencil.tscn",
|
||||
"Eraser" : "res://src/Tools/Eraser.tscn",
|
||||
"Bucket" : "res://src/Tools/Bucket.tscn",
|
||||
"LightenDarken" : "res://src/Tools/LightenDarken.tscn",
|
||||
}
|
||||
var _slots = {}
|
||||
var _panels = {}
|
||||
var _tool_buttons : Node
|
||||
var _active_button := -1
|
||||
var _last_position := Vector2.INF
|
||||
|
||||
var pen_pressure := 1.0
|
||||
var control := false
|
||||
var shift := false
|
||||
var alt := false
|
||||
|
||||
|
||||
func _ready():
|
||||
yield(get_tree(), "idle_frame")
|
||||
_slots[BUTTON_LEFT] = Slot.new("Left tool")
|
||||
_slots[BUTTON_RIGHT] = Slot.new("Right tool")
|
||||
_panels[BUTTON_LEFT] = Global.find_node_by_name(Global.control, "LeftPanelContainer")
|
||||
_panels[BUTTON_RIGHT] = Global.find_node_by_name(Global.control, "RightPanelContainer")
|
||||
_tool_buttons = Global.find_node_by_name(Global.control, "ToolButtons")
|
||||
|
||||
var value = Global.config_cache.get_value(_slots[BUTTON_LEFT].kname, "tool", "Pencil")
|
||||
set_tool(value, BUTTON_LEFT)
|
||||
value = Global.config_cache.get_value(_slots[BUTTON_RIGHT].kname, "tool", "Eraser")
|
||||
set_tool(value, BUTTON_RIGHT)
|
||||
value = Global.config_cache.get_value(_slots[BUTTON_LEFT].kname, "color", Color.black)
|
||||
assign_color(value, BUTTON_LEFT)
|
||||
value = Global.config_cache.get_value(_slots[BUTTON_RIGHT].kname, "color", Color.white)
|
||||
assign_color(value, BUTTON_RIGHT)
|
||||
|
||||
update_tool_buttons()
|
||||
update_tool_cursors()
|
||||
|
||||
|
||||
func set_tool(name : String, button : int) -> void:
|
||||
var slot = _slots[button]
|
||||
var panel : Node = _panels[button]
|
||||
var node : Node = load(_tools[name]).instance()
|
||||
node.name = name
|
||||
node.tool_slot = slot
|
||||
slot.tool_node = node
|
||||
slot.button = button
|
||||
panel.add_child(slot.tool_node)
|
||||
|
||||
|
||||
func assign_tool(name : String, button : int) -> void:
|
||||
var slot = _slots[button]
|
||||
var panel : Node = _panels[button]
|
||||
|
||||
if slot.tool_node != null:
|
||||
if slot.tool_node.name == name:
|
||||
return
|
||||
panel.remove_child(slot.tool_node)
|
||||
slot.tool_node.queue_free()
|
||||
|
||||
set_tool(name, button)
|
||||
update_tool_buttons()
|
||||
update_tool_cursors()
|
||||
Global.config_cache.set_value(slot.kname, "tool", name)
|
||||
|
||||
|
||||
func default_color() -> void:
|
||||
assign_color(Color.black, BUTTON_LEFT)
|
||||
assign_color(Color.white, BUTTON_RIGHT)
|
||||
|
||||
|
||||
func swap_color() -> void:
|
||||
var left = _slots[BUTTON_LEFT].color
|
||||
var right = _slots[BUTTON_RIGHT].color
|
||||
assign_color(right, BUTTON_LEFT)
|
||||
assign_color(left, BUTTON_RIGHT)
|
||||
|
||||
|
||||
func assign_color(color : Color, button : int) -> void:
|
||||
var c : Color = _slots[button].color
|
||||
if color.a == 0:
|
||||
if color.r != c.r or color.g != c.g or color.b != c.b:
|
||||
color.a = 1
|
||||
_slots[button].color = color
|
||||
Global.config_cache.set_value(_slots[button].kname, "color", color)
|
||||
emit_signal("color_changed", color, button)
|
||||
|
||||
|
||||
func get_assigned_color(button : int) -> Color:
|
||||
return _slots[button].color
|
||||
|
||||
|
||||
func update_tool_buttons() -> void:
|
||||
for child in _tool_buttons.get_children():
|
||||
var texture : TextureRect = child.get_child(0)
|
||||
var filename = child.name.to_lower()
|
||||
if _slots[BUTTON_LEFT].tool_node.name == child.name:
|
||||
filename += "_l"
|
||||
if _slots[BUTTON_RIGHT].tool_node.name == child.name:
|
||||
filename += "_r"
|
||||
filename += ".png"
|
||||
Global.change_button_texturerect(texture, filename)
|
||||
|
||||
|
||||
func update_tool_cursors() -> void:
|
||||
var image = "res://assets/graphics/cursor_icons/%s_cursor.png" % _slots[BUTTON_LEFT].tool_node.name.to_lower()
|
||||
Global.left_cursor_tool_texture.create_from_image(load(image), 0)
|
||||
image = "res://assets/graphics/cursor_icons/%s_cursor.png" % _slots[BUTTON_RIGHT].tool_node.name.to_lower()
|
||||
Global.right_cursor_tool_texture.create_from_image(load(image), 0)
|
||||
|
||||
|
||||
func draw_indicator() -> void:
|
||||
if Global.left_square_indicator_visible:
|
||||
_slots[BUTTON_LEFT].tool_node.draw_indicator()
|
||||
if Global.right_square_indicator_visible:
|
||||
_slots[BUTTON_RIGHT].tool_node.draw_indicator()
|
||||
|
||||
|
||||
func handle_draw(position : Vector2, event : InputEvent) -> void:
|
||||
if not (Global.can_draw and Global.has_focus):
|
||||
return
|
||||
|
||||
if event is InputEventWithModifiers:
|
||||
control = event.control
|
||||
shift = event.shift
|
||||
alt = event.alt
|
||||
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index in [BUTTON_LEFT, BUTTON_RIGHT]:
|
||||
if event.pressed and _active_button == -1:
|
||||
_active_button = event.button_index
|
||||
_slots[_active_button].tool_node.draw_start(position)
|
||||
elif not event.pressed and event.button_index == _active_button:
|
||||
_slots[_active_button].tool_node.draw_end(position)
|
||||
_active_button = -1
|
||||
|
||||
if event is InputEventMouseMotion:
|
||||
if Engine.get_version_info().major == 3 && Engine.get_version_info().minor >= 2:
|
||||
pen_pressure = event.pressure
|
||||
if Global.pressure_sensitivity_mode == Global.Pressure_Sensitivity.NONE:
|
||||
pen_pressure = 1.0
|
||||
|
||||
if not position.is_equal_approx(_last_position):
|
||||
_last_position = position
|
||||
_slots[BUTTON_LEFT].tool_node.cursor_move(position)
|
||||
_slots[BUTTON_RIGHT].tool_node.cursor_move(position)
|
||||
if _active_button != -1:
|
||||
_slots[_active_button].tool_node.draw_move(position)
|
||||
|
||||
var project : Project = Global.current_project
|
||||
var text := "[%s×%s]" % [project.size.x, project.size.y]
|
||||
if Global.has_focus:
|
||||
text += " %s, %s" % [position.x, position.y]
|
||||
if not _slots[BUTTON_LEFT].tool_node.cursor_text.empty():
|
||||
text += " %s" % _slots[BUTTON_LEFT].tool_node.cursor_text
|
||||
if not _slots[BUTTON_RIGHT].tool_node.cursor_text.empty():
|
||||
text += " %s" % _slots[BUTTON_RIGHT].tool_node.cursor_text
|
||||
Global.cursor_position_label.text = text
|
Loading…
Add table
Add a link
Reference in a new issue