diff --git a/material_maker/nodes/portal/completion.gd b/material_maker/nodes/portal/completion.gd new file mode 100644 index 000000000..bc46e5ac7 --- /dev/null +++ b/material_maker/nodes/portal/completion.gd @@ -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() diff --git a/material_maker/nodes/portal/completion.gd.uid b/material_maker/nodes/portal/completion.gd.uid new file mode 100644 index 000000000..9633f3964 --- /dev/null +++ b/material_maker/nodes/portal/completion.gd.uid @@ -0,0 +1 @@ +uid://buqmwxkc40t11 diff --git a/material_maker/nodes/portal/completion.tscn b/material_maker/nodes/portal/completion.tscn new file mode 100644 index 000000000..711b4ca4d --- /dev/null +++ b/material_maker/nodes/portal/completion.tscn @@ -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 = " + +" + +[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 diff --git a/material_maker/nodes/portal/portal.gd b/material_maker/nodes/portal/portal.gd index 0116b2bfe..8e6b2d311 100644 --- a/material_maker/nodes/portal/portal.gd +++ b/material_maker/nodes/portal/portal.gd @@ -78,12 +78,19 @@ 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: - setup_portal_edit() + if not is_editing: + setup_portal_edit() + KEY_UP, KEY_DOWN: + if is_editing: + accept_event() + KEY_ENTER: + accept_event() elif event is InputEventMouseMotion: 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) @@ -285,11 +292,21 @@ func setup_portal_edit() -> void: position_offset_changed.connect(edit_box_set_position.bind(edit)) graph.draw.connect(edit_box_set_position.bind(edit)) + 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: 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(): if is_link_unique(new_link): @@ -301,20 +318,28 @@ func setup_portal_edit() -> void: 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 := new_text.strip_edges() if not new_link.is_empty(): on_parameter_changed("link", new_link) 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)) diff --git a/material_maker/nodes/portal/portal.tscn b/material_maker/nodes/portal/portal.tscn index 40b737c09..6e20ec394 100644 --- a/material_maker/nodes/portal/portal.tscn +++ b/material_maker/nodes/portal/portal.tscn @@ -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") @@ -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 diff --git a/material_maker/theme/classic_base.tres b/material_maker/theme/classic_base.tres index 5e759d08f..d90d16687 100644 --- a/material_maker/theme/classic_base.tres +++ b/material_maker/theme/classic_base.tres @@ -219,15 +219,10 @@ content_margin_left = 3.0 content_margin_top = 3.0 content_margin_right = 3.0 content_margin_bottom = 3.0 -draw_center = false -border_width_left = 1 -border_width_top = 1 -border_width_right = 1 -border_width_bottom = 1 -border_color = Color(0.473976, 0.473976, 0.473975, 1) +bg_color = Color(0.234, 0.26970002, 0.36, 1) [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_fbnbn"] -bg_color = Color(0.14902, 0.172549, 0.231373, 1) +bg_color = Color(0.1625, 0.18729167, 0.25, 1) [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_attdh"] content_margin_left = 3.0 @@ -1068,7 +1063,7 @@ ItemList/colors/guide_color = Color(0.701961, 0.701961, 0.701961, 0.129412) ItemList/styles/focus = SubResource("StyleBoxEmpty_v2584") ItemList/styles/hovered = SubResource("StyleBoxFlat_m2221") ItemList/styles/panel = SubResource("StyleBoxFlat_fbnbn") -ItemList/styles/selected = SubResource("StyleBoxFlat_attdh") +ItemList/styles/selected = SubResource("StyleBoxFlat_m2221") ItemList/styles/selected_focus = SubResource("StyleBoxFlat_attdh") Label/colors/font_color = Color(0.8, 0.807843, 0.827451, 1) Label/colors/font_outline_color = Color(0, 0, 0, 0)