1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-02-08 11:29:47 +00:00
Pixelorama/src/UI/Nodes/GradientEdit.gd
2024-03-22 03:07:21 +02:00

216 lines
6.2 KiB
GDScript

# Code taken and modified from Material Maker, licensed under MIT
# gdlint: ignore=max-line-length
# https://github.com/RodZill4/material-maker/blob/master/material_maker/widgets/gradient_editor/gradient_editor.gd
class_name GradientEditNode
extends Control
signal updated(gradient: Gradient, cc: bool)
var continuous_change := true
var active_cursor: GradientCursor ## Showing a color picker popup to change a cursor's color
@onready var x_offset: float = size.x - GradientCursor.WIDTH
@onready var texture_rect: TextureRect = $TextureRect as TextureRect
@onready var texture := texture_rect.texture as GradientTexture2D
@onready var gradient := texture.gradient
@onready var color_picker := $Popup.get_node("ColorPicker") as ColorPicker
@onready var divide_dialog := $DivideConfirmationDialog as ConfirmationDialog
@onready var number_of_parts_spin_box := $"%NumberOfPartsSpinBox" as SpinBox
@onready var add_point_end_check_box := $"%AddPointEndCheckBox" as CheckBox
class GradientCursor:
extends Control
const WIDTH := 10
var color: Color
var sliding := false
@onready var parent: TextureRect = get_parent()
@onready var grand_parent: Container = parent.get_parent()
@onready var label: Label = parent.get_node("Value")
func _ready() -> void:
position = Vector2(0, 15)
size = Vector2(WIDTH, 15)
func _draw() -> void:
var polygon := PackedVector2Array(
[
Vector2(0, 5),
Vector2(WIDTH / 2.0, 0),
Vector2(WIDTH, 5),
Vector2(WIDTH, 15),
Vector2(0, 15),
Vector2(0, 5)
]
)
var c := color
c.a = 1.0
draw_colored_polygon(polygon, c)
draw_polyline(polygon, Color(0.0, 0.0, 0.0) if color.v > 0.5 else Color(1.0, 1.0, 1.0))
func _gui_input(ev: InputEvent) -> void:
if ev is InputEventMouseButton:
if ev.button_index == MOUSE_BUTTON_LEFT:
if ev.double_click:
grand_parent.select_color(self, ev.global_position)
elif ev.pressed:
grand_parent.continuous_change = false
sliding = true
label.visible = true
label.text = "%.03f" % get_caret_column()
else:
sliding = false
label.visible = false
elif (
ev.button_index == MOUSE_BUTTON_RIGHT
and grand_parent.get_sorted_cursors().size() > 2
):
parent.remove_child(self)
grand_parent.continuous_change = false
grand_parent.update_from_value()
queue_free()
elif (
ev is InputEventMouseMotion
and (ev.button_mask & MOUSE_BUTTON_MASK_LEFT) != 0
and sliding
):
position.x += get_local_mouse_position().x
if ev.ctrl_pressed:
position.x = (roundi(get_caret_column() * 20.0) * 0.05 * (parent.size.x - WIDTH))
position.x = mini(maxi(0, position.x), parent.size.x - size.x)
grand_parent.update_from_value()
label.text = "%.03f" % get_caret_column()
func get_caret_column() -> float:
return position.x / (parent.size.x - WIDTH)
func set_color(c: Color) -> void:
color = c
grand_parent.update_from_value()
queue_redraw()
func _can_drop_data(_position: Vector2, data) -> bool:
return typeof(data) == TYPE_COLOR
func _drop_data(_position: Vector2, data) -> void:
set_color(data)
func _ready() -> void:
_create_cursors()
%InterpolationOptionButton.select(gradient.interpolation_mode)
%ColorSpaceOptionButton.select(gradient.interpolation_color_space)
func _create_cursors() -> void:
for c in texture_rect.get_children():
if c is GradientCursor:
texture_rect.remove_child(c)
c.queue_free()
for i in gradient.get_point_count():
var p: float = gradient.get_offset(i)
add_cursor(p * x_offset, gradient.get_color(i))
func _gui_input(ev: InputEvent) -> void:
if ev.is_action_pressed("left_mouse"):
var p := clampf(ev.position.x, 0, x_offset)
add_cursor(p, get_gradient_color(p))
continuous_change = false
update_from_value()
func update_from_value() -> void:
gradient.offsets = []
for c in texture_rect.get_children():
if c is GradientCursor:
var point: float = c.position.x / x_offset
gradient.add_point(point, c.color)
updated.emit(gradient, continuous_change)
continuous_change = true
func add_cursor(x: float, color: Color) -> void:
var cursor := GradientCursor.new()
texture_rect.add_child(cursor)
cursor.position.x = x
cursor.color = color
func select_color(cursor: GradientCursor, pos: Vector2) -> void:
active_cursor = cursor
color_picker.color = cursor.color
if pos.x > global_position.x + (size.x / 2.0):
pos.x = global_position.x + size.x
else:
pos.x = global_position.x - $Popup.size.x
$Popup.position = pos
$Popup.popup()
func get_sorted_cursors() -> Array:
var array: Array[GradientCursor] = []
for c in texture_rect.get_children():
if c is GradientCursor:
array.append(c)
array.sort_custom(
func(a: GradientCursor, b: GradientCursor): return a.get_position() < b.get_position()
)
return array
func get_gradient_color(x: float) -> Color:
return gradient.sample(x / x_offset)
func set_gradient_texture(new_texture: GradientTexture2D) -> void:
$TextureRect.texture = new_texture
texture = new_texture
gradient = texture.gradient
func _on_ColorPicker_color_changed(color: Color) -> void:
active_cursor.set_color(color)
func _on_GradientEdit_resized() -> void:
if not is_instance_valid(texture_rect):
return
x_offset = size.x - GradientCursor.WIDTH
_create_cursors()
func _on_InterpolationOptionButton_item_selected(index: Gradient.InterpolationMode) -> void:
gradient.interpolation_mode = index
updated.emit(gradient, continuous_change)
func _on_color_space_option_button_item_selected(index: Gradient.ColorSpace) -> void:
gradient.interpolation_color_space = index
updated.emit(gradient, continuous_change)
func _on_DivideButton_pressed() -> void:
divide_dialog.popup_centered()
func _on_DivideConfirmationDialog_confirmed() -> void:
var add_point_to_end := add_point_end_check_box.button_pressed
var parts := number_of_parts_spin_box.value
var colors: PackedColorArray = []
var end_point := 1 if add_point_to_end else 0
parts -= end_point
if not add_point_to_end:
# Move the final color one part behind, useful for it to be in constant interpolation
gradient.add_point((parts - 1) / parts, gradient.sample(1))
for i in parts + end_point:
colors.append(gradient.sample(i / parts))
gradient.offsets = []
for i in parts + end_point:
gradient.add_point(i / parts, colors[i])
_create_cursors()
updated.emit(gradient, continuous_change)