Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions addons/material_maker/engine/nodes/gen_portal.gd
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var source : MMGenBase.OutputPort

var editable := false
var color : Color = Color.WHITE
var horizontal_label : bool = mm_globals.get_config("aperture_label_position")

func is_editable() -> bool:
return true
Expand Down Expand Up @@ -93,6 +94,7 @@ func _serialize(data : Dictionary) -> Dictionary:
data.io = io
data.port_type = port_type
data.color = MMType.serialize_value(color)
data.horizontal_label = horizontal_label

# remove unused field
data.erase("seed_int")
Expand All @@ -105,3 +107,5 @@ func _deserialize(data : Dictionary) -> void:
port_type = data.port_type
if data.has("color"):
color = MMType.deserialize_value(data.color)
if data.has("horizontal_label"):
horizontal_label = data.horizontal_label
3 changes: 3 additions & 0 deletions material_maker/doc/user_interface_shortcuts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ Graph Editor
+-------------------------------------------------------+----------------------------------------------------+
| :kbd:`F2` | :kbd:`Enter` | :kbd:`LMB` Double-click | Edit selected aperture node |
+-------------------------------------------------------+----------------------------------------------------+
| :kbd:`R` | Toggle aperture node label position |
| | (vertical/horizontal) |
+-------------------------------------------------------+----------------------------------------------------+
| :kbd:`Ctrl/Cmd-G` | Create group from selected nodes |
+-------------------------------------------------------+----------------------------------------------------+
| :kbd:`Alt-S` | Swap inputs on selected node |
Expand Down
5 changes: 3 additions & 2 deletions material_maker/globals.gd
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@ const DEFAULT_CONFIG : Dictionary = {
ui_use_native_file_dialogs = true,
win_tablet_driver = 0,
dialog_dim_background = true,
node_minimize_button = true,
node_close_button = true,
node_minimize_button = false,
node_close_button = false,
aperture_label_position = 0
}


Expand Down
132 changes: 132 additions & 0 deletions material_maker/nodes/portal/completion.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
class_name PortalCompletionPanel
extends Panel

var selected_item : int = -1
const HEIGHT_MAX_ITEMS : int = 8

@export_multiline var slot_svg : String
@onready var graph : MMGraphEdit = get_parent()

var portal_edit : LineEdit = null


## Emitted when selected item changes(i.e. via up/down key presses)
signal selection_updated

func _ready() -> void:
hide_panel()
setup_theme()
update_position()
setup_signals()

func setup_signals() -> void:
graph.draw.connect(update_position)
portal_edit.tree_exiting.connect(portal_edit_tree_exiting)

func portal_edit_tree_exiting() -> void:
graph.draw.disconnect(update_position)
queue_free()

func update_position() -> void:
scale = portal_edit.scale
position = Vector2((portal_edit.size.x - size.x) * 0.5,
portal_edit.size.y + 10) * graph.zoom + portal_edit.position

func _gui_input(event: InputEvent) -> void:
if (event is InputEventMouseButton
and event.button_index == MOUSE_BUTTON_WHEEL_UP
or event.button_index == MOUSE_BUTTON_WHEEL_DOWN):
accept_event()

func _input(event : InputEvent) -> void:
if event is InputEventKey and event.pressed and visible:
match event.get_keycode_with_modifiers():
KEY_UP:
update_current_selection(KEY_UP)
accept_event()
KEY_DOWN:
update_current_selection(KEY_DOWN)
accept_event()
KEY_ESCAPE:
hide_panel()
accept_event()
elif event is InputEventMouseButton and event.pressed:
if event.button_index == MOUSE_BUTTON_LEFT or event.button_index == MOUSE_BUTTON_RIGHT:
if not Rect2(Vector2.ZERO, size).has_point(get_local_mouse_position()) or not visible:
hide_panel()
else:
if visible:
handle_click_completion()
accept_event()

func setup_theme() -> void:
theme = mm_globals.main_window.theme
$ItemList.add_theme_constant_override("scrollbar_h_separation", 1)

