mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-18 17:19:50 +00:00
Paint selection brush (#792)
* Added the PaintSelect tool The shortcut keys are not configured * Some Optimization attempts * remove typo * Re-Designed Tool Icon
This commit is contained in:
parent
6148791069
commit
1df003b2df
BIN
assets/graphics/tools/cursors/paintselect.png
Normal file
BIN
assets/graphics/tools/cursors/paintselect.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 261 B |
BIN
assets/graphics/tools/paintselect.png
Normal file
BIN
assets/graphics/tools/paintselect.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 225 B |
|
@ -51,6 +51,13 @@ var tools := {
|
||||||
"lasso",
|
"lasso",
|
||||||
preload("res://src/Tools/SelectionTools/Lasso.tscn")
|
preload("res://src/Tools/SelectionTools/Lasso.tscn")
|
||||||
),
|
),
|
||||||
|
"PaintSelect":
|
||||||
|
Tool.new(
|
||||||
|
"PaintSelect",
|
||||||
|
"Select by Drawing",
|
||||||
|
"paint_selection",
|
||||||
|
preload("res://src/Tools/SelectionTools/PaintSelect.tscn")
|
||||||
|
),
|
||||||
"Move": Tool.new("Move", "Move", "move", preload("res://src/Tools/Move.tscn")),
|
"Move": Tool.new("Move", "Move", "move", preload("res://src/Tools/Move.tscn")),
|
||||||
"Zoom": Tool.new("Zoom", "Zoom", "zoom", preload("res://src/Tools/Zoom.tscn")),
|
"Zoom": Tool.new("Zoom", "Zoom", "zoom", preload("res://src/Tools/Zoom.tscn")),
|
||||||
"Pan": Tool.new("Pan", "Pan", "pan", preload("res://src/Tools/Pan.tscn")),
|
"Pan": Tool.new("Pan", "Pan", "pan", preload("res://src/Tools/Pan.tscn")),
|
||||||
|
|
380
src/Tools/SelectionTools/PaintSelect.gd
Normal file
380
src/Tools/SelectionTools/PaintSelect.gd
Normal file
|
@ -0,0 +1,380 @@
|
||||||
|
extends SelectionTool
|
||||||
|
|
||||||
|
var _brush_size: int = 2
|
||||||
|
var _brush := Brushes.get_default_brush()
|
||||||
|
var _indicator := BitMap.new()
|
||||||
|
var _polylines := []
|
||||||
|
var _brush_image := Image.new()
|
||||||
|
var _brush_texture := ImageTexture.new()
|
||||||
|
var _circle_tool_shortcut: PoolVector2Array
|
||||||
|
|
||||||
|
var _last_position := Vector2.INF
|
||||||
|
var _draw_points := []
|
||||||
|
|
||||||
|
|
||||||
|
func get_config() -> Dictionary:
|
||||||
|
return {
|
||||||
|
"brush_type": _brush.type,
|
||||||
|
"brush_index": _brush.index,
|
||||||
|
"brush_size": _brush_size,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func set_config(config: Dictionary) -> void:
|
||||||
|
var type: int = config.get("brush_type", _brush.type)
|
||||||
|
var index: int = config.get("brush_index", _brush.index)
|
||||||
|
_brush = Global.brushes_popup.get_brush(type, index)
|
||||||
|
_brush_size = config.get("brush_size", _brush_size)
|
||||||
|
|
||||||
|
|
||||||
|
func update_config() -> void:
|
||||||
|
$Brush/BrushSize.value = _brush_size
|
||||||
|
update_brush()
|
||||||
|
|
||||||
|
|
||||||
|
func draw_start(position: Vector2) -> void:
|
||||||
|
.draw_start(position)
|
||||||
|
if !_move:
|
||||||
|
_draw_points.append_array(draw_tool(position))
|
||||||
|
_last_position = position
|
||||||
|
|
||||||
|
|
||||||
|
func draw_move(position: Vector2) -> void:
|
||||||
|
if selection_node.arrow_key_move:
|
||||||
|
return
|
||||||
|
.draw_move(position)
|
||||||
|
if !_move:
|
||||||
|
append_gap(_last_position, position)
|
||||||
|
_last_position = position
|
||||||
|
_draw_points.append_array(draw_tool(position))
|
||||||
|
_offset = position
|
||||||
|
|
||||||
|
|
||||||
|
func draw_end(position: Vector2) -> void:
|
||||||
|
if selection_node.arrow_key_move:
|
||||||
|
return
|
||||||
|
if !_move:
|
||||||
|
_draw_points.append_array(draw_tool(position))
|
||||||
|
.draw_end(position)
|
||||||
|
|
||||||
|
|
||||||
|
func draw_preview() -> void:
|
||||||
|
if _last_position != Vector2.INF and !_move:
|
||||||
|
var canvas: Node2D = Global.canvas.previews
|
||||||
|
var position := canvas.position
|
||||||
|
var scale := canvas.scale
|
||||||
|
if Global.mirror_view:
|
||||||
|
position.x = position.x + Global.current_project.size.x
|
||||||
|
scale.x = -1
|
||||||
|
canvas.draw_set_transform(position, canvas.rotation, scale)
|
||||||
|
var indicator := _fill_bitmap_with_points(_draw_points, Global.current_project.size)
|
||||||
|
|
||||||
|
for line in _create_polylines(indicator):
|
||||||
|
canvas.draw_polyline(PoolVector2Array(line), Color.black)
|
||||||
|
|
||||||
|
# Handle mirroring
|
||||||
|
if Tools.horizontal_mirror:
|
||||||
|
for line in _create_polylines(
|
||||||
|
_fill_bitmap_with_points(
|
||||||
|
mirror_array(_draw_points, true, false), Global.current_project.size
|
||||||
|
)
|
||||||
|
):
|
||||||
|
canvas.draw_polyline(PoolVector2Array(line), Color.black)
|
||||||
|
if Tools.vertical_mirror:
|
||||||
|
for line in _create_polylines(
|
||||||
|
_fill_bitmap_with_points(
|
||||||
|
mirror_array(_draw_points, true, true), Global.current_project.size
|
||||||
|
)
|
||||||
|
):
|
||||||
|
canvas.draw_polyline(PoolVector2Array(line), Color.black)
|
||||||
|
if Tools.vertical_mirror:
|
||||||
|
for line in _create_polylines(
|
||||||
|
_fill_bitmap_with_points(
|
||||||
|
mirror_array(_draw_points, false, true), Global.current_project.size
|
||||||
|
)
|
||||||
|
):
|
||||||
|
canvas.draw_polyline(PoolVector2Array(line), Color.black)
|
||||||
|
|
||||||
|
canvas.draw_set_transform(canvas.position, canvas.rotation, canvas.scale)
|
||||||
|
|
||||||
|
|
||||||
|
func apply_selection(_position) -> void:
|
||||||
|
var project: Project = Global.current_project
|
||||||
|
var cleared := false
|
||||||
|
if !_add and !_subtract and !_intersect:
|
||||||
|
cleared = true
|
||||||
|
Global.canvas.selection.clear_selection()
|
||||||
|
if _draw_points.size() > 1:
|
||||||
|
var selection_map_copy := SelectionMap.new()
|
||||||
|
selection_map_copy.copy_from(project.selection_map)
|
||||||
|
if _intersect:
|
||||||
|
selection_map_copy.clear()
|
||||||
|
paint_selection(selection_map_copy, _draw_points)
|
||||||
|
|
||||||
|
# Handle mirroring
|
||||||
|
if Tools.horizontal_mirror:
|
||||||
|
paint_selection(selection_map_copy, mirror_array(_draw_points, true, false))
|
||||||
|
if Tools.vertical_mirror:
|
||||||
|
paint_selection(selection_map_copy, mirror_array(_draw_points, true, true))
|
||||||
|
if Tools.vertical_mirror:
|
||||||
|
paint_selection(selection_map_copy, mirror_array(_draw_points, false, true))
|
||||||
|
|
||||||
|
project.selection_map = selection_map_copy
|
||||||
|
Global.canvas.selection.big_bounding_rectangle = project.selection_map.get_used_rect()
|
||||||
|
else:
|
||||||
|
if !cleared:
|
||||||
|
Global.canvas.selection.clear_selection()
|
||||||
|
|
||||||
|
Global.canvas.selection.commit_undo("Select", undo_data)
|
||||||
|
_draw_points.clear()
|
||||||
|
_last_position = Vector2.INF
|
||||||
|
|
||||||
|
|
||||||
|
func paint_selection(selection_map: SelectionMap, points: PoolVector2Array) -> void:
|
||||||
|
var project: Project = Global.current_project
|
||||||
|
var size := selection_map.get_size()
|
||||||
|
for point in points:
|
||||||
|
if point.x < 0 or point.y < 0 or point.x >= size.x or point.y >= size.y:
|
||||||
|
continue
|
||||||
|
if _intersect:
|
||||||
|
if project.selection_map.is_pixel_selected(point):
|
||||||
|
selection_map.select_pixel(point, true)
|
||||||
|
else:
|
||||||
|
selection_map.select_pixel(point, !_subtract)
|
||||||
|
|
||||||
|
|
||||||
|
# Bresenham's Algorithm
|
||||||
|
# Thanks to https://godotengine.org/qa/35276/tile-based-line-drawing-algorithm-efficiency
|
||||||
|
func append_gap(start: Vector2, end: Vector2) -> void:
|
||||||
|
var dx := int(abs(end.x - start.x))
|
||||||
|
var dy := int(-abs(end.y - start.y))
|
||||||
|
var err := dx + dy
|
||||||
|
var e2 := err << 1
|
||||||
|
var sx = 1 if start.x < end.x else -1
|
||||||
|
var sy = 1 if start.y < end.y else -1
|
||||||
|
var x = start.x
|
||||||
|
var y = start.y
|
||||||
|
while !(x == end.x && y == end.y):
|
||||||
|
e2 = err << 1
|
||||||
|
if e2 >= dy:
|
||||||
|
err += dy
|
||||||
|
x += sx
|
||||||
|
if e2 <= dx:
|
||||||
|
err += dx
|
||||||
|
y += sy
|
||||||
|
_draw_points.append_array(draw_tool(Vector2(x, y)))
|
||||||
|
|
||||||
|
|
||||||
|
func mirror_array(array: Array, h: bool, v: bool) -> Array:
|
||||||
|
var new_array := []
|
||||||
|
var project: Project = Global.current_project
|
||||||
|
for point in array:
|
||||||
|
if h and v:
|
||||||
|
new_array.append(
|
||||||
|
Vector2(project.x_symmetry_point - point.x, project.y_symmetry_point - point.y)
|
||||||
|
)
|
||||||
|
elif h:
|
||||||
|
new_array.append(Vector2(project.x_symmetry_point - point.x, point.y))
|
||||||
|
elif v:
|
||||||
|
new_array.append(Vector2(point.x, project.y_symmetry_point - point.y))
|
||||||
|
|
||||||
|
return new_array
|
||||||
|
|
||||||
|
|
||||||
|
func draw_tool(position: Vector2) -> PoolVector2Array:
|
||||||
|
_prepare_tool()
|
||||||
|
return _draw_tool(position)
|
||||||
|
|
||||||
|
|
||||||
|
func _prepare_tool() -> void:
|
||||||
|
match _brush.type:
|
||||||
|
Brushes.CIRCLE:
|
||||||
|
_prepare_circle_tool(false)
|
||||||
|
Brushes.FILLED_CIRCLE:
|
||||||
|
_prepare_circle_tool(true)
|
||||||
|
|
||||||
|
|
||||||
|
func _prepare_circle_tool(fill: bool) -> void:
|
||||||
|
var circle_tool_map := _create_circle_indicator(_brush_size, fill)
|
||||||
|
# Go through that BitMap and build an Array of the "displacement" from the center of the bits
|
||||||
|
# that are true.
|
||||||
|
var diameter := _brush_size * 2 + 1
|
||||||
|
for n in range(0, diameter):
|
||||||
|
for m in range(0, diameter):
|
||||||
|
if circle_tool_map.get_bit(Vector2(m, n)):
|
||||||
|
_circle_tool_shortcut.append(Vector2(m - _brush_size, n - _brush_size))
|
||||||
|
|
||||||
|
|
||||||
|
# Make sure to always have invoked _prepare_tool() before this. This computes the coordinates to be
|
||||||
|
# drawn if it can (except for the generic brush, when it's actually drawing them)
|
||||||
|
func _draw_tool(position: Vector2) -> PoolVector2Array:
|
||||||
|
match _brush.type:
|
||||||
|
Brushes.PIXEL:
|
||||||
|
return _compute_draw_tool_pixel(position)
|
||||||
|
Brushes.CIRCLE:
|
||||||
|
return _compute_draw_tool_circle(position, false)
|
||||||
|
Brushes.FILLED_CIRCLE:
|
||||||
|
return _compute_draw_tool_circle(position, true)
|
||||||
|
_:
|
||||||
|
return _compute_draw_tool_brush(position)
|
||||||
|
|
||||||
|
|
||||||
|
func _compute_draw_tool_pixel(position: Vector2) -> PoolVector2Array:
|
||||||
|
var result := PoolVector2Array()
|
||||||
|
var start := position - Vector2.ONE * (_brush_size >> 1)
|
||||||
|
var end := start + Vector2.ONE * _brush_size
|
||||||
|
for y in range(start.y, end.y):
|
||||||
|
for x in range(start.x, end.x):
|
||||||
|
if !_draw_points.has(Vector2(x, y)):
|
||||||
|
result.append(Vector2(x, y))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
# Compute the array of coordinates that should be drawn
|
||||||
|
func _compute_draw_tool_circle(position: Vector2, fill := false) -> PoolVector2Array:
|
||||||
|
var size := Vector2(_brush_size, _brush_size)
|
||||||
|
var pos = position - (size / 2).floor()
|
||||||
|
if _circle_tool_shortcut:
|
||||||
|
return _draw_tool_circle_from_map(position)
|
||||||
|
|
||||||
|
var result := PoolVector2Array()
|
||||||
|
if fill:
|
||||||
|
result = DrawingAlgos.get_ellipse_points_filled(pos, size)
|
||||||
|
else:
|
||||||
|
result = DrawingAlgos.get_ellipse_points(pos, size)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
func _draw_tool_circle_from_map(position: Vector2) -> PoolVector2Array:
|
||||||
|
var result := PoolVector2Array()
|
||||||
|
for displacement in _circle_tool_shortcut:
|
||||||
|
result.append(position + displacement)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
func _compute_draw_tool_brush(position: Vector2) -> PoolVector2Array:
|
||||||
|
var result := PoolVector2Array()
|
||||||
|
var brush_mask := BitMap.new()
|
||||||
|
var pos = position - (_indicator.get_size() / 2).floor()
|
||||||
|
brush_mask.create_from_image_alpha(_brush_image, 0.0)
|
||||||
|
for x in brush_mask.get_size().x:
|
||||||
|
for y in brush_mask.get_size().y:
|
||||||
|
if !_draw_points.has(Vector2(x, y)):
|
||||||
|
if brush_mask.get_bit(Vector2(x, y)):
|
||||||
|
result.append(pos + Vector2(x, y))
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
func _on_BrushType_pressed() -> void:
|
||||||
|
if not Global.brushes_popup.is_connected("brush_selected", self, "_on_Brush_selected"):
|
||||||
|
Global.brushes_popup.connect(
|
||||||
|
"brush_selected", self, "_on_Brush_selected", [], CONNECT_ONESHOT
|
||||||
|
)
|
||||||
|
# Now we set position and tab allignment considering certain conditions
|
||||||
|
var pop_size := Vector2(226, 72)
|
||||||
|
var pop_position: Vector2 = $Brush/Type.rect_global_position
|
||||||
|
var off_limit: float = Global.shrink * (pop_position.x + pop_size.x) - OS.get_window_size().x
|
||||||
|
if off_limit <= 72 and off_limit > 0: # Some space left "Leftward"
|
||||||
|
pop_position -= Vector2(pop_size.x / 2.0 - 48, -32)
|
||||||
|
Global.brushes_popup.get_node("TabContainer").tab_align = TabContainer.ALIGN_CENTER
|
||||||
|
elif off_limit >= 72: # No space left "Leftward"
|
||||||
|
pop_position -= Vector2(pop_size.x / 2.0 + 16, -32)
|
||||||
|
Global.brushes_popup.get_node("TabContainer").tab_align = TabContainer.ALIGN_RIGHT
|
||||||
|
else:
|
||||||
|
pop_position -= Vector2(0, -32) # Plenty of space left "Leftward"
|
||||||
|
Global.brushes_popup.get_node("TabContainer").tab_align = TabContainer.ALIGN_LEFT
|
||||||
|
Global.brushes_popup.popup(Rect2(pop_position, pop_size))
|
||||||
|
|
||||||
|
|
||||||
|
func _on_Brush_selected(brush: Brushes.Brush) -> void:
|
||||||
|
_brush = brush
|
||||||
|
update_brush()
|
||||||
|
save_config()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_BrushSize_value_changed(value: float) -> void:
|
||||||
|
if _brush_size != int(value):
|
||||||
|
_brush_size = int(value)
|
||||||
|
update_config()
|
||||||
|
save_config()
|
||||||
|
|
||||||
|
|
||||||
|
# The Blue Indicator code
|
||||||
|
func update_brush() -> void:
|
||||||
|
$Brush/BrushSize.suffix = "px" # Assume we are using default brushes
|
||||||
|
match _brush.type:
|
||||||
|
Brushes.PIXEL:
|
||||||
|
_brush_texture.create_from_image(load("res://assets/graphics/pixel_image.png"), 0)
|
||||||
|
Brushes.CIRCLE:
|
||||||
|
_brush_texture.create_from_image(load("res://assets/graphics/circle_9x9.png"), 0)
|
||||||
|
Brushes.FILLED_CIRCLE:
|
||||||
|
_brush_texture.create_from_image(load("res://assets/graphics/circle_filled_9x9.png"), 0)
|
||||||
|
Brushes.FILE, Brushes.RANDOM_FILE, Brushes.CUSTOM:
|
||||||
|
$Brush/BrushSize.suffix = "00 %" # Use a different size convention on images
|
||||||
|
if _brush.random.size() <= 1:
|
||||||
|
_brush_image = _create_blended_brush_image(_brush.image)
|
||||||
|
else:
|
||||||
|
var random := randi() % _brush.random.size()
|
||||||
|
_brush_image = _create_blended_brush_image(_brush.random[random])
|
||||||
|
_brush_texture.create_from_image(_brush_image, 0)
|
||||||
|
_indicator = _create_brush_indicator()
|
||||||
|
_polylines = _create_polylines(_indicator)
|
||||||
|
|
||||||
|
$Brush/Type/Texture.texture = _brush_texture
|
||||||
|
|
||||||
|
|
||||||
|
func _create_blended_brush_image(image: Image) -> Image:
|
||||||
|
var size := image.get_size() * _brush_size
|
||||||
|
var brush := Image.new()
|
||||||
|
brush.copy_from(image)
|
||||||
|
brush.resize(size.x, size.y, Image.INTERPOLATE_NEAREST)
|
||||||
|
return brush
|
||||||
|
|
||||||
|
|
||||||
|
func _create_brush_indicator() -> BitMap:
|
||||||
|
match _brush.type:
|
||||||
|
Brushes.PIXEL:
|
||||||
|
return _create_pixel_indicator(_brush_size)
|
||||||
|
Brushes.CIRCLE:
|
||||||
|
return _create_circle_indicator(_brush_size, false)
|
||||||
|
Brushes.FILLED_CIRCLE:
|
||||||
|
return _create_circle_indicator(_brush_size, true)
|
||||||
|
_:
|
||||||
|
return _create_image_indicator(_brush_image)
|
||||||
|
|
||||||
|
|
||||||
|
func _create_pixel_indicator(size: int) -> BitMap:
|
||||||
|
var bitmap := BitMap.new()
|
||||||
|
bitmap.create(Vector2.ONE * size)
|
||||||
|
bitmap.set_bit_rect(Rect2(Vector2.ZERO, Vector2.ONE * size), true)
|
||||||
|
return bitmap
|
||||||
|
|
||||||
|
|
||||||
|
func _create_circle_indicator(size: int, fill := false) -> BitMap:
|
||||||
|
_circle_tool_shortcut = PoolVector2Array()
|
||||||
|
var diameter := Vector2(size, size) * 2 + Vector2.ONE
|
||||||
|
return _fill_bitmap_with_points(_compute_draw_tool_circle(Vector2(size, size), fill), diameter)
|
||||||
|
|
||||||
|
|
||||||
|
func _create_image_indicator(image: Image) -> BitMap:
|
||||||
|
var bitmap := BitMap.new()
|
||||||
|
bitmap.create_from_image_alpha(image, 0.0)
|
||||||
|
return bitmap
|
||||||
|
|
||||||
|
|
||||||
|
func draw_indicator(left: bool) -> void:
|
||||||
|
var color := Global.left_tool_color if left else Global.right_tool_color
|
||||||
|
draw_indicator_at(_cursor, Vector2.ZERO, color)
|
||||||
|
|
||||||
|
|
||||||
|
func draw_indicator_at(position: Vector2, offset: Vector2, color: Color) -> void:
|
||||||
|
var canvas = Global.canvas.indicators
|
||||||
|
position -= (_indicator.get_size() / 2).floor()
|
||||||
|
position -= offset
|
||||||
|
canvas.draw_set_transform(position, canvas.rotation, canvas.scale)
|
||||||
|
var polylines := _polylines
|
||||||
|
for line in polylines:
|
||||||
|
var pool := PoolVector2Array(line)
|
||||||
|
canvas.draw_polyline(pool, color)
|
||||||
|
canvas.draw_set_transform(canvas.position, canvas.rotation, canvas.scale)
|
90
src/Tools/SelectionTools/PaintSelect.tscn
Normal file
90
src/Tools/SelectionTools/PaintSelect.tscn
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
[gd_scene load_steps=6 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://src/Tools/SelectionTools/SelectionTool.tscn" type="PackedScene" id=1]
|
||||||
|
[ext_resource path="res://src/Tools/SelectionTools/PaintSelect.gd" type="Script" id=2]
|
||||||
|
[ext_resource path="res://src/UI/Nodes/ValueSlider.tscn" type="PackedScene" id=3]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id=1]
|
||||||
|
bg_color = Color( 1, 1, 1, 1 )
|
||||||
|
border_color = Color( 1, 1, 1, 1 )
|
||||||
|
corner_radius_top_left = 5
|
||||||
|
corner_radius_top_right = 5
|
||||||
|
corner_radius_bottom_right = 5
|
||||||
|
corner_radius_bottom_left = 5
|
||||||
|
anti_aliasing = false
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id=2]
|
||||||
|
bg_color = Color( 1, 1, 1, 1 )
|
||||||
|
border_color = Color( 1, 1, 1, 1 )
|
||||||
|
corner_radius_top_left = 5
|
||||||
|
corner_radius_top_right = 5
|
||||||
|
corner_radius_bottom_right = 5
|
||||||
|
corner_radius_bottom_left = 5
|
||||||
|
anti_aliasing = false
|
||||||
|
|
||||||
|
[node name="ToolOptions" instance=ExtResource( 1 )]
|
||||||
|
script = ExtResource( 2 )
|
||||||
|
|
||||||
|
[node name="Brush" type="HBoxContainer" parent="." index="2"]
|
||||||
|
margin_top = 26.0
|
||||||
|
margin_right = 116.0
|
||||||
|
margin_bottom = 58.0
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="Type" type="Button" parent="Brush" index="0"]
|
||||||
|
margin_right = 32.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
rect_min_size = Vector2( 32, 32 )
|
||||||
|
hint_tooltip = "Select a brush"
|
||||||
|
mouse_default_cursor_shape = 2
|
||||||
|
size_flags_horizontal = 0
|
||||||
|
custom_styles/hover = SubResource( 1 )
|
||||||
|
custom_styles/pressed = SubResource( 1 )
|
||||||
|
custom_styles/focus = SubResource( 2 )
|
||||||
|
custom_styles/disabled = SubResource( 2 )
|
||||||
|
custom_styles/normal = SubResource( 1 )
|
||||||
|
|
||||||
|
[node name="Texture" type="TextureRect" parent="Brush/Type" index="0"]
|
||||||
|
margin_right = 32.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
expand = true
|
||||||
|
stretch_mode = 6
|
||||||
|
|
||||||
|
[node name="BrushSize" parent="Brush" index="1" instance=ExtResource( 3 )]
|
||||||
|
margin_left = 36.0
|
||||||
|
margin_right = 116.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
min_value = 1.0
|
||||||
|
max_value = 25.0
|
||||||
|
value = 1.0
|
||||||
|
allow_greater = true
|
||||||
|
prefix = "Size:"
|
||||||
|
suffix = "px"
|
||||||
|
is_global = true
|
||||||
|
|
||||||
|
[node name="PositionLabel" parent="." index="3"]
|
||||||
|
margin_top = 62.0
|
||||||
|
margin_bottom = 76.0
|
||||||
|
|
||||||
|
[node name="XSpinBox" parent="." index="4"]
|
||||||
|
margin_top = 80.0
|
||||||
|
margin_bottom = 104.0
|
||||||
|
|
||||||
|
[node name="YSpinBox" parent="." index="5"]
|
||||||
|
margin_top = 108.0
|
||||||
|
margin_bottom = 132.0
|
||||||
|
|
||||||
|
[node name="SizeLabel" parent="." index="6"]
|
||||||
|
margin_top = 136.0
|
||||||
|
margin_bottom = 150.0
|
||||||
|
|
||||||
|
[node name="WSpinBox" parent="." index="7"]
|
||||||
|
margin_top = 154.0
|
||||||
|
margin_bottom = 178.0
|
||||||
|
|
||||||
|
[node name="HSpinBox" parent="." index="8"]
|
||||||
|
margin_top = 182.0
|
||||||
|
margin_bottom = 206.0
|
||||||
|
|
||||||
|
[connection signal="pressed" from="Brush/Type" to="." method="_on_BrushType_pressed"]
|
||||||
|
[connection signal="value_changed" from="Brush/BrushSize" to="." method="_on_BrushSize_value_changed"]
|
Loading…
Reference in a new issue