2022-06-11 13:15:34 +00:00
|
|
|
# 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 TextureRect
|
|
|
|
|
|
|
|
signal updated(gradient, cc)
|
|
|
|
|
|
|
|
var continuous_change := true
|
|
|
|
var active_cursor: GradientCursor # Showing a color picker popup to change a cursor's color
|
|
|
|
|
|
|
|
onready var x_offset: float = rect_size.x - GradientCursor.WIDTH
|
|
|
|
onready var gradient: Gradient = texture.gradient
|
2022-08-04 14:14:43 +00:00
|
|
|
onready var color_picker: ColorPicker = $Popup.get_node("ColorPicker")
|
2022-06-11 13:15:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
class GradientCursor:
|
|
|
|
extends Control
|
|
|
|
|
|
|
|
const WIDTH := 10
|
|
|
|
var color: Color
|
|
|
|
var sliding := false
|
|
|
|
onready var label: Label = get_parent().get_node("Value")
|
|
|
|
|
|
|
|
func _ready() -> void:
|
|
|
|
rect_position = Vector2(0, 15)
|
|
|
|
rect_size = Vector2(WIDTH, 15)
|
|
|
|
|
|
|
|
func _draw() -> void:
|
|
|
|
# warning-ignore:integer_division
|
|
|
|
var polygon := PoolVector2Array(
|
|
|
|
[
|
|
|
|
Vector2(0, 5),
|
|
|
|
Vector2(WIDTH / 2, 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 == BUTTON_LEFT:
|
|
|
|
if ev.doubleclick:
|
|
|
|
get_parent().select_color(self, ev.global_position)
|
|
|
|
elif ev.pressed:
|
|
|
|
get_parent().continuous_change = false
|
|
|
|
sliding = true
|
|
|
|
label.visible = true
|
|
|
|
label.text = "%.03f" % get_cursor_position()
|
|
|
|
else:
|
|
|
|
sliding = false
|
|
|
|
label.visible = false
|
|
|
|
elif ev.button_index == BUTTON_RIGHT and get_parent().get_sorted_cursors().size() > 2:
|
|
|
|
var parent = get_parent()
|
|
|
|
parent.remove_child(self)
|
|
|
|
parent.continuous_change = false
|
|
|
|
parent.update_from_value()
|
|
|
|
queue_free()
|
|
|
|
elif ev is InputEventMouseMotion and (ev.button_mask & BUTTON_MASK_LEFT) != 0 and sliding:
|
|
|
|
rect_position.x += get_local_mouse_position().x
|
|
|
|
if ev.control:
|
|
|
|
rect_position.x = (
|
|
|
|
round(get_cursor_position() * 20.0)
|
|
|
|
* 0.05
|
|
|
|
* (get_parent().rect_size.x - WIDTH)
|
|
|
|
)
|
|
|
|
rect_position.x = min(max(0, rect_position.x), get_parent().rect_size.x - rect_size.x)
|
|
|
|
get_parent().update_from_value()
|
|
|
|
label.text = "%.03f" % get_cursor_position()
|
|
|
|
|
|
|
|
func get_cursor_position() -> float:
|
|
|
|
return rect_position.x / (get_parent().rect_size.x - WIDTH)
|
|
|
|
|
|
|
|
func set_color(c: Color) -> void:
|
|
|
|
color = c
|
|
|
|
get_parent().update_from_value()
|
|
|
|
update()
|
|
|
|
|
|
|
|
static func sort(a, b) -> bool:
|
|
|
|
return a.get_position() < b.get_position()
|
|
|
|
|
|
|
|
func can_drop_data(_position, data) -> bool:
|
|
|
|
return typeof(data) == TYPE_COLOR
|
|
|
|
|
|
|
|
func drop_data(_position, data) -> void:
|
|
|
|
set_color(data)
|
|
|
|
|
|
|
|
|
|
|
|
func _ready() -> void:
|
|
|
|
create_cursors()
|
|
|
|
|
|
|
|
|
|
|
|
func create_cursors() -> void:
|
|
|
|
for c in get_children():
|
|
|
|
if c is GradientCursor:
|
|
|
|
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 = clamp(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 get_children():
|
|
|
|
if c is GradientCursor:
|
|
|
|
var point: float = c.rect_position.x / x_offset
|
|
|
|
gradient.add_point(point, c.color)
|
|
|
|
emit_signal("updated", gradient, continuous_change)
|
|
|
|
continuous_change = true
|
|
|
|
|
|
|
|
|
|
|
|
func add_cursor(x: float, color: Color) -> void:
|
|
|
|
var cursor := GradientCursor.new()
|
|
|
|
add_child(cursor)
|
|
|
|
cursor.rect_position.x = x
|
|
|
|
cursor.color = color
|
|
|
|
|
|
|
|
|
|
|
|
func select_color(cursor: GradientCursor, position: Vector2) -> void:
|
|
|
|
active_cursor = cursor
|
|
|
|
color_picker.color = cursor.color
|
2022-08-04 14:14:43 +00:00
|
|
|
if position.x > rect_global_position.x + (rect_size.x / 2.0):
|
|
|
|
position.x = rect_global_position.x + rect_size.x
|
|
|
|
else:
|
|
|
|
position.x = rect_global_position.x - $Popup.rect_size.x
|
2022-06-11 13:15:34 +00:00
|
|
|
$Popup.rect_position = position
|
|
|
|
$Popup.popup()
|
|
|
|
|
|
|
|
|
|
|
|
func get_sorted_cursors() -> Array:
|
|
|
|
var array := []
|
|
|
|
for c in get_children():
|
|
|
|
if c is GradientCursor:
|
|
|
|
array.append(c)
|
|
|
|
array.sort_custom(GradientCursor, "sort")
|
|
|
|
return array
|
|
|
|
|
|
|
|
|
|
|
|
func get_gradient_color(x: float) -> Color:
|
|
|
|
return gradient.interpolate(x / x_offset)
|
|
|
|
|
|
|
|
|
|
|
|
func _on_ColorPicker_color_changed(color: Color) -> void:
|
|
|
|
active_cursor.set_color(color)
|
|
|
|
|
|
|
|
|
|
|
|
func _on_GradientEdit_resized() -> void:
|
|
|
|
if not gradient:
|
|
|
|
return
|
|
|
|
x_offset = rect_size.x - GradientCursor.WIDTH
|
|
|
|
create_cursors()
|