var vscroll : VScrollBar = $ItemList.get_v_scroll_bar()
vscroll.add_theme_constant_override("padding_left", 2)
vscroll.add_theme_constant_override("padding_right", 1)

var sb : StyleBoxFlat = StyleBoxFlat.new()
sb.draw_center = true
sb.bg_color = Color.TRANSPARENT
sb.border_color = sb.bg_color
sb.set_border_width_all(2)
vscroll.add_theme_stylebox_override("scroll", sb)

func show_panel() -> void:
mouse_filter = Control.MOUSE_FILTER_PASS
show()

func hide_panel() -> void:
mouse_filter = Control.MOUSE_FILTER_IGNORE
hide()

func request_completion(filter : String) -> void:
if filter.is_empty():
hide_panel()
return
show_panel()
selected_item = -1
$ItemList.clear()

if not filter.is_empty():
for node in graph.get_children():
if node is MMGraphPortal and node.is_portal_in():
var link : String = node.get_link()
if link.begins_with(filter.to_lower()) or link.contains(filter.to_lower()):
var port_color : Color = node.get_input_port_color(0)
var icon : Image = Image.new()
icon.load_svg_from_buffer(slot_svg.replace("#FFF",
"#" + port_color.to_html(false)).to_utf8_buffer())
var index : int = $ItemList.add_icon_item(ImageTexture.create_from_image(icon))
$ItemList.set_item_text(index, link)
$ItemList.set_item_tooltip_enabled(index, false)

# approx height adjustment
size.y = clampf(4 + $ItemList.item_count * 25, 50, HEIGHT_MAX_ITEMS * 25)
custom_minimum_size = size
if $ItemList.item_count == 0:
hide_panel()

func update_current_selection(input : Key) -> void:
selected_item = wrapi(selected_item +
(1 if input == KEY_DOWN else -1), 0, $ItemList.item_count)
if $ItemList.item_count != 0:
$ItemList.select(selected_item)
$ItemList.ensure_current_is_visible()
set_portal_edit_text($ItemList.get_item_text(selected_item))
portal_edit.size.x = 0
selection_updated.emit()

func handle_click_completion() -> void:
var item : int = $ItemList.get_item_at_position(get_local_mouse_position(), true)
if item != -1:
$ItemList.select(item)
set_portal_edit_text($ItemList.get_item_text(item))
portal_edit.focus_exited.emit()
hide_panel()

func set_portal_edit_text(new_text : String) -> void:
portal_edit.text = new_text
portal_edit.caret_column = new_text.length()
1 change: 1 addition & 0 deletions material_maker/nodes/portal/completion.gd.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://buqmwxkc40t11
28 changes: 28 additions & 0 deletions material_maker/nodes/portal/completion.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[gd_scene format=3 uid="uid://s1vtfefwu7cr"]

[ext_resource type="Script" uid="uid://buqmwxkc40t11" path="res://material_maker/nodes/portal/completion.gd" id="1_v4kch"]

[node name="Completion" type="Panel" unique_id=1214631678]
custom_minimum_size = Vector2(225, 0)
anchors_preset = 5
anchor_left = 0.5
anchor_right = 0.5
offset_left = -100.0
offset_right = 100.0
grow_horizontal = 2
script = ExtResource("1_v4kch")
slot_svg = "<svg width=\"16\" height=\"16\">
<circle cx=\"8\" cy=\"8\" r=\"6\" fill=\"#FFF\" stroke=\"#000\" stroke-width=\"1\"/>
</svg>"

[node name="ItemList" type="ItemList" parent="." unique_id=1794413207]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
allow_search = false
wraparound_items = false
fixed_column_width = 200
metadata/_edit_use_anchors_ = true
85 changes: 65 additions & 20 deletions material_maker/nodes/portal/portal.gd
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ var is_editing := false

var syncing_io := false

const label_y_offset : float = 35.0

func _ready() -> void:
super._ready()
get_titlebar_hbox().get_children().map(func(n): n.hide())
Expand All @@ -22,7 +24,6 @@ func update_node() -> void:

