Updated switch node and refactored generator edit feature.

This commit is contained in:
Rodolphe Suescun 2019-10-20 00:59:51 +02:00
parent cdfc247fc1
commit c8414f47df
14 changed files with 308 additions and 430 deletions

View File

@ -40,6 +40,12 @@ func _ready():
func can_be_deleted() -> bool:
return true
func toggle_editable():
return false
func is_editable():
return false
func init_parameters():
for p in get_parameter_defs():
if !parameters.has(p.name):

View File

@ -5,12 +5,26 @@ class_name MMGenGraph
var label : String = "Graph"
var connections = []
var editable = false
func get_type():
return "graph"
func get_type_name():
return label
func toggle_editable():
editable = !editable
if editable:
model = null
return true
func is_editable():
return editable
func get_parameter_defs():
if has_node("gen_parameters"):
return get_node("gen_parameters").get_parameter_defs()

View File

@ -5,6 +5,17 @@ class_name MMGenShader
var shader_model : Dictionary = {}
var uses_seed = false
var editable = false
func toggle_editable():
editable = !editable
if editable:
model = null
return true
func is_editable():
return editable
func get_type():
return "shader"

View File

@ -6,32 +6,48 @@ class_name MMGenSwitch
Texture generator switch
"""
var editable = false
func get_type():
return "switch"
func get_type_name():
return "Switch"
func toggle_editable():
editable = !editable
return true
func is_editable():
return editable
func get_parameter_defs():
var choices = parameters.choices if parameters.has("choices") else 2
return [
{ name="outputs", label="Outputs", type="float", min=1, max=5, step=1, default=2 },
{ name="choices", label="Choices", type="float", min=2, max=5, step=1, default=2 },
{ name="source", label="Source", type="float", min=0, max=1, step=1, default=0 },
{ name="source", label="Source", type="float", min=0, max=choices-1, step=1, default=0 },
]
func get_input_defs():
var rv : Array = []
for c in range(parameters.choices):
for o in range(parameters.outputs):
rv.push_back({ name=PoolByteArray([64+o]).get_string_from_ascii()+str(c), type="rgba" })
var n = PoolByteArray([65+o]).get_string_from_ascii()+str(c)
rv.push_back({ name=n, label=n, type="rgba" })
return rv
func get_output_defs():
var rv : Array = []
for o in range(parameters.outputs):
rv.push_back({ name=PoolByteArray([64+o]).get_string_from_ascii(), type="rgba" })
var n = PoolByteArray([65+o]).get_string_from_ascii()
rv.push_back({ name=n, type="rgba" })
return rv
func set_parameter(p, v):
.set_parameter(p, v)
emit_signal("parameter_changed", "__update_all__", null)
func source_changed(input_index : int):
notify_output_change(input_index % int(parameters.outputs))
@ -42,7 +58,7 @@ func _get_shader_code(uv : String, output_index : int, context : MMGenContext):
while rv is GDScriptFunctionState:
rv = yield(rv, "completed")
return rv
return { defs="", code="", textures={} }
return { globals=[], defs="", code="", textures={} }
func _serialize(data):
return data

View File

@ -30,7 +30,7 @@ const MENU = [
{ menu="View", command="view_reset_zoom", shortcut="Control+0", description="Reset zoom" },
{ menu="Tools", submenu="create", description="Create" },
{ menu="Tools", command="create_subgraph", shortcut="Control+G", description="Create group" },
{ menu="Tools", command="make_selected_nodes_editable", shortcut="Control+F", description="Make selected nodes editable" },
{ menu="Tools", command="make_selected_nodes_editable", shortcut="Control+E", description="Make selected nodes editable" },
{ menu="Tools" },
{ menu="Tools", command="add_to_user_library", description="Add selected node to user library" },
{ menu="Tools", command="save_user_library", description="Save user library" },
@ -308,8 +308,8 @@ func make_selected_nodes_editable():
var selected_nodes = get_selected_nodes()
if !selected_nodes.empty():
for n in selected_nodes:
n.generator.model = null
n.update_node()
if n.generator.toggle_editable():
n.update_node()
func add_to_user_library():
var selected_nodes = get_selected_nodes()

View File

@ -62,7 +62,7 @@ margin_left = 125.0
margin_right = 171.0
margin_bottom = 20.0
text = "Tools"
items = [ "Create", null, 0, false, false, -1, 0, null, "PopupMenu", false, "Create group", null, 0, false, false, 18, 268435527, null, "", false, "Make selected nodes editable", null, 0, false, false, 19, 268435526, null, "", false, "", null, 0, false, false, -1, 0, null, "", true, "Add selected node to user library", null, 0, false, false, 21, 0, null, "", false, "Save user library", null, 0, false, false, 22, 0, null, "", false ]
items = [ "Create", null, 0, false, false, -1, 0, null, "PopupMenu", false, "Create group", null, 0, false, false, 18, 268435527, null, "", false, "Make selected nodes editable", null, 0, false, false, 19, 268435525, null, "", false, "", null, 0, false, false, -1, 0, null, "", true, "Add selected node to user library", null, 0, false, false, 21, 0, null, "", false, "Save user library", null, 0, false, false, 22, 0, null, "", false ]
[node name="Help" type="MenuButton" parent="VBoxContainer/Menu"]
margin_left = 175.0

View File

@ -1,53 +0,0 @@
tool
extends "res://addons/material_maker/nodes/node_generic.gd"
func _on_Edit_pressed():
var edit_window = load("res://addons/material_maker/widgets/node_editor/node_editor.tscn").instance()
get_parent().add_child(edit_window)
if model_data != null:
edit_window.set_model_data(model_data)
edit_window.connect("node_changed", self, "update_node")
edit_window.popup_centered()
func _on_Load_pressed():
var dialog = FileDialog.new()
add_child(dialog)
dialog.rect_min_size = Vector2(500, 500)
dialog.access = FileDialog.ACCESS_FILESYSTEM
dialog.mode = FileDialog.MODE_OPEN_FILE
dialog.add_filter("*.mmn;Material Maker Node")
dialog.connect("file_selected", self, "do_load_node")
dialog.popup_centered()
func do_load_node(file_name):
set_model(file_name)
func _on_Save_pressed():
var dialog = FileDialog.new()
add_child(dialog)
dialog.rect_min_size = Vector2(500, 500)
dialog.access = FileDialog.ACCESS_FILESYSTEM
dialog.mode = FileDialog.MODE_SAVE_FILE
dialog.add_filter("*.mmn;Material Maker Node")
dialog.connect("file_selected", self, "do_save_node")
dialog.popup_centered()
func do_save_node(file_name):
var file = File.new()
if file.open(file_name, File.WRITE) == OK:
file.store_string(to_json(model_data))
file.close()
model = file_name
func deserialize(data):
if data.has("model_data"):
update_node(data.model_data)
.deserialize(data)
func serialize():
var file = model
model = "custom"
var return_value = .serialize()
model = file
return_value.model_data = model_data
return return_value

View File

@ -1,65 +0,0 @@
[gd_scene load_steps=6 format=2]
[ext_resource path="res://addons/material_maker/nodes/custom.gd" type="Script" id=1]
[ext_resource path="res://addons/material_maker/icons/icons.svg" type="Texture" id=2]
[sub_resource type="AtlasTexture" id=1]
flags = 4
atlas = ExtResource( 2 )
region = Rect2( 16, 16, 15, 17 )
[sub_resource type="AtlasTexture" id=2]
flags = 4
atlas = ExtResource( 2 )
region = Rect2( 48, 16, 16, 16 )
[sub_resource type="AtlasTexture" id=3]
flags = 4
atlas = ExtResource( 2 )
region = Rect2( 32, 16, 16, 16 )
[node name="Custom" type="GraphNode"]
margin_left = 1.0
margin_top = 2.0
margin_right = 95.0
margin_bottom = 53.0
mouse_filter = 1
title = "Custom"
show_close = true
slot/0/left_enabled = false
slot/0/left_type = 0
slot/0/left_color = Color( 1, 1, 1, 1 )
slot/0/right_enabled = false
slot/0/right_type = 0
slot/0/right_color = Color( 1, 1, 1, 1 )
script = ExtResource( 1 )
model = null
[node name="CustomNodeButtons" type="HBoxContainer" parent="."]
margin_left = 16.0
margin_top = 24.0
margin_right = 92.0
margin_bottom = 47.0
[node name="Edit" type="Button" parent="CustomNodeButtons"]
margin_right = 27.0
margin_bottom = 23.0
icon = SubResource( 1 )
flat = true
[node name="Load" type="Button" parent="CustomNodeButtons"]
margin_left = 31.0
margin_right = 59.0
margin_bottom = 23.0
icon = SubResource( 2 )
flat = true
[node name="Save" type="Button" parent="CustomNodeButtons"]
margin_left = 63.0
margin_right = 76.0
margin_bottom = 23.0
icon = SubResource( 3 )
flat = true
[connection signal="pressed" from="CustomNodeButtons/Edit" to="." method="_on_Edit_pressed"]
[connection signal="pressed" from="CustomNodeButtons/Load" to="." method="_on_Load_pressed"]
[connection signal="pressed" from="CustomNodeButtons/Save" to="." method="_on_Save_pressed"]

View File

@ -28,7 +28,9 @@ func on_offset_changed():
func on_parameter_changed(p, v):
if ignore_parameter_change == p:
return
if controls.has(p):
if p == "__update_all__":
call_deferred("update_node")
elif controls.has(p):
var o = controls[p]
if o is LineEdit:
o.text = str(v)
@ -140,14 +142,33 @@ func create_parameter_control(p : Dictionary):
control = preload("res://addons/material_maker/widgets/gradient_editor.tscn").instance()
return control
func update_node():
# Clean node
var custom_node_buttons = null
func save_preview_widget():
if preview != null:
remove_child(preview)
if preview_timer != null:
preview_timer.stop()
remove_child(preview_timer)
func restore_preview_widget():
if preview == null:
preview = TextureRect.new()
preview.visible = false
preview_position = get_child_count()
if preview.visible:
add_child(preview)
update_preview()
set_slot(preview_position, false, 0, Color(0.0, 0.0, 0.0), false, 0, Color(0.0, 0.0, 0.0))
# Preview timer
if preview_timer == null:
preview_timer = Timer.new()
preview_timer.one_shot = true
preview_timer.connect("timeout", self, "do_update_preview")
add_child(preview_timer)
func update_node():
# Clean node
var custom_node_buttons = null
save_preview_widget()
for c in get_children():
remove_child(c)
c.free()
@ -275,23 +296,14 @@ func update_node():
var empty_control : Control = Control.new()
empty_control.rect_min_size.x = button_width
hsizer.add_child(empty_control)
# Preview
if preview == null:
preview = TextureRect.new()
preview.visible = false
preview_position = get_child_count()
# Edit buttons
if generator.model == null:
if generator.is_editable():
var edit_buttons = preload("res://addons/material_maker/nodes/edit_buttons.tscn").instance()
add_child(edit_buttons)
edit_buttons.connect_buttons(self, "edit_generator", "load_generator", "save_generator")
# Preview timer
if preview_timer == null:
preview_timer = Timer.new()
preview_timer.one_shot = true
preview_timer.connect("timeout", self, "do_update_preview")
add_child(preview_timer)
set_slot(edit_buttons.get_index(), false, 0, Color(0.0, 0.0, 0.0), false, 0, Color(0.0, 0.0, 0.0))
# Preview
restore_preview_widget()
func edit_generator():
if generator.has_method("edit"):
@ -350,15 +362,18 @@ func do_save_generator(file_name : String):
file.store_string(to_json(data))
file.close()
func update_preview_buttons(index : int):
for i in range(output_count):
if i != index:
var line = get_child(i)
line.get_child(line.get_child_count()-1).pressed = false
func on_preview_button(pressed : bool, index : int):
if pressed:
preview_index = index
var width
if preview.visible:
for i in range(output_count):
if i != index:
var line = get_child(i)
line.get_child(line.get_child_count()-1).pressed = false
update_preview_buttons(index)
update_preview()
else:
var status = update_preview(get_child(0).rect_size.x)

View File

@ -1,5 +1,5 @@
tool
extends "res://addons/material_maker/node_base.gd"
extends GraphNode
var generator = null

View File

@ -1,281 +0,0 @@
tool
extends "res://addons/material_maker/node_base.gd"
export(String) var model = null setget set_model
var model_data = null
var uses_seed = false
func _ready():
show_close = true
connect("offset_changed", self, "_on_offset_changed")
func set_model(m):
if m != null and typeof(m) == TYPE_STRING:
var file = File.new()
var file_name = m
if !file.file_exists(file_name):
file_name = "res://addons/material_maker/nodes/%s.mmn" % [ m ]
if file.file_exists(file_name):
if file.open(file_name, File.READ) != OK:
return
var data = file.get_as_text()
var status = validate_json(data)
file.close()
if status != "":
print("Incorrect node description (%s)" % status)
return
data = parse_json(data)
model = m
update_node(data)
else:
print("set_model error "+str(m))
func update_node(data):
print("node_generic.update_node")
if typeof(data) != TYPE_DICTIONARY:
return
if !data.has("name"):
return
# Clean node
parameters = {}
var custom_node_buttons = null
for c in get_children():
if c.name != "CustomNodeButtons":
remove_child(c)
c.queue_free()
else:
custom_node_buttons = c
# Rebuild node
title = data.name
model_data = data
uses_seed = false
if model_data.has("instance") and model_data.instance.find("$(seed)"):
uses_seed = true
if model_data.has("parameters") and typeof(model_data.parameters) == TYPE_ARRAY:
var control_list = []
var sizer = null
for p in model_data.parameters:
if !p.has("name") or !p.has("type"):
continue
var control = null
if p.type == "float":
if p.has("widget") and p.widget == "spinbox":
control = SpinBox.new()
else:
control = HSlider.new()
control.min_value = p.min
control.max_value = p.max
control.step = 0 if !p.has("step") else p.step
if p.has("default"):
control.value = p.default
control.rect_min_size.x = 80
parameters[p.name] = 0.5*(p.min+p.max)
elif p.type == "size":
control = OptionButton.new()
for i in range(p.first, p.last+1):
var s = pow(2, i)
control.add_item("%dx%d" % [ s, s ])
control.selected = 0 if !p.has("default") else p.default-p.first
elif p.type == "enum":
control = OptionButton.new()
for i in range(p.values.size()):
var value = p.values[i]
control.add_item(value.name)
control.selected = 0 if !p.has("default") else p.default
elif p.type == "boolean":
control = CheckBox.new()
elif p.type == "color":
control = ColorPickerButton.new()
elif p.type == "gradient":
control = preload("res://addons/material_maker/widgets/gradient_editor.tscn").instance()
if control != null:
var label = p.name
control.name = label
control_list.append(control)
if p.has("label"):
label = p.label
if sizer == null or label != "nonewline":
sizer = HBoxContainer.new()
sizer.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
add_child(sizer)
if label != "" && label != "nonewline":
var label_widget = Label.new()
label_widget.text = label
label_widget.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
sizer.add_child(label_widget)
control.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
sizer.add_child(control)
initialize_properties(control_list)
else:
model_data.parameters = []
if model_data.has("inputs") and typeof(model_data.inputs) == TYPE_ARRAY:
for i in range(model_data.inputs.size()):
var input = model_data.inputs[i]
var enable_left = false
var color_left = Color(0.5, 0.5, 0.5)
if typeof(input) == TYPE_DICTIONARY:
if input.type == "rgb":
enable_left = true
color_left = Color(0.5, 0.5, 1.0)
elif input.type == "rgba":
enable_left = true
color_left = Color(0.0, 0.5, 0.0, 0.5)
else:
enable_left = true
set_slot(i, enable_left, 0, color_left, false, 0, Color())
else:
model_data.inputs = []
if model_data.has("outputs") and typeof(model_data.outputs) == TYPE_ARRAY:
for i in range(model_data.outputs.size()):
var output = model_data.outputs[i]
var enable_right = false
var color_right = Color(0.5, 0.5, 0.5)
if typeof(output) == TYPE_DICTIONARY:
if output.has("rgb"):
enable_right = true
color_right = Color(0.5, 0.5, 1.0)
elif output.has("rgba"):
enable_right = true
color_right = Color(0.0, 0.5, 0.0, 0.5)
elif output.has("f"):
enable_right = true
set_slot(i, is_slot_enabled_left(i), get_slot_type_left(i), get_slot_color_left(i), enable_right, 0, color_right)
else:
model_data.outputs = []
if custom_node_buttons != null:
move_child(custom_node_buttons, get_child_count()-1)
func find_keyword_call(string, keyword):
var search_string = "$%s(" % keyword
var position = string.find(search_string)
if position == -1:
return null
var parenthesis_level = 0
var parameter_begin = position+search_string.length()
var parameter_end = -1
for i in range(parameter_begin, string.length()):
if string[i] == '(':
parenthesis_level += 1
elif string[i] == ')':
if parenthesis_level == 0:
return string.substr(parameter_begin, i-parameter_begin)
parenthesis_level -= 1
return ""
func replace_input(string, input, type, src, default):
var required_defs = ""
var required_code = ""
while true:
var uv = find_keyword_call(string, input)
if uv == null:
break
elif uv == "":
print("syntax error")
break
var src_code
if src == null:
src_code = subst(default, "(%s)" % uv)
else:
src_code = src.get_shader_code(uv)
src_code.string = src_code[type]
required_defs += src_code.defs
required_code += src_code.code
string = string.replace("$%s(%s)" % [ input, uv ], src_code.string)
return { string=string, defs=required_defs, code=required_code }
func is_word_letter(l):
return "azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN1234567890_".find(l) != -1
func replace_variable(string, variable, value):
string = string.replace("$(%s)" % variable, value)
var keyword_size = variable.length()+1
var new_string = ""
while !string.empty():
var pos = string.find("$"+variable)
if pos == -1:
new_string += string
break
new_string += string.left(pos)
string = string.right(pos)
if string.empty() or !is_word_letter(string[0]):
new_string += value
else:
new_string += "$"+variable
string = string.right(keyword_size)
return new_string
func subst(string, uv = ""):
var required_defs = ""
var required_code = ""
string = replace_variable(string, "name", name)
string = replace_variable(string, "seed", str(get_seed()))
if uv != "":
string = replace_variable(string, "uv", "("+uv+")")
if model_data.has("parameters") and typeof(model_data.parameters) == TYPE_ARRAY:
for p in model_data.parameters:
if !p.has("name") or !p.has("type"):
continue
var value = parameters[p.name]
var value_string = null
if p.type == "float":
value_string = "%.9f" % value
elif p.type == "size":
value_string = "%.9f" % pow(2, value+p.first)
elif p.type == "enum":
value_string = p.values[value].value
elif p.type == "color":
value_string = "vec4(%.9f, %.9f, %.9f, %.9f)" % [ value.r, value.g, value.b, value.a ]
elif p.type == "gradient":
value_string = p.name+"_gradient_fct"
if value_string != null:
string = replace_variable(string, p.name, value_string)
if model_data.has("inputs") and typeof(model_data.inputs) == TYPE_ARRAY:
for i in range(model_data.inputs.size()):
var input = model_data.inputs[i]
var source = get_source(i)
var result = replace_input(string, input.name, input.type, source, input.default)
string = result.string
required_defs += result.defs
required_code += result.code
return { string=string, defs=required_defs, code=required_code }
func _get_shader_code(uv, slot = 0):
var output_info = [ { field="rgba", type="vec4" }, { field="rgb", type="vec3" }, { field="f", type="float" } ]
var rv = { defs="", code="" }
var variant_string = uv+","+str(slot)
if model_data != null and model_data.has("outputs") and model_data.outputs.size() > slot:
var output = model_data.outputs[slot]
rv.defs = ""
if model_data.has("instance") && generated_variants.empty():
rv.defs += subst(model_data.instance).string
for p in model_data.parameters:
if p.type == "gradient":
rv.defs += parameters[p.name].get_shader(p.name+"_gradient_fct")
var variant_index = generated_variants.find(variant_string)
if variant_index == -1:
variant_index = generated_variants.size()
generated_variants.append(variant_string)
for t in output_info:
if output.has(t.field):
var subst_output = subst(output[t.field], uv)
rv.defs += subst_output.defs
rv.code += subst_output.code
rv.code += "%s %s_%d_%d_%s = %s;\n" % [ t.type, name, slot, variant_index, t.field, subst_output.string ]
for t in output_info:
if output.has(t.field):
rv[t.field] = "%s_%d_%d_%s" % [ name, slot, variant_index, t.field ]
return rv
func get_globals():
var list = .get_globals()
if typeof(model_data) == TYPE_DICTIONARY and model_data.has("global") and list.find(model_data.global) == -1:
list.append(model_data.global)
return list
func _on_offset_changed():
update_shaders()
func serialize():
var return_value = .serialize()
return_value.type = model
return return_value

View File

@ -0,0 +1,87 @@
tool
extends MMGraphNodeGeneric
var fixed_lines : int = 0
func _ready():
update_node()
func update_preview_buttons(index : int):
for i in range(generator.parameters.outputs):
if i != index:
var line = get_child(i)
line.get_child(2).pressed = false
func update_node():
print("update_node")
if generator == null or !generator.parameters.has("outputs") or !generator.parameters.has("choices"):
return
save_preview_widget()
var new_fixed_lines = 3 if generator.editable else 1
if new_fixed_lines != fixed_lines:
fixed_lines = new_fixed_lines
# Remove all lines
while get_child_count() > 0:
var remove = get_child(0)
remove_child(remove)
remove.free()
var lines_list = []
if generator.editable:
lines_list.push_back( { name="outputs", min=1, max=5 } )
lines_list.push_back( { name="choices", min=2, max=5 } )
lines_list.push_back( { name="source", min=0, max=generator.parameters.choices-1 } )
for l in lines_list:
var sizer = HBoxContainer.new()
var input_label = Label.new()
sizer.add_child(input_label)
var control : HSlider = HSlider.new()
control.name = l.name
control.value = generator.parameters[l.name]
control.min_value = l.min
control.max_value = l.max
control.step = 1
control.rect_min_size.x = 75
sizer.add_child(control)
control.connect("value_changed", self, "_on_value_changed", [ l.name ])
controls[l.name] = control
sizer.add_child(preload("res://addons/material_maker/widgets/preview_button.tscn").instance())
add_child(sizer)
else:
# Keep lines with controls
while get_child_count() > output_count and get_child_count() > fixed_lines:
var remove = get_child(get_child_count()-1)
remove_child(remove)
remove.free()
# Populate the GraphNode
var output_count : int = generator.parameters.outputs
var input_count : int = output_count * generator.parameters.choices
controls["source"].max_value = generator.parameters.choices-1
while get_child_count() < input_count:
var sizer = HBoxContainer.new()
var input_label = Label.new()
sizer.add_child(input_label)
if get_child_count() < 5:
var space = Control.new()
space.size_flags_horizontal = SIZE_EXPAND | SIZE_FILL
sizer.add_child(space)
sizer.add_child(preload("res://addons/material_maker/widgets/preview_button.tscn").instance())
add_child(sizer)
rect_size = Vector2(0, 0)
for i in range(get_child_count()):
var sizer = get_child(i)
var has_input = true
var has_output = false
if i < 5:
has_output = i < output_count
sizer.get_child(2).visible = has_output
sizer.get_child(2).connect("toggled", self, "on_preview_button", [ i ])
if i >= input_count:
sizer.get_child(0).text = ""
has_input = false
else:
sizer.get_child(0).text = PoolByteArray([65+i%int(output_count)]).get_string_from_ascii()+str(1+i/int(output_count))
sizer.get_child(0).add_color_override("font_color", Color(1.0, 1.0, 1.0) if i/int(output_count) == generator.parameters.source else Color(0.5, 0.5, 0.5))
set_slot(i, has_input, 0, Color(0.0, 0.5, 0.0, 0.5), has_output, 0, Color(0.0, 0.5, 0.0, 0.5))
# Preview
restore_preview_widget()
print("update_node end")

View File

@ -0,0 +1,129 @@
[gd_scene load_steps=4 format=2]
[ext_resource path="res://addons/material_maker/nodes/switch.gd" type="Script" id=1]
[ext_resource path="res://addons/material_maker/widgets/preview_button.tscn" type="PackedScene" id=2]
[sub_resource type="Theme" id=1]
[node name="Switch" type="GraphNode"]
margin_left = -1.0
margin_top = -1.0
margin_right = 150.0
margin_bottom = 78.0
mouse_filter = 1
size_flags_stretch_ratio = 0.13
theme = SubResource( 1 )
title = "Switch"
show_close = true
slot/0/left_enabled = false
slot/0/left_type = 0
slot/0/left_color = Color( 0.5, 0.5, 1, 1 )
slot/0/right_enabled = true
slot/0/right_type = 0
slot/0/right_color = Color( 0.5, 0.5, 1, 1 )
slot/1/left_enabled = false
slot/1/left_type = 0
slot/1/left_color = Color( 1, 1, 1, 1 )
slot/1/right_enabled = false
slot/1/right_type = 0
slot/1/right_color = Color( 1, 1, 1, 1 )
slot/2/left_enabled = false
slot/2/left_type = 0
slot/2/left_color = Color( 1, 1, 1, 1 )
slot/2/right_enabled = false
slot/2/right_type = 0
slot/2/right_color = Color( 1, 1, 1, 1 )
script = ExtResource( 1 )
[node name="HBox1" type="HBoxContainer" parent="."]
margin_left = 16.0
margin_top = 24.0
margin_right = 135.0
margin_bottom = 40.0
[node name="Label" type="Label" parent="HBox1"]
margin_top = 1.0
margin_right = 20.0
margin_bottom = 15.0
rect_min_size = Vector2( 20, 0 )
text = "A0"
[node name="outputs" type="HSlider" parent="HBox1"]
margin_left = 24.0
margin_right = 99.0
margin_bottom = 16.0
rect_min_size = Vector2( 75, 0 )
hint_tooltip = "Output count"
min_value = 1.0
max_value = 5.0
value = 2.0
[node name="PreviewButton" parent="HBox1" instance=ExtResource( 2 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 103.0
margin_right = 119.0
margin_bottom = 16.0
[node name="HBox2" type="HBoxContainer" parent="."]
margin_left = 16.0
margin_top = 40.0
margin_right = 135.0
margin_bottom = 56.0
[node name="Label" type="Label" parent="HBox2"]
margin_top = 1.0
margin_right = 20.0
margin_bottom = 15.0
rect_min_size = Vector2( 20, 0 )
text = "A0"
[node name="choices" type="HSlider" parent="HBox2"]
margin_left = 24.0
margin_right = 99.0
margin_bottom = 16.0
rect_min_size = Vector2( 75, 0 )
hint_tooltip = "Choice count"
min_value = 2.0
max_value = 5.0
value = 2.0
[node name="PreviewButton" parent="HBox2" instance=ExtResource( 2 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 103.0
margin_right = 119.0
margin_bottom = 16.0
[node name="HBox3" type="HBoxContainer" parent="."]
margin_left = 16.0
margin_top = 57.0
margin_right = 135.0
margin_bottom = 73.0
[node name="Label" type="Label" parent="HBox3"]
margin_top = 1.0
margin_right = 20.0
margin_bottom = 15.0
rect_min_size = Vector2( 20, 0 )
text = "A0"
[node name="source" type="HSlider" parent="HBox3"]
margin_left = 24.0
margin_right = 99.0
margin_bottom = 16.0
rect_min_size = Vector2( 75, 0 )
hint_tooltip = "Choice"
max_value = 4.0
value = 1.0
ticks_on_borders = true
[node name="PreviewButton" parent="HBox3" instance=ExtResource( 2 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_left = 103.0
margin_right = 119.0
margin_bottom = 16.0
[connection signal="value_changed" from="HBox1/outputs" to="." method="_on_value_changed" binds= [ "outputs" ]]
[connection signal="value_changed" from="HBox2/choices" to="." method="_on_value_changed" binds= [ "choices" ]]
[connection signal="value_changed" from="HBox3/source" to="." method="_on_value_changed" binds= [ "source" ]]

View File

@ -179,5 +179,4 @@ file_logging/enable_file_logging=true
[rendering]
quality/filters/anisotropic_filter_level=16
environment/default_environment="res://default_env.tres"