From 70f3c3cf6f9c1563d95ffb8c25bf8cd2bb7a1ad0 Mon Sep 17 00:00:00 2001 From: hop311 Date: Tue, 30 Jul 2024 00:02:35 +0100 Subject: Search panel + text edit box UI generation --- game/src/Game/GameSession/GameSession.tscn | 10 +- .../GameSession/MapControlPanel/MapControlPanel.gd | 4 + .../MapControlPanel/MapControlPanel.tscn | 3 +- game/src/Game/GameSession/MapView.gd | 15 ++- game/src/Game/GameSession/SearchPanel.gd | 143 +++++++++++++++++++++ 5 files changed, 170 insertions(+), 5 deletions(-) create mode 100644 game/src/Game/GameSession/SearchPanel.gd (limited to 'game/src/Game') diff --git a/game/src/Game/GameSession/GameSession.tscn b/game/src/Game/GameSession/GameSession.tscn index d54970f..018aad8 100644 --- a/game/src/Game/GameSession/GameSession.tscn +++ b/game/src/Game/GameSession/GameSession.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=19 format=3 uid="uid://bgnupcshe1m7r"] +[gd_scene load_steps=20 format=3 uid="uid://bgnupcshe1m7r"] [ext_resource type="Script" path="res://src/Game/GameSession/GameSession.gd" id="1_eklvp"] [ext_resource type="PackedScene" uid="uid://cvl76duuym1wq" path="res://src/Game/MusicConductor/MusicPlayer.tscn" id="2_kt6aa"] @@ -9,6 +9,7 @@ [ext_resource type="PackedScene" uid="uid://dkehmdnuxih2r" path="res://src/Game/GameSession/MapView.tscn" id="4_xkg5j"] [ext_resource type="Script" path="res://src/Game/GameSession/NationManagementScreen/ProductionMenu.gd" id="5_16755"] [ext_resource type="Script" path="res://src/Game/GameSession/ProvinceOverviewPanel.gd" id="5_lfv8l"] +[ext_resource type="Script" path="res://src/Game/GameSession/SearchPanel.gd" id="5_t260f"] [ext_resource type="PackedScene" uid="uid://cnbfxjy1m6wja" path="res://src/Game/Menu/OptionMenu/OptionsMenu.tscn" id="6_p5mnx"] [ext_resource type="Script" path="res://src/Game/GameSession/NationManagementScreen/BudgetMenu.gd" id="6_vninv"] [ext_resource type="Script" path="res://src/Game/GameSession/NationManagementScreen/TechnologyMenu.gd" id="7_r712c"] @@ -111,6 +112,12 @@ anchor_bottom = 1.0 grow_horizontal = 0 grow_vertical = 0 +[node name="SearchPanel" type="GUINode" parent="UICanvasLayer/UI" node_paths=PackedStringArray("_map_view")] +layout_mode = 1 +anchors_preset = 15 +script = ExtResource("5_t260f") +_map_view = NodePath("../../../MapView") + [node name="GameSessionMenu" parent="UICanvasLayer/UI" instance=ExtResource("3_bvmqh")] visible = false layout_mode = 1 @@ -153,6 +160,7 @@ grow_horizontal = 0 [connection signal="map_view_camera_changed" from="MapView" to="UICanvasLayer/UI/MapControlPanel" method="_on_map_view_camera_changed"] [connection signal="game_session_menu_button_pressed" from="UICanvasLayer/UI/MapControlPanel" to="." method="_on_game_session_menu_button_pressed"] [connection signal="minimap_clicked" from="UICanvasLayer/UI/MapControlPanel" to="MapView" method="_on_minimap_clicked"] +[connection signal="search_button_pressed" from="UICanvasLayer/UI/MapControlPanel" to="UICanvasLayer/UI/SearchPanel" method="toggle_visibility"] [connection signal="zoom_in_button_pressed" from="UICanvasLayer/UI/MapControlPanel" to="MapView" method="zoom_in"] [connection signal="zoom_out_button_pressed" from="UICanvasLayer/UI/MapControlPanel" to="MapView" method="zoom_out"] [connection signal="load_button_pressed" from="UICanvasLayer/UI/GameSessionMenu" to="UICanvasLayer/UI/SaveLoadMenu" method="show_for_load"] diff --git a/game/src/Game/GameSession/MapControlPanel/MapControlPanel.gd b/game/src/Game/GameSession/MapControlPanel/MapControlPanel.gd index eb4dd9f..61de6ae 100644 --- a/game/src/Game/GameSession/MapControlPanel/MapControlPanel.gd +++ b/game/src/Game/GameSession/MapControlPanel/MapControlPanel.gd @@ -1,6 +1,7 @@ extends PanelContainer signal game_session_menu_button_pressed +signal search_button_pressed signal map_view_camera_changed(near_left : Vector2, far_left : Vector2, far_right : Vector2, near_right : Vector2) signal minimap_clicked(pos_clicked : Vector2) signal zoom_in_button_pressed @@ -35,6 +36,9 @@ func _ready() -> void: func _on_game_session_menu_button_pressed() -> void: game_session_menu_button_pressed.emit() +func _on_search_button_pressed() -> void: + search_button_pressed.emit() + # REQUIREMENTS: # * SS-76 # * UIFUN-129, UIFUN-131, UIFUN-133, UIFUN-140, UIFUN-141, UIFUN-142 diff --git a/game/src/Game/GameSession/MapControlPanel/MapControlPanel.tscn b/game/src/Game/GameSession/MapControlPanel/MapControlPanel.tscn index 7578c82..d49cf61 100644 --- a/game/src/Game/GameSession/MapControlPanel/MapControlPanel.tscn +++ b/game/src/Game/GameSession/MapControlPanel/MapControlPanel.tscn @@ -80,7 +80,7 @@ focus_mode = 0 mouse_filter = 1 text = "L" -[node name="FindButton" type="Button" parent="MapPanelMargin/MapPanelList/AuxiliaryPanel"] +[node name="SearchButton" type="Button" parent="MapPanelMargin/MapPanelList/AuxiliaryPanel"] editor_description = "UI-861" layout_mode = 2 focus_mode = 0 @@ -108,5 +108,6 @@ text = "-" [connection signal="map_view_camera_changed" from="." to="MapPanelMargin/MapPanelList/MapDisplayList/Minimap/ViewportQuad" method="_on_map_view_camera_changed"] [connection signal="minimap_clicked" from="MapPanelMargin/MapPanelList/MapDisplayList/Minimap/ViewportQuad" to="." method="_on_minimap_clicked"] [connection signal="pressed" from="MapPanelMargin/MapPanelList/AuxiliaryPanel/GameSessionMenuButton" to="." method="_on_game_session_menu_button_pressed"] +[connection signal="pressed" from="MapPanelMargin/MapPanelList/AuxiliaryPanel/SearchButton" to="." method="_on_search_button_pressed"] [connection signal="pressed" from="MapPanelMargin/MapPanelList/AuxiliaryPanel/ZoomButtonsContainer/ZoomInButton" to="." method="_on_zoom_in_button_pressed"] [connection signal="pressed" from="MapPanelMargin/MapPanelList/AuxiliaryPanel/ZoomButtonsContainer/ZoomOutButton" to="." method="_on_zoom_out_button_pressed"] diff --git a/game/src/Game/GameSession/MapView.gd b/game/src/Game/GameSession/MapView.gd index 01755ec..d77cfe5 100644 --- a/game/src/Game/GameSession/MapView.gd +++ b/game/src/Game/GameSession/MapView.gd @@ -134,18 +134,27 @@ func _map_to_world_coords(pos : Vector2) -> Vector3: pos = pos * _map_mesh_dims + _map_mesh_corner return Vector3(pos.x, 0, pos.y) -func _viewport_to_map_coords(pos_viewport : Vector2) -> Vector2: +func _viewport_to_world_coords(pos_viewport : Vector2) -> Vector3: var ray_origin := _camera.project_ray_origin(pos_viewport) var ray_normal := _camera.project_ray_normal(pos_viewport) # Plane with normal (0,1,0) facing upwards, at a distance 0 from the origin var intersection : Variant = Plane(0, 1, 0, 0).intersects_ray(ray_origin, ray_normal) if typeof(intersection) == TYPE_VECTOR3: - return _world_to_map_coords(intersection as Vector3) + return intersection else: # Normals parallel to the xz-plane could cause null intersections, # but the camera's orientation should prevent such normals push_error("Invalid intersection: ", intersection) - return Vector2(0.5, 0.5) + return _map_to_world_coords(Vector2(0.5, 0.5)) + +func _viewport_to_map_coords(pos_viewport : Vector2) -> Vector2: + return _world_to_map_coords(_viewport_to_world_coords(pos_viewport)) + +func look_at_map_position(pos : Vector2) -> void: + var viewport_centre : Vector2 = Vector2(0.5, 0.5) * _viewport_dims / GuiScale.get_current_guiscale() + var pos_delta : Vector3 = _map_to_world_coords(pos) - _viewport_to_world_coords(viewport_centre) + _camera.position.x += pos_delta.x + _camera.position.z += pos_delta.z func zoom_in() -> void: _zoom_target -= _zoom_target_step diff --git a/game/src/Game/GameSession/SearchPanel.gd b/game/src/Game/GameSession/SearchPanel.gd new file mode 100644 index 0000000..5554226 --- /dev/null +++ b/game/src/Game/GameSession/SearchPanel.gd @@ -0,0 +1,143 @@ +extends GUINode + +@export var _map_view : MapView + +var _search_panel : Panel +var _search_line_edit : LineEdit +var _results_list_box : GUIListBox +var _result_buttons : Array[Button] + +var _drag_active : bool = false +var _drag_anchor : Vector2 + +func _ready() -> void: + MenuSingleton.search_cache_changed.connect(_update_results_base) + + add_gui_element("goto", "goto_box") + + remove_node(^"./goto_box/goto") + + _search_panel = get_panel_from_nodepath(^"./goto_box") + + var close_button : Button = get_button_from_nodepath(^"./goto_box/cancel") + if close_button: + close_button.pressed.connect(hide) + + var panel_button : Button = get_button_from_nodepath(^"./goto_box/goto_box") + if panel_button: + panel_button.button_down.connect(_start_drag) + panel_button.button_up.connect(_end_drag) + if _search_panel: + # Move to back so it's not drawn over the results list + _search_panel.move_child(panel_button, 0) + + _search_line_edit = get_line_edit_from_nodepath(^"./goto_box/goto_edit") + if _search_line_edit: + _search_line_edit.text_changed.connect(_search_string_updated) + # Restrict to desired size (by default it's a bit too tall, probably due to font size) + _search_line_edit.set_size(_search_line_edit.get_minimum_size()) + + _results_list_box = get_gui_listbox_from_nodepath(^"./goto_box/provinces") + if _results_list_box: + _results_list_box.scroll_index_changed.connect(_update_results_scroll) + + _results_list_box.set_position(_results_list_box.get_position() - Vector2(4, 0)) + + hide() + + MenuSingleton.generate_search_cache() + +func toggle_visibility() -> void: + if is_visible(): + hide() + else: + show() + if _search_line_edit: + _search_line_edit.grab_focus() + +func _start_drag() -> void: + if _search_panel: + _drag_anchor = _search_panel.get_position() - get_window().get_mouse_position() + _drag_active = true + +func _end_drag() -> void: + _drag_active = false + +func _input(event : InputEvent) -> void: + if _drag_active and event is InputEventMouseMotion: + _search_panel.set_position(_drag_anchor + get_window().get_mouse_position()) + +func _notification(what : int) -> void: + match what: + NOTIFICATION_TRANSLATION_CHANGED: + MenuSingleton.generate_search_cache() + +func _search_string_updated(search_string : String) -> void: + MenuSingleton.update_search_results(search_string) + _update_results_base() + +func _update_results_base() -> void: + if not _results_list_box: + return + + var result_count : int = MenuSingleton.get_search_result_row_count() + + var result_height : float = 0.0 + if result_count > 0 and (_results_list_box.get_child_count() > 0 or _add_result_button()): + result_height = _results_list_box.get_child(0).get_size().y + + _results_list_box.set_fixed(result_count, result_height, false) + _update_results_scroll() + +func _add_result_button() -> bool: + if not _results_list_box: + return false + + var child : Panel = GUINode.generate_gui_element("menubar", "save_game_entry") + if not child: + return false + + var button : Button = GUINode.get_button_from_node(child.get_node(^"./game")) + if not button: + child.queue_free() + return false + + button.pressed.connect(_result_selected.bind(_result_buttons.size())) + + _results_list_box.add_child(child) + _result_buttons.push_back(button) + + return true + +func _update_results_scroll(scroll_index : int = -1) -> void: + if not _results_list_box: + return + + if scroll_index >= 0: + _results_list_box.set_scroll_index(scroll_index, false) + + scroll_index = _results_list_box.get_scroll_index() + + var results : PackedStringArray = MenuSingleton.get_search_result_rows(scroll_index, _results_list_box.get_fixed_visible_items()) + + if results.size() < _result_buttons.size(): + _result_buttons.resize(results.size()) + _results_list_box.clear_children(results.size()) + else: + while _result_buttons.size() < results.size() and _add_result_button(): + pass # Button is added in the loop condition + + for index : int in min(results.size(), _result_buttons.size()): + _result_buttons[index].set_text(results[index]) + +func _result_selected(index : int) -> void: + if _map_view: + _map_view.look_at_map_position(MenuSingleton.get_search_result_position(index)) + else: + push_error("SearchPanel missing MapView reference!") + + if _search_line_edit: + # This triggers a search results update, preventing further get_search_result_position(index) calls + _search_line_edit.clear() + + hide() -- cgit v1.2.3-56-ga3b1