func _draw() -> void:
const label_font_size : int = 16
const label_y_offset : int = 40

# in/out arc decoration
var offset : float = PI if is_portal_out() else 0.0
Expand All @@ -31,10 +32,16 @@ func _draw() -> void:
# label
var label_pos := size * 0.5
var label_color : Color = generator.color
var label_draw_pos : Vector2 = label_pos
var label_size : Vector2 = LABEL_FONT.get_string_size(
get_link(), HORIZONTAL_ALIGNMENT_CENTER, -1, label_font_size)

var label_size = LABEL_FONT.get_string_size(get_link(), HORIZONTAL_ALIGNMENT_CENTER, -1, label_font_size)
var label_draw_pos := label_pos - Vector2(label_size.x * 0.5, label_y_offset)
if not is_editing:
if generator.horizontal_label:
label_draw_pos += Vector2(31.0 if is_portal_in() else (-label_size.x - 31.0), 5.0)
else:
label_draw_pos -= Vector2(label_size.x * 0.5, label_y_offset)

draw_string_outline(LABEL_FONT, label_draw_pos, get_link(), HORIZONTAL_ALIGNMENT_CENTER, -1, label_font_size, 5, Color.BLACK)
draw_string(LABEL_FONT, label_draw_pos, get_link(), HORIZONTAL_ALIGNMENT_CENTER, -1, label_font_size, label_color)

Expand Down Expand Up @@ -78,20 +85,30 @@ func _exit_tree() -> void:
func _gui_input(event : InputEvent) -> void:
if event is InputEventMouseButton and event.double_click:
setup_portal_edit()
accept_event()

func _input(event : InputEvent) -> void:
if event is InputEventKey and event.pressed and selected and not is_editing:
if event is InputEventKey and event.pressed and selected:
match event.get_keycode_with_modifiers():
KEY_F2, KEY_ENTER:
if not is_editing:
setup_portal_edit()
KEY_UP, KEY_DOWN:
if is_editing:
accept_event()
KEY_ENTER:
accept_event()
setup_portal_edit()
KEY_R:
generator.horizontal_label = !generator.horizontal_label
queue_redraw()
elif event is InputEventMouseMotion:
const tip : String = "#LMB: Select node, #LMB#LMB/F2/Enter: Rename link, R: Toggle label position"
if Rect2(Vector2.ZERO, size).has_point(get_local_mouse_position()):
mm_globals.set_tip_text(tr("#LMB: Select node, #LMB#LMB/F2/Enter: Rename link"), 1.0, 2)
mm_globals.set_tip_text(tr(tip), 1.0, 2)
elif %Dragger.get_rect().has_point(get_local_mouse_position()):
if is_editing:
mm_globals.set_tip_text(tr("Enter: Rename link, Ctrl/Cmd+Enter: Batch rename links"), 1.0, 2)
else:
mm_globals.set_tip_text(tr("#LMB: Select node, #LMB#LMB: Rename link"), 1.0, 2)
mm_globals.set_tip_text(
tr("Enter: Rename link, Ctrl/Cmd+Enter: Batch rename links" if is_editing else tip))

func _on_dragger_gui_input(event : InputEvent) -> void:
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
Expand Down Expand Up @@ -257,14 +274,19 @@ func replace_links(new_link : String, from_link : String) -> void:
p.on_parameter_changed("link", new_link)

func edit_box_set_position(edit : LineEdit) -> void:
const y_offset : int = 61
var y_offset : float = label_y_offset + 21.0
var g : MMGraphEdit = get_parent()
if g == null:
edit.queue_free()
return
edit.scale = Vector2.ONE * g.zoom
edit.position = graph_node_center(self, g)
edit.position -= Vector2(edit.size.x * 0.5 - 0.5, y_offset) * g.zoom

if generator.horizontal_label:
edit.alignment = HORIZONTAL_ALIGNMENT_LEFT if is_portal_in() else HORIZONTAL_ALIGNMENT_RIGHT
edit.position -= Vector2(-21.0 if is_portal_in() else edit.size.x + 21.0, edit.size.y * 0.5) * g.zoom
else:
edit.position -= Vector2(edit.size.x * 0.5 - 0.5, y_offset) * g.zoom

func setup_portal_edit() -> void:
if is_editing:
Expand All @@ -285,33 +307,56 @@ func setup_portal_edit() -> void:
position_offset_changed.connect(edit_box_set_position.bind(edit))
graph.draw.connect(edit_box_set_position.bind(edit))

edit.modulate = link_collision_warning_color()
var completion_panel : PortalCompletionPanel
if is_portal_out():
completion_panel = preload("res://material_maker/nodes/portal/completion.tscn").instantiate()
completion_panel.portal_edit = edit
completion_panel.selection_updated.connect(edit_box_set_position.bind(edit))
completion_panel.visibility_changed.connect(
func() -> void:
if not generator.horizontal_label:
visible = not completion_panel.visible)
graph.add_child(completion_panel)

edit.modulate = link_collision_warning_color(get_link())

edit.text_submitted.connect(
func(new_text : String) -> void:
if not is_editing:
return

var new_link := new_text.strip_edges()
if not new_link.is_empty() and is_link_unique(new_link):
graph.undoredo.start_group()
on_parameter_changed("link", new_link)
add_link_undoredo(old_link, new_link)
if Input.is_key_pressed(KEY_CTRL) or Input.is_key_pressed(KEY_META):
replace_links(new_link, old_link)
graph.undoredo.end_group()
if not new_link.is_empty():
if is_link_unique(new_link):
graph.undoredo.start_group()
on_parameter_changed("link", new_link)
add_link_undoredo(old_link, new_link)
if Input.is_key_pressed(KEY_CTRL) or Input.is_key_pressed(KEY_META):
replace_links(new_link, old_link)
graph.undoredo.end_group()
else:
on_parameter_changed("link", old_link)
else:
edit.text = old_link
is_editing = false
generator.editable = false
edit.reset_size()
edit.queue_free())
edit.queue_free()
graph.grab_focus()
selected = true
queue_redraw())
edit.text_changed.connect(
func(new_text : String) -> void:
var new_link : String = new_text.strip_edges()
if not new_link.is_empty():
edit.modulate = link_collision_warning_color(new_link)
if completion_panel:
completion_panel.request_completion(new_link)
edit_box_set_position(edit))
edit.focus_exited.connect(func(): edit.text_submitted.emit(edit.text))
edit.tree_exiting.connect(
func() -> void:
show()
position_offset_changed.disconnect(edit_box_set_position)
graph.draw.disconnect(edit_box_set_position))

Expand Down
8 changes: 4 additions & 4 deletions material_maker/nodes/portal/portal.tscn
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[gd_scene load_steps=3 format=3 uid="uid://8ne0p5ahkdw1"]
[gd_scene format=3 uid="uid://8ne0p5ahkdw1"]

[ext_resource type="Script" uid="uid://bqruhogmtlu81" path="res://material_maker/nodes/portal/portal.gd" id="1_qhgt7"]

[sub_resource type="Theme" id="Theme_fybc5"]

[node name="Portal" type="GraphNode"]
[node name="Portal" type="GraphNode" unique_id=97108403]
offset_right = 60.0
offset_bottom = 79.0
theme = SubResource("Theme_fybc5")
Expand All @@ -21,12 +21,12 @@ slot/0/right_icon = null
slot/0/draw_stylebox = true
script = ExtResource("1_qhgt7")

[node name="Control" type="Control" parent="."]
[node name="Control" type="Control" parent="." unique_id=1244434570]
custom_minimum_size = Vector2(24, 24)
layout_mode = 2
mouse_filter = 2

[node name="Dragger" type="Control" parent="Control"]
[node name="Dragger" type="Control" parent="Control" unique_id=467501132]
unique_name_in_owner = true
anchors_preset = 0
offset_right = 40.0
Expand Down
Loading
Loading