extends Control class_name MMGradientEditor class GradientCursor: extends Control var color : Color const WIDTH : int = 10 func _ready() -> void: rect_position = Vector2(0, 15) rect_size = Vector2(WIDTH, 15) func _draw() -> void: var polygon : PoolVector2Array = PoolVector2Array([Vector2(0, 5), Vector2(WIDTH/2, 0), Vector2(WIDTH, 5), Vector2(WIDTH, 15), Vector2(0, 15)]) var c = color c.a = 1.0 draw_colored_polygon(polygon, c) func _gui_input(ev) -> void: if ev is InputEventMouseButton: if ev.button_index == BUTTON_LEFT && ev.doubleclick: get_parent().select_color(self, ev.global_position) elif ev.button_index == BUTTON_RIGHT && get_parent().get_sorted_cursors().size() > 2: var parent = get_parent() parent.remove_child(self) parent.update_value() queue_free() elif ev is InputEventMouseMotion && (ev.button_mask & 1) != 0: rect_position.x += ev.relative.x rect_position.x = min(max(0, rect_position.x), get_parent().rect_size.x-rect_size.x) get_parent().update_value() func get_position() -> Vector2: return rect_position.x / (get_parent().rect_size.x - WIDTH) func set_color(c) -> void: color = c get_parent().update_value() update() static func sort(a, b) -> bool: return a.get_position() < b.get_position() var value = null setget set_value export var embedded : bool = true signal updated(value) func _ready() -> void: $Gradient.material = $Gradient.material.duplicate(true) set_value(MMGradient.new()) func get_gradient_from_data(data): if typeof(data) == TYPE_ARRAY: return data elif typeof(data) == TYPE_DICTIONARY: if data.has("parameters") and data.parameters.has("gradient"): return data.parameters.gradient if data.has("type") and data.type == "Gradient": return data return null func get_drag_data(position : Vector2): var data = MMType.serialize_value(value) var preview = ColorRect.new() preview.rect_size = Vector2(64, 24) preview.material = $Gradient.material set_drag_preview(preview) return data func can_drop_data(position : Vector2, data) -> bool: return get_gradient_from_data(data) != null func drop_data(position : Vector2, data) -> void: var gradient = get_gradient_from_data(data) if gradient != null: set_value(MMType.deserialize_value(gradient)) func set_value(v) -> void: value = v for c in get_children(): if c is GradientCursor: remove_child(c) c.free() for p in value.points: add_cursor(p.v*(rect_size.x-GradientCursor.WIDTH), p.c) $Interpolation.selected = value.interpolation update_shader() func update_value() -> void: value.clear() for c in get_children(): if c is GradientCursor: value.add_point(c.rect_position.x/(rect_size.x-GradientCursor.WIDTH), c.color) update_shader() func add_cursor(x, color) -> void: var cursor = GradientCursor.new() add_child(cursor) cursor.rect_position.x = x cursor.color = color func _gui_input(ev) -> void: if ev is InputEventMouseButton && ev.button_index == 1 && ev.doubleclick: if ev.position.y > 15: var p = clamp(ev.position.x, 0, rect_size.x-GradientCursor.WIDTH) add_cursor(p, get_gradient_color(p)) update_value() elif embedded: var popup = load("res://material_maker/widgets/gradient_popup.tscn").instance() add_child(popup) var popup_size = popup.rect_size popup.popup(Rect2(ev.global_position, Vector2(0, 0))) popup.set_global_position(ev.global_position-Vector2(popup_size.x / 2, popup_size.y)) popup.init(value) popup.connect("updated", self, "set_value") # Showing a color picker popup to change a cursor's color var active_cursor func select_color(cursor, position) -> void: active_cursor = cursor $Gradient/Popup/ColorPicker.color = cursor.color $Gradient/Popup/ColorPicker.connect("color_changed", cursor, "set_color") $Gradient/Popup.rect_position = position $Gradient/Popup.popup() func _on_Popup_popup_hide() -> void: $Gradient/Popup/ColorPicker.disconnect("color_changed", active_cursor, "set_color") # Calculating a color from the gradient and generating the shader 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) -> Color: return value.get_color(x / (rect_size.x - GradientCursor.WIDTH)) func update_shader() -> void: var shader shader = "shader_type canvas_item;\n" var params = value.get_shader_params("") for sp in params.keys(): shader += "uniform float "+sp+" = "+str(params[sp])+";\n" shader += value.get_shader("") shader += "void fragment() { COLOR = _gradient_fct(UV.x); }" $Gradient.material.shader.set_code(shader) emit_signal("updated", value) func _on_Interpolation_item_selected(ID) -> void: value.interpolation = ID update_shader()