From 07c567ea6aa3b9532b365cdd53dccdd6301d3d92 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sat, 27 Jan 2024 13:01:41 +0100 Subject: [PATCH 01/26] Update rotation UI control --- Scenes/ContentManager/Mapeditor/Scripts/GridContainer.gd | 1 - Scenes/ContentManager/Mapeditor/mapeditor.tscn | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Scenes/ContentManager/Mapeditor/Scripts/GridContainer.gd b/Scenes/ContentManager/Mapeditor/Scripts/GridContainer.gd index 723e6012..46ee94d7 100644 --- a/Scenes/ContentManager/Mapeditor/Scripts/GridContainer.gd +++ b/Scenes/ContentManager/Mapeditor/Scripts/GridContainer.gd @@ -456,6 +456,5 @@ func rotate_level_clockwise(): var furniture_rotation = int(new_level_data[new_index].get("furniture").get("rotation", 0)) new_level_data[new_index]["furniture"]["rotation"] = (furniture_rotation + 90) % 360 - # Update the current level data currentLevelData = new_level_data diff --git a/Scenes/ContentManager/Mapeditor/mapeditor.tscn b/Scenes/ContentManager/Mapeditor/mapeditor.tscn index 2eee8025..f7dc8ed9 100644 --- a/Scenes/ContentManager/Mapeditor/mapeditor.tscn +++ b/Scenes/ContentManager/Mapeditor/mapeditor.tscn @@ -86,11 +86,10 @@ theme_override_icons/unchecked = ExtResource("2_bib5l") [node name="RotateMap" type="CheckBox" parent="HSplitContainer/MapeditorContainer/Toolbar"] layout_mode = 2 -tooltip_text = "Rotate the brush to paint with rotation" +tooltip_text = "Rotate the map and all levels in it by 90 degrees clockwise. Tiles and furniture will be rotated" theme_override_icons/checked = ExtResource("3_8q2iq") theme_override_icons/unchecked = ExtResource("3_8q2iq") shortcut = SubResource("Shortcut_1tryc") -text = "0" [node name="ZoomScroller" parent="HSplitContainer/MapeditorContainer/Toolbar" instance=ExtResource("1_0ytmu")] layout_mode = 2 From 806f0fe273f3e6e54eb5667babad2105a7237a0d Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sat, 27 Jan 2024 17:15:15 +0100 Subject: [PATCH 02/26] Basic list implemented --- Scenes/InventoryWindow.tscn | 11 +- Scenes/UI/CtrlInventoryStackedCustom.tscn | 59 ++++++ Scripts/CtrlInventoryStackedCustom.gd | 237 ++++++++++++++++++++++ 3 files changed, 305 insertions(+), 2 deletions(-) create mode 100644 Scenes/UI/CtrlInventoryStackedCustom.tscn create mode 100644 Scripts/CtrlInventoryStackedCustom.gd diff --git a/Scenes/InventoryWindow.tscn b/Scenes/InventoryWindow.tscn index 7397c471..259378f4 100644 --- a/Scenes/InventoryWindow.tscn +++ b/Scenes/InventoryWindow.tscn @@ -1,13 +1,14 @@ -[gd_scene load_steps=14 format=3 uid="uid://e0ebcv1n8jnq"] +[gd_scene load_steps=15 format=3 uid="uid://e0ebcv1n8jnq"] [ext_resource type="Script" path="res://Scripts/InventoryWindow.gd" id="1_7kqbx"] [ext_resource type="PackedScene" uid="uid://crck2fhgayxhn" path="res://Scenes/InventoryContainerListItem.tscn" id="2_xfgb3"] [ext_resource type="Script" path="res://addons/gloot/core/inventory_stacked.gd" id="3_l8xgt"] -[ext_resource type="Resource" uid="uid://clehtt4tyqvdy" path="res://ItemProtosets.tres" id="3_sqsc0"] +[ext_resource type="Resource" uid="uid://cr7u5aveonr7t" path="res://ItemProtosets.tres" id="3_sqsc0"] [ext_resource type="Script" path="res://addons/gloot/core/inventory_item.gd" id="5_qidb6"] [ext_resource type="FontFile" uid="uid://chm7lbcdeyo0h" path="res://Roboto-Bold.ttf" id="6_xpf2l"] [ext_resource type="Script" path="res://addons/gloot/ui/ctrl_item_slot_ex.gd" id="7_kcmi5"] [ext_resource type="Texture2D" uid="uid://dfmrlie57qrbo" path="res://Mods/Core/Items/9mm.png" id="8_0yr0i"] +[ext_resource type="PackedScene" uid="uid://y2iul2r3nysx" path="res://Scenes/UI/CtrlInventoryStackedCustom.tscn" id="8_f75fl"] [ext_resource type="Script" path="res://addons/gloot/ui/ctrl_inventory_stacked.gd" id="9_8a8sx"] [ext_resource type="Texture2D" uid="uid://df2n5aculnj82" path="res://addons/gloot/images/icon_inventory.svg" id="10_6ygdg"] [ext_resource type="Script" path="res://addons/gloot/core/item_ref_slot.gd" id="11_nqptt"] @@ -126,6 +127,7 @@ layout_mode = 2 text = "<-" [node name="CtrlInventoryStacked" type="Control" parent="HBoxContainer"] +visible = false custom_minimum_size = Vector2(300, 400) layout_mode = 2 size_flags_horizontal = 3 @@ -133,6 +135,11 @@ script = ExtResource("9_8a8sx") inventory_path = NodePath("../../InventoryStacked") default_item_icon = ExtResource("10_6ygdg") +[node name="CtrlInventoryStackedCustom" parent="HBoxContainer" node_paths=PackedStringArray("myInventory") instance=ExtResource("8_f75fl")] +layout_mode = 2 +size_flags_horizontal = 3 +myInventory = NodePath("../../InventoryStacked") + [node name="EquipmentSlotList" type="VBoxContainer" parent="HBoxContainer"] custom_minimum_size = Vector2(64, 0) layout_mode = 2 diff --git a/Scenes/UI/CtrlInventoryStackedCustom.tscn b/Scenes/UI/CtrlInventoryStackedCustom.tscn new file mode 100644 index 00000000..159eaedc --- /dev/null +++ b/Scenes/UI/CtrlInventoryStackedCustom.tscn @@ -0,0 +1,59 @@ +[gd_scene load_steps=2 format=3 uid="uid://y2iul2r3nysx"] + +[ext_resource type="Script" path="res://Scripts/CtrlInventoryStackedCustom.gd" id="1_1pahw"] + +[node name="CtrlInventoryStackedCustom" type="Control" node_paths=PackedStringArray("inventoryGrid", "WeightBar", "VolumeBar")] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_1pahw") +inventoryGrid = NodePath("VBoxContainer/InventoryGrid") +WeightBar = NodePath("VBoxContainer/HBoxContainer/WeightBar") +VolumeBar = NodePath("VBoxContainer/HBoxContainer/VolumeBar") + +[node name="ColorRect" type="ColorRect" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0.278431, 0.278431, 0.278431, 1) + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="InventoryGrid" type="GridContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +size_flags_stretch_ratio = 0.95 +columns = 5 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +size_flags_stretch_ratio = 0.05 + +[node name="WeightLabel" type="Label" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Weight:" + +[node name="WeightBar" type="ProgressBar" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="VolumeLabel" type="Label" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Volume:" + +[node name="VolumeBar" type="ProgressBar" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd new file mode 100644 index 00000000..5eb57ac4 --- /dev/null +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -0,0 +1,237 @@ +extends Control + +# This script is intended to be used with CtrlInventoryStackedCustom +# It will display inventory items with their properties in a ItemList displayed as a grid +# The first row in the grid will be the header +# Below the header will be a list it inventory items +# The first column will have the item's icon +# The second column will have the item's name +# The third column will have the item's weight +# The fourth column will have the item's volume +# The fifth column will show if an item is favorited +# Clicking on a header column will sort the grid's items by that column +# There will be variables and functions to keep track of the inventory's weight and volume capacity +# There will be functions to update the weightbar and volumebar when the weight and volume changes +# There will be signals for when items get added and removed and when the list is sorted and cleared +# There will be functions to update the list and to populate the list +# There will be signals for when the inventory reaches capacity and when it is empty +# When the mouse hovers over an item, it will be highlighted +# The user will be able to select items. Selected items will be highlighted also, but in a different color +# There will be signals for when an item is selected and when multiple items are selected +# The user will be able to drag the cursor over items while pressing the left mouse button, this will allow the user to select multiple items +# Items can be dragged from the list to other controls in the interface +# The user will be able to favorite an item in the list by selecting it and pressing F. + + +@export var inventoryGrid: GridContainer +@export var WeightBar: ProgressBar +@export var VolumeBar: ProgressBar +@export var myInventory: InventoryStacked +@export var max_weight: int = 1000 +@export var max_volume: int = 1000 + +var selectedItem: InventoryItem = null +var selectedItems: Array = [] + +signal item_selected(item) +signal items_selected(items) +signal inventory_sorted(column) +signal inventory_updated +signal inventory_reached_capacity +signal inventory_empty + +func _ready(): + populate_inventory_list() + connect_signals() + update_bars() + +var last_hovered_item: Node = null + + +func _process(_delta): + var mouse_pos = get_global_mouse_position() + var hovered_item: Node = null + + # Check each child in the GridContainer + for child in inventoryGrid.get_children(): + if child is Control and child.get_global_rect().has_point(mouse_pos): + hovered_item = child + break + + # Apply highlight effect + if hovered_item and hovered_item != last_hovered_item: + if last_hovered_item: + _remove_highlight(last_hovered_item) + _apply_highlight(hovered_item) + last_hovered_item = hovered_item + elif last_hovered_item and not hovered_item: + # Remove highlight effect when cursor moves away + _remove_highlight(last_hovered_item) + last_hovered_item = null + + +func _apply_highlight(item: Node): + if item is Label: + item.modulate = Color(1, 0.8, 0.8) # Highlight color + +func _remove_highlight(item: Node): + if item is Label: + item.modulate = Color(1, 1, 1) # Default color + + +func connect_signals(): + # Connect each item for selection + for item_index in range(inventoryGrid.get_child_count()): + var child = inventoryGrid.get_child(item_index) + if child is TextureRect or child is Label: + child.connect("gui_input", _on_item_gui_input) + + +# Function to handle GUI input on an item +func _on_item_gui_input(event): + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed: + var item = inventoryGrid.get_selected_item() + # Check if CTRL is held for multiple selections + if Input.is_key_pressed(KEY_CTRL): + # Add or remove from the selection + if item in selectedItems: + selectedItems.erase(item) + else: + selectedItems.append(item) + emit_signal("items_selected", selectedItems) + else: + # Single selection + selectedItem = item + selectedItems = [item] + emit_signal("item_selected", item) + +func populate_inventory_list(): + # Clear current grid + for child in inventoryGrid.get_children(): + child.queue_free() + + # Add header row + add_header_row_to_grid() + + # Add items to grid + for item in myInventory.get_children(): + add_item_to_grid(item) + + +func add_header_row_to_grid(): + # Create header elements and add them to the grid + + # Already given: header for Icon + var header_icon = Label.new() + header_icon.text = "I" + inventoryGrid.add_child(header_icon) + + # Add header for Name + var header_name = Label.new() + header_name.text = "Name" + inventoryGrid.add_child(header_name) + + # Add header for Weight + var header_weight = Label.new() + header_weight.text = "W" + inventoryGrid.add_child(header_weight) + + # Add header for Volume + var header_volume = Label.new() + header_volume.text = "V" + inventoryGrid.add_child(header_volume) + + # Add header for Favorite (If applicable) + var header_favorite = Label.new() + header_favorite.text = "F" + inventoryGrid.add_child(header_favorite) + + + +func add_item_to_grid(item: InventoryItem): + # Add the item icon + var item_icon = TextureRect.new() + item_icon.texture = item.get_texture() + inventoryGrid.add_child(item_icon) + + # Add the item name + var item_name = Label.new() + item_name.text = item.get_title() + inventoryGrid.add_child(item_name) + + # Add the item weight + var item_weight = Label.new() + item_weight.text = str(item.get_property("weight", 0)) + inventoryGrid.add_child(item_weight) + + # Add the item volume + var item_volume = Label.new() + item_volume.text = str(item.get_property("volume", 0)) + inventoryGrid.add_child(item_volume) + + + # Add the item favorite + var item_favorite = Label.new() + item_favorite.text = str(item.get_property("favorite", 0)) + inventoryGrid.add_child(item_favorite) + + # Assign a unique name to each UI element + item_icon.name = "icon_" + str(item.get_name()) + item_name.name = "name_" + str(item.get_name()) + item_weight.name = "weight_" + str(item.get_name()) + item_volume.name = "volume_" + str(item.get_name()) + item_favorite.name = "favorite_" + str(item.get_name()) + + +func update_bars(): + var total_weight = 0 + var total_volume = 0 + for item in myInventory.get_children(): + total_weight += item.get_property("weight", 0) + total_volume += item.get_property("volume", 0) + + WeightBar.value = total_weight + WeightBar.max_value = max_weight + VolumeBar.value = total_volume + VolumeBar.max_value = max_volume + + _check_inventory_capacity() + +func _check_inventory_capacity(): + var is_full = WeightBar.value >= WeightBar.max_value or VolumeBar.value >= VolumeBar.max_value + var is_empty = myInventory.get_child_count() == 0 + emit_signal("inventory_updated") + if is_full: + emit_signal("inventory_reached_capacity") + if is_empty: + emit_signal("inventory_empty") + + +func sort_inventory_by_property(property_name: String): + # Create an array of items with additional data for sorting + var items_with_data = [] + for item in myInventory.get_children(): + var prop_value = item.get_property(property_name, null) + items_with_data.append({ + "item": item, + "sort_value": prop_value + }) + + # Sort the array based on the property value + items_with_data.sort_custom(_sort_items) + + # Clear and repopulate the grid with sorted items + inventoryGrid.queue_free_children() + add_header_row_to_grid() + for item_data in items_with_data: + add_item_to_grid(item_data["item"]) + + emit_signal("inventory_sorted", property_name) + +func _sort_items(a, b): + var value_a = a["sort_value"] + var value_b = b["sort_value"] + if typeof(value_a) == TYPE_STRING: + return value_a.nocasecmp_to(value_b) < 0 + else: + return value_a < value_b From a29e7b2230d0dfbb14eb72dea61f4c110aedefdd Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sat, 27 Jan 2024 18:50:32 +0100 Subject: [PATCH 03/26] Layout, highlighting --- Scenes/InventoryWindow.tscn | 13 ++- Scenes/UI/CtrlInventoryStackedCustom.tscn | 8 +- Scenes/UI/CtrlInventoryStackedListItem.tscn | 42 +++++++++ Scripts/CtrlInventoryStackedCustom.gd | 47 +++++++--- Scripts/CtrlInventoryStackedListItem.gd | 97 +++++++++++++++++++++ 5 files changed, 189 insertions(+), 18 deletions(-) create mode 100644 Scenes/UI/CtrlInventoryStackedListItem.tscn create mode 100644 Scripts/CtrlInventoryStackedListItem.gd diff --git a/Scenes/InventoryWindow.tscn b/Scenes/InventoryWindow.tscn index 259378f4..c1a91c8b 100644 --- a/Scenes/InventoryWindow.tscn +++ b/Scenes/InventoryWindow.tscn @@ -61,25 +61,25 @@ script = ExtResource("5_qidb6") protoset = ExtResource("3_sqsc0") prototype_id = "bullet_9mm" -[node name="_Node_23288" type="Node" parent="InventoryStacked"] +[node name="_Node_211710" type="Node" parent="InventoryStacked"] script = ExtResource("5_qidb6") protoset = ExtResource("3_sqsc0") prototype_id = "pistol_magazine" -[node name="_Node_23298" type="Node" parent="InventoryStacked"] +[node name="_Node_211729" type="Node" parent="InventoryStacked"] script = ExtResource("5_qidb6") protoset = ExtResource("3_sqsc0") -prototype_id = "rifle_m4a1" +prototype_id = "pistol_9mm" -[node name="_Node_23311" type="Node" parent="InventoryStacked"] +[node name="_Node_211748" type="Node" parent="InventoryStacked"] script = ExtResource("5_qidb6") protoset = ExtResource("3_sqsc0") prototype_id = "pistol_9mm" -[node name="_Node_65384" type="Node" parent="InventoryStacked"] +[node name="_Node_211767" type="Node" parent="InventoryStacked"] script = ExtResource("5_qidb6") protoset = ExtResource("3_sqsc0") -prototype_id = "pistol_9mm" +prototype_id = "rifle_m4a1" [node name="InventoryStackedProx" type="Node" parent="."] script = ExtResource("3_l8xgt") @@ -137,7 +137,6 @@ default_item_icon = ExtResource("10_6ygdg") [node name="CtrlInventoryStackedCustom" parent="HBoxContainer" node_paths=PackedStringArray("myInventory") instance=ExtResource("8_f75fl")] layout_mode = 2 -size_flags_horizontal = 3 myInventory = NodePath("../../InventoryStacked") [node name="EquipmentSlotList" type="VBoxContainer" parent="HBoxContainer"] diff --git a/Scenes/UI/CtrlInventoryStackedCustom.tscn b/Scenes/UI/CtrlInventoryStackedCustom.tscn index 159eaedc..d205ab70 100644 --- a/Scenes/UI/CtrlInventoryStackedCustom.tscn +++ b/Scenes/UI/CtrlInventoryStackedCustom.tscn @@ -1,6 +1,7 @@ -[gd_scene load_steps=2 format=3 uid="uid://y2iul2r3nysx"] +[gd_scene load_steps=3 format=3 uid="uid://y2iul2r3nysx"] [ext_resource type="Script" path="res://Scripts/CtrlInventoryStackedCustom.gd" id="1_1pahw"] +[ext_resource type="PackedScene" uid="uid://bgnxsnv6ltej8" path="res://Scenes/UI/CtrlInventoryStackedListItem.tscn" id="2_woew4"] [node name="CtrlInventoryStackedCustom" type="Control" node_paths=PackedStringArray("inventoryGrid", "WeightBar", "VolumeBar")] layout_mode = 3 @@ -9,10 +10,13 @@ anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 script = ExtResource("1_1pahw") inventoryGrid = NodePath("VBoxContainer/InventoryGrid") WeightBar = NodePath("VBoxContainer/HBoxContainer/WeightBar") VolumeBar = NodePath("VBoxContainer/HBoxContainer/VolumeBar") +listItemContainer = ExtResource("2_woew4") [node name="ColorRect" type="ColorRect" parent="."] layout_mode = 1 @@ -35,6 +39,8 @@ grow_vertical = 2 layout_mode = 2 size_flags_vertical = 3 size_flags_stretch_ratio = 0.95 +theme_override_constants/h_separation = 0 +theme_override_constants/v_separation = 0 columns = 5 [node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] diff --git a/Scenes/UI/CtrlInventoryStackedListItem.tscn b/Scenes/UI/CtrlInventoryStackedListItem.tscn new file mode 100644 index 00000000..f365f331 --- /dev/null +++ b/Scenes/UI/CtrlInventoryStackedListItem.tscn @@ -0,0 +1,42 @@ +[gd_scene load_steps=2 format=3 uid="uid://bgnxsnv6ltej8"] + +[ext_resource type="Script" path="res://Scripts/CtrlInventoryStackedListItem.gd" id="1_1qim3"] + +[node name="CtrlInventoryStackedListItem" type="Control" node_paths=PackedStringArray("myBackgroundRect", "myLabel", "myIcon")] +custom_minimum_size = Vector2(50, 24) +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_1qim3") +myBackgroundRect = NodePath("ColorRect") +myLabel = NodePath("HBoxContainer/Label") +myIcon = NodePath("HBoxContainer/TextureRect") + +[node name="ColorRect" type="ColorRect" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0.454902, 0.454902, 0.454902, 1) + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="TextureRect" type="TextureRect" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +expand_mode = 2 + +[node name="Label" type="Label" parent="HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index 5eb57ac4..23f2a2f9 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -29,6 +29,7 @@ extends Control @export var myInventory: InventoryStacked @export var max_weight: int = 1000 @export var max_volume: int = 1000 +@export var listItemContainer: PackedScene var selectedItem: InventoryItem = null var selectedItems: Array = [] @@ -148,39 +149,65 @@ func add_header_row_to_grid(): +# Function to handle item click +func _on_item_clicked(clickedItem: Control): + # Logic to handle item click, e.g., marking as selected + if clickedItem.is_item_selected(): + clickedItem.unselect_item() + selectedItems.erase(clickedItem) + else: + clickedItem.select_item() + selectedItems.append(clickedItem) + # Optional: unselect other items if only one item should be selected at a time + for child in inventoryGrid.get_children(): + if child is Control and child != clickedItem: + child.unselect_item() + selectedItems.erase(child) + + # Emit signals based on selection + if selectedItems.size() == 1: + emit_signal("item_selected", selectedItems[0]) + elif selectedItems.size() > 1: + emit_signal("items_selected", selectedItems) + + func add_item_to_grid(item: InventoryItem): # Add the item icon - var item_icon = TextureRect.new() - item_icon.texture = item.get_texture() + var item_icon = listItemContainer.instantiate() as Control + item_icon.set_icon(item.get_texture()) inventoryGrid.add_child(item_icon) + item_icon.connect("item_clicked", _on_item_clicked) # Add the item name - var item_name = Label.new() - item_name.text = item.get_title() + var item_name = listItemContainer.instantiate() as Control + item_name.set_label_text(item.get_title()) inventoryGrid.add_child(item_name) + item_name.connect("item_clicked", _on_item_clicked) # Add the item weight - var item_weight = Label.new() - item_weight.text = str(item.get_property("weight", 0)) + var item_weight = listItemContainer.instantiate() as Control + item_weight.set_label_text(str(item.get_property("weight", 0))) inventoryGrid.add_child(item_weight) # Add the item volume - var item_volume = Label.new() - item_volume.text = str(item.get_property("volume", 0)) + var item_volume = listItemContainer.instantiate() as Control + item_volume.set_label_text(str(item.get_property("volume", 0))) inventoryGrid.add_child(item_volume) # Add the item favorite - var item_favorite = Label.new() - item_favorite.text = str(item.get_property("favorite", 0)) + var item_favorite = listItemContainer.instantiate() as Control + item_favorite.set_label_text(str(item.get_property("favorite", 0))) inventoryGrid.add_child(item_favorite) # Assign a unique name to each UI element item_icon.name = "icon_" + str(item.get_name()) + item_icon.adjust_size() item_name.name = "name_" + str(item.get_name()) item_weight.name = "weight_" + str(item.get_name()) item_volume.name = "volume_" + str(item.get_name()) item_favorite.name = "favorite_" + str(item.get_name()) + item_name.size_flags_horizontal = Control.SIZE_EXPAND_FILL func update_bars(): diff --git a/Scripts/CtrlInventoryStackedListItem.gd b/Scripts/CtrlInventoryStackedListItem.gd new file mode 100644 index 00000000..5b83970b --- /dev/null +++ b/Scripts/CtrlInventoryStackedListItem.gd @@ -0,0 +1,97 @@ +extends Control + + +# This script is intended to be used by the CtrlInventoryStackedListItem +# It is meant to be a container for control nodes that allow the inventory +# to be represented visually +# When the mouse cursor hover over this item, it will change color +# When this item is clicked, it will change color to indicate it is selected +# When this item is clicked, it will emit a signal that it is clicked +# There will be a function that returns if this item is selected + + +@export var myBackgroundRect: ColorRect +@export var myLabel: Label +@export var myIcon: TextureRect + +# Colors for different states +var default_color: Color = Color(0.4, 0.4, 0.4, 1) # Default color +var hover_color: Color = Color(0.8, 0.8, 0.8, 1) # Hover color +var selected_color: Color = Color(0.5, 0.5, 0.8, 1) # Selected color + +var is_selected: bool = false + +signal item_clicked(item) + +# Called when the node enters the scene tree for the first time. +func _ready(): + myBackgroundRect.color = default_color + set_process_unhandled_input(true) + connect("mouse_entered", _on_mouse_entered) + connect("mouse_exited", _on_mouse_exited) + +func _unhandled_input(event): + if event is InputEventMouse: + if get_global_rect().has_point(event.global_position): + if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: + _select_item() + else: + if not is_selected: + myBackgroundRect.color = default_color + +func _select_item(): + is_selected = true + myBackgroundRect.color = selected_color + emit_signal("item_clicked", self) + +func is_item_selected() -> bool: + return is_selected + +func unselect_item(): + is_selected = false + myBackgroundRect.color = default_color + +func _on_mouse_entered(): + if not is_selected: + myBackgroundRect.color = hover_color + +func _on_mouse_exited(): + if not is_selected: + myBackgroundRect.color = default_color + +# Function to set the text of the label. This hides the icon and shows the label. +func set_label_text(text: String): + myLabel.text = text + myLabel.visible = true + myIcon.visible = false + +# Function to get the text of the label. +func get_label_text() -> String: + return myLabel.text + +# Function to set the icon. This hides the label and shows the icon. +func set_icon(texture: Texture): + myIcon.texture = texture + myIcon.visible = true + myLabel.visible = false + +# Function to get the icon's texture. +func get_icon() -> Texture: + return myIcon.texture + +# Adjusts the size of the item based on its content +func adjust_size(): + var content_width = 0 + var content_height = 0 + + # Calculate size based on visible content (label or icon) + if myLabel.visible: + content_width = myLabel.get_minimum_size().x + content_height = myLabel.get_minimum_size().y + + # Check if the icon is visible and has a texture + if myIcon.visible and myIcon.texture: + custom_minimum_size = Vector2(32,32) + + # Set the size of the background rectangle to fit the content + myBackgroundRect.custom_minimum_size = Vector2(content_width, content_height) From 1654fe877478b38e577fa7ccc748f60151894405 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sat, 27 Jan 2024 19:02:29 +0100 Subject: [PATCH 04/26] The entire row is highlighted --- Scripts/CtrlInventoryStackedCustom.gd | 35 ++++++++++++++++++++----- Scripts/CtrlInventoryStackedListItem.gd | 25 +++++------------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index 23f2a2f9..e12ff51c 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -70,14 +70,25 @@ func _process(_delta): _remove_highlight(last_hovered_item) last_hovered_item = null - func _apply_highlight(item: Node): - if item is Label: - item.modulate = Color(1, 0.8, 0.8) # Highlight color + if item is Control: + var group_name = _get_group_name(item) + for group_item in get_tree().get_nodes_in_group(group_name): + if group_item is Control: + group_item.highlight() func _remove_highlight(item: Node): - if item is Label: - item.modulate = Color(1, 1, 1) # Default color + if item is Control: + var group_name = _get_group_name(item) + for group_item in get_tree().get_nodes_in_group(group_name): + if group_item is Control: + group_item.unhighlight() + +func _get_group_name(item: Control) -> String: + for group in item.get_groups(): + if group.begins_with("item_group_"): + return group + return "" func connect_signals(): @@ -172,42 +183,52 @@ func _on_item_clicked(clickedItem: Control): func add_item_to_grid(item: InventoryItem): + # Define a unique group name for this set of items + var group_name = "item_group_" + str(item.get_name()) + # Add the item icon var item_icon = listItemContainer.instantiate() as Control item_icon.set_icon(item.get_texture()) inventoryGrid.add_child(item_icon) item_icon.connect("item_clicked", _on_item_clicked) + item_icon.add_to_group(group_name) # Add the item name var item_name = listItemContainer.instantiate() as Control item_name.set_label_text(item.get_title()) inventoryGrid.add_child(item_name) item_name.connect("item_clicked", _on_item_clicked) + item_name.add_to_group(group_name) # Add the item weight var item_weight = listItemContainer.instantiate() as Control item_weight.set_label_text(str(item.get_property("weight", 0))) inventoryGrid.add_child(item_weight) + item_weight.connect("item_clicked", _on_item_clicked) + item_weight.add_to_group(group_name) # Add the item volume var item_volume = listItemContainer.instantiate() as Control item_volume.set_label_text(str(item.get_property("volume", 0))) inventoryGrid.add_child(item_volume) + item_volume.connect("item_clicked", _on_item_clicked) + item_volume.add_to_group(group_name) - # Add the item favorite var item_favorite = listItemContainer.instantiate() as Control item_favorite.set_label_text(str(item.get_property("favorite", 0))) inventoryGrid.add_child(item_favorite) + item_favorite.connect("item_clicked", _on_item_clicked) + item_favorite.add_to_group(group_name) # Assign a unique name to each UI element item_icon.name = "icon_" + str(item.get_name()) - item_icon.adjust_size() item_name.name = "name_" + str(item.get_name()) item_weight.name = "weight_" + str(item.get_name()) item_volume.name = "volume_" + str(item.get_name()) item_favorite.name = "favorite_" + str(item.get_name()) item_name.size_flags_horizontal = Control.SIZE_EXPAND_FILL + item_icon.custom_minimum_size = Vector2(32,32) func update_bars(): diff --git a/Scripts/CtrlInventoryStackedListItem.gd b/Scripts/CtrlInventoryStackedListItem.gd index 5b83970b..01c44607 100644 --- a/Scripts/CtrlInventoryStackedListItem.gd +++ b/Scripts/CtrlInventoryStackedListItem.gd @@ -52,10 +52,16 @@ func unselect_item(): myBackgroundRect.color = default_color func _on_mouse_entered(): + highlight() + +func _on_mouse_exited(): + unhighlight() + +func highlight(): if not is_selected: myBackgroundRect.color = hover_color -func _on_mouse_exited(): +func unhighlight(): if not is_selected: myBackgroundRect.color = default_color @@ -78,20 +84,3 @@ func set_icon(texture: Texture): # Function to get the icon's texture. func get_icon() -> Texture: return myIcon.texture - -# Adjusts the size of the item based on its content -func adjust_size(): - var content_width = 0 - var content_height = 0 - - # Calculate size based on visible content (label or icon) - if myLabel.visible: - content_width = myLabel.get_minimum_size().x - content_height = myLabel.get_minimum_size().y - - # Check if the icon is visible and has a texture - if myIcon.visible and myIcon.texture: - custom_minimum_size = Vector2(32,32) - - # Set the size of the background rectangle to fit the content - myBackgroundRect.custom_minimum_size = Vector2(content_width, content_height) From ea06c0d1d56085a226c59a28d45619e30ddb31d2 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sat, 27 Jan 2024 19:41:18 +0100 Subject: [PATCH 05/26] Item selection works --- Scenes/UI/CtrlInventoryStackedListItem.tscn | 2 + Scripts/CtrlInventoryStackedCustom.gd | 70 ++++++++++++++++----- Scripts/CtrlInventoryStackedListItem.gd | 29 +++++---- 3 files changed, 75 insertions(+), 26 deletions(-) diff --git a/Scenes/UI/CtrlInventoryStackedListItem.tscn b/Scenes/UI/CtrlInventoryStackedListItem.tscn index f365f331..b9d65bee 100644 --- a/Scenes/UI/CtrlInventoryStackedListItem.tscn +++ b/Scenes/UI/CtrlInventoryStackedListItem.tscn @@ -40,3 +40,5 @@ expand_mode = 2 [node name="Label" type="Label" parent="HBoxContainer"] layout_mode = 2 size_flags_horizontal = 3 + +[connection signal="gui_input" from="." to="." method="_on_gui_input"] diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index e12ff51c..4e7ebf6b 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -158,22 +158,55 @@ func add_header_row_to_grid(): header_favorite.text = "F" inventoryGrid.add_child(header_favorite) - - -# Function to handle item click -func _on_item_clicked(clickedItem: Control): - # Logic to handle item click, e.g., marking as selected +# +# +## Function to handle item click +#func _on_item_clicked(clickedItem: Control, ctrl_pressed: bool): + ## Logic to handle item click, e.g., marking as selected + #if clickedItem.is_item_selected(): + ## The item was just selected + #if ctrl_pressed: + ## Control was pressed, so add it to the selected items list + #selectedItems.append(clickedItem) + #else: + ## Control was not pressed, so this should be the only selected item + #clickedItem.select_item() + #else: + ## The item was just de-selected + ## If the control key was held, the other selected items should remain selected + ## If the control key was not held, de-select all items and re-select the cliked item + #clickedItem.select_item() +# + ## Emit signals based on selection + #if selectedItems.size() == 1: + #emit_signal("item_selected", selectedItems[0]) + #elif selectedItems.size() > 1: + #emit_signal("items_selected", selectedItems) +# + +func _on_item_clicked(clickedItem: Control, ctrl_pressed: bool): + # Check if the item is already selected if clickedItem.is_item_selected(): - clickedItem.unselect_item() - selectedItems.erase(clickedItem) + # The item was just selected + if ctrl_pressed: + # Control was pressed, so add it to the selected items list + selectedItems.append(clickedItem) + else: + selectedItems.append(clickedItem) + # If control is not pressed, deselect other items + _deselect_all_except(clickedItem) else: - clickedItem.select_item() - selectedItems.append(clickedItem) - # Optional: unselect other items if only one item should be selected at a time - for child in inventoryGrid.get_children(): - if child is Control and child != clickedItem: - child.unselect_item() - selectedItems.erase(child) + # Item was de-selected + if ctrl_pressed: + # the control key was held, the other selected items should remain selected + selectedItems.erase(clickedItem) + else: + if clickedItem in selectedItems: + selectedItems.erase(clickedItem) + else: + # If control is not pressed, clear other selections and select this one + _deselect_all_except(clickedItem) + clickedItem.select_item() # Emit signals based on selection if selectedItems.size() == 1: @@ -181,6 +214,15 @@ func _on_item_clicked(clickedItem: Control): elif selectedItems.size() > 1: emit_signal("items_selected", selectedItems) +func _deselect_all_except(except_item: Control): + for item in selectedItems: + if item != except_item: + item.unselect_item() + selectedItems.clear() + selectedItems = [except_item] + + + func add_item_to_grid(item: InventoryItem): # Define a unique group name for this set of items diff --git a/Scripts/CtrlInventoryStackedListItem.gd b/Scripts/CtrlInventoryStackedListItem.gd index 01c44607..183878c5 100644 --- a/Scripts/CtrlInventoryStackedListItem.gd +++ b/Scripts/CtrlInventoryStackedListItem.gd @@ -21,7 +21,7 @@ var selected_color: Color = Color(0.5, 0.5, 0.8, 1) # Selected color var is_selected: bool = false -signal item_clicked(item) +signal item_clicked(item: Control, ctrl_pressed: bool) # Called when the node enters the scene tree for the first time. func _ready(): @@ -30,19 +30,9 @@ func _ready(): connect("mouse_entered", _on_mouse_entered) connect("mouse_exited", _on_mouse_exited) -func _unhandled_input(event): - if event is InputEventMouse: - if get_global_rect().has_point(event.global_position): - if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: - _select_item() - else: - if not is_selected: - myBackgroundRect.color = default_color - -func _select_item(): +func select_item(): is_selected = true myBackgroundRect.color = selected_color - emit_signal("item_clicked", self) func is_item_selected() -> bool: return is_selected @@ -84,3 +74,18 @@ func set_icon(texture: Texture): # Function to get the icon's texture. func get_icon() -> Texture: return myIcon.texture + + +func _on_gui_input(event): + if event is InputEventMouseButton: + match event.button_index: + MOUSE_BUTTON_LEFT: + if event.pressed: + if is_selected: + unselect_item() + else: + select_item() + if Input.is_key_pressed(KEY_CTRL): + item_clicked.emit(self, true) + else: + item_clicked.emit(self, false) From d7053812abc90972726176d0c24fc91ad3a6d6af Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sat, 27 Jan 2024 20:29:38 +0100 Subject: [PATCH 06/26] Now only rows are selected --- Scripts/CtrlInventoryStackedCustom.gd | 137 +++++++++++++++--------- Scripts/CtrlInventoryStackedListItem.gd | 7 +- 2 files changed, 86 insertions(+), 58 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index 4e7ebf6b..bbac8fea 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -33,6 +33,7 @@ extends Control var selectedItem: InventoryItem = null var selectedItems: Array = [] +var last_selected_item: Control = null signal item_selected(item) signal items_selected(items) @@ -158,61 +159,91 @@ func add_header_row_to_grid(): header_favorite.text = "F" inventoryGrid.add_child(header_favorite) -# -# -## Function to handle item click -#func _on_item_clicked(clickedItem: Control, ctrl_pressed: bool): - ## Logic to handle item click, e.g., marking as selected - #if clickedItem.is_item_selected(): - ## The item was just selected - #if ctrl_pressed: - ## Control was pressed, so add it to the selected items list - #selectedItems.append(clickedItem) - #else: - ## Control was not pressed, so this should be the only selected item - #clickedItem.select_item() - #else: - ## The item was just de-selected - ## If the control key was held, the other selected items should remain selected - ## If the control key was not held, de-select all items and re-select the cliked item - #clickedItem.select_item() -# - ## Emit signals based on selection - #if selectedItems.size() == 1: - #emit_signal("item_selected", selectedItems[0]) - #elif selectedItems.size() > 1: - #emit_signal("items_selected", selectedItems) -# - -func _on_item_clicked(clickedItem: Control, ctrl_pressed: bool): - # Check if the item is already selected - if clickedItem.is_item_selected(): - # The item was just selected - if ctrl_pressed: - # Control was pressed, so add it to the selected items list - selectedItems.append(clickedItem) - else: - selectedItems.append(clickedItem) - # If control is not pressed, deselect other items - _deselect_all_except(clickedItem) + + +func _on_item_clicked(clickedItem: Control): + var group_name = _get_group_name(clickedItem) + if Input.is_key_pressed(KEY_CTRL): + # Toggle the entire group selection + _toggle_group_selection(group_name, not _is_group_selected(group_name)) + elif Input.is_key_pressed(KEY_SHIFT) and last_selected_item: + # Select a range of items (handled as before) + _select_range(last_selected_item, clickedItem) else: - # Item was de-selected - if ctrl_pressed: - # the control key was held, the other selected items should remain selected - selectedItems.erase(clickedItem) - else: - if clickedItem in selectedItems: - selectedItems.erase(clickedItem) + # Select only the clicked group + for selected_group in selectedItems.duplicate(): + _toggle_group_selection(selected_group, false) + _toggle_group_selection(group_name, true) + + # Update last selected item + last_selected_item = clickedItem + +func _toggle_group_selection(group_name: String, select: bool): + for group_item in get_tree().get_nodes_in_group(group_name): + if group_item is Control: + if select: + group_item.select_item() else: - # If control is not pressed, clear other selections and select this one - _deselect_all_except(clickedItem) - clickedItem.select_item() - - # Emit signals based on selection - if selectedItems.size() == 1: - emit_signal("item_selected", selectedItems[0]) - elif selectedItems.size() > 1: - emit_signal("items_selected", selectedItems) + group_item.unselect_item() + if select: + selectedItems.append(group_name) + else: + selectedItems.erase(group_name) + +func _is_group_selected(group_name: String) -> bool: + for group_item in get_tree().get_nodes_in_group(group_name): + if group_item is Control and not group_item.is_item_selected(): + return false + return true + + + + + + + +func _select_row_items(item: Control): + var group_name = _get_group_name(item) + for group_item in get_tree().get_nodes_in_group(group_name): + if group_item is Control and not group_item.is_item_selected(): + group_item.select_item() + + +func _select_range(start_item: Control, end_item: Control): + var start_group_name = _get_group_name(start_item) + var end_group_name = _get_group_name(end_item) + + var start_index = _find_group_start_index(start_group_name) + var end_index = _find_group_start_index(end_group_name) + + var min_index = min(start_index, end_index) + var max_index = max(start_index, end_index) + + # Iterate through the grid and select groups within the range + for i in range(min_index, max_index + 1): + var item = inventoryGrid.get_child(i) + if item: + var group_name = _get_group_name(item) + _toggle_group_selection(group_name, true) + +# Find the index of the first item in a group +func _find_group_start_index(group_name: String) -> int: + for i in range(inventoryGrid.get_child_count()): + var item = inventoryGrid.get_child(i) + if item and _get_group_name(item) == group_name: + return i + return -1 + + + + +func _find_child_index(item: Control) -> int: + for i in range(inventoryGrid.get_child_count()): + if inventoryGrid.get_child(i) == item: + return i + return -1 + + func _deselect_all_except(except_item: Control): for item in selectedItems: diff --git a/Scripts/CtrlInventoryStackedListItem.gd b/Scripts/CtrlInventoryStackedListItem.gd index 183878c5..819a8161 100644 --- a/Scripts/CtrlInventoryStackedListItem.gd +++ b/Scripts/CtrlInventoryStackedListItem.gd @@ -21,7 +21,7 @@ var selected_color: Color = Color(0.5, 0.5, 0.8, 1) # Selected color var is_selected: bool = false -signal item_clicked(item: Control, ctrl_pressed: bool) +signal item_clicked(item: Control) # Called when the node enters the scene tree for the first time. func _ready(): @@ -85,7 +85,4 @@ func _on_gui_input(event): unselect_item() else: select_item() - if Input.is_key_pressed(KEY_CTRL): - item_clicked.emit(self, true) - else: - item_clicked.emit(self, false) + item_clicked.emit(self) From e1d8b2000f698ff70b786ce24481538c73b99d04 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sat, 27 Jan 2024 20:50:54 +0100 Subject: [PATCH 07/26] Add headers --- Scenes/UI/CtrlInventoryStackedCustom.tscn | 4 +- .../CtrlInventoryStackedlistHeaderItem.tscn | 36 ++++++++++ Scripts/CtrlInventoryStackedCustom.gd | 40 ++++++++--- Scripts/CtrlInventoryStackedlistHeaderItem.gd | 72 +++++++++++++++++++ 4 files changed, 141 insertions(+), 11 deletions(-) create mode 100644 Scenes/UI/CtrlInventoryStackedlistHeaderItem.tscn create mode 100644 Scripts/CtrlInventoryStackedlistHeaderItem.gd diff --git a/Scenes/UI/CtrlInventoryStackedCustom.tscn b/Scenes/UI/CtrlInventoryStackedCustom.tscn index d205ab70..d6d0433b 100644 --- a/Scenes/UI/CtrlInventoryStackedCustom.tscn +++ b/Scenes/UI/CtrlInventoryStackedCustom.tscn @@ -1,7 +1,8 @@ -[gd_scene load_steps=3 format=3 uid="uid://y2iul2r3nysx"] +[gd_scene load_steps=4 format=3 uid="uid://y2iul2r3nysx"] [ext_resource type="Script" path="res://Scripts/CtrlInventoryStackedCustom.gd" id="1_1pahw"] [ext_resource type="PackedScene" uid="uid://bgnxsnv6ltej8" path="res://Scenes/UI/CtrlInventoryStackedListItem.tscn" id="2_woew4"] +[ext_resource type="PackedScene" uid="uid://dxgl4vkc313we" path="res://Scenes/UI/CtrlInventoryStackedlistHeaderItem.tscn" id="3_svicc"] [node name="CtrlInventoryStackedCustom" type="Control" node_paths=PackedStringArray("inventoryGrid", "WeightBar", "VolumeBar")] layout_mode = 3 @@ -17,6 +18,7 @@ inventoryGrid = NodePath("VBoxContainer/InventoryGrid") WeightBar = NodePath("VBoxContainer/HBoxContainer/WeightBar") VolumeBar = NodePath("VBoxContainer/HBoxContainer/VolumeBar") listItemContainer = ExtResource("2_woew4") +listHeaderContainer = ExtResource("3_svicc") [node name="ColorRect" type="ColorRect" parent="."] layout_mode = 1 diff --git a/Scenes/UI/CtrlInventoryStackedlistHeaderItem.tscn b/Scenes/UI/CtrlInventoryStackedlistHeaderItem.tscn new file mode 100644 index 00000000..86909e15 --- /dev/null +++ b/Scenes/UI/CtrlInventoryStackedlistHeaderItem.tscn @@ -0,0 +1,36 @@ +[gd_scene load_steps=2 format=3 uid="uid://dxgl4vkc313we"] + +[ext_resource type="Script" path="res://Scripts/CtrlInventoryStackedlistHeaderItem.gd" id="1_obkif"] + +[node name="CtrlInventoryStackedHeaderItem" type="Control" node_paths=PackedStringArray("myBackgroundRect", "myLabel")] +custom_minimum_size = Vector2(50, 24) +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_obkif") +myBackgroundRect = NodePath("ColorRect") +myLabel = NodePath("Label") + +[node name="ColorRect" type="ColorRect" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0.454902, 0.454902, 0.454902, 1) + +[node name="Label" type="Label" parent="."] +layout_mode = 1 +anchors_preset = -1 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +text = "wadawd" + +[connection signal="gui_input" from="ColorRect" to="." method="_on_gui_input"] diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index bbac8fea..d4b0bb4e 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -30,6 +30,7 @@ extends Control @export var max_weight: int = 1000 @export var max_volume: int = 1000 @export var listItemContainer: PackedScene +@export var listHeaderContainer: PackedScene var selectedItem: InventoryItem = null var selectedItems: Array = [] @@ -135,29 +136,34 @@ func add_header_row_to_grid(): # Create header elements and add them to the grid # Already given: header for Icon - var header_icon = Label.new() - header_icon.text = "I" + var header_icon = listHeaderContainer.instantiate() as Control + header_icon.set_label_text("I") inventoryGrid.add_child(header_icon) + header_icon.connect("header_clicked", _on_header_clicked) # Add header for Name - var header_name = Label.new() - header_name.text = "Name" + var header_name = listHeaderContainer.instantiate() as Control + header_name.set_label_text("Name") inventoryGrid.add_child(header_name) + header_name.connect("header_clicked", _on_header_clicked) # Add header for Weight - var header_weight = Label.new() - header_weight.text = "W" + var header_weight = listHeaderContainer.instantiate() as Control + header_weight.set_label_text("W") inventoryGrid.add_child(header_weight) + header_weight.connect("header_clicked", _on_header_clicked) # Add header for Volume - var header_volume = Label.new() - header_volume.text = "V" + var header_volume = listHeaderContainer.instantiate() as Control + header_volume.set_label_text("V") inventoryGrid.add_child(header_volume) + header_volume.connect("header_clicked", _on_header_clicked) # Add header for Favorite (If applicable) - var header_favorite = Label.new() - header_favorite.text = "F" + var header_favorite = listHeaderContainer.instantiate() as Control + header_favorite.set_label_text("F") inventoryGrid.add_child(header_favorite) + header_favorite.connect("header_clicked", _on_header_clicked) @@ -356,3 +362,17 @@ func _sort_items(a, b): return value_a.nocasecmp_to(value_b) < 0 else: return value_a < value_b + +# When the header is clicked +func _on_header_clicked(headerItem: Control) -> void: + var header_label = headerItem.get_label_text() + if header_label == "I": + print_debug("Icon column clicked") + elif header_label == "Name": + print_debug("Name column clicked") + elif header_label == "W": + print_debug("Weight column clicked") + elif header_label == "V": + print_debug("Volume column clicked") + elif header_label == "F": + print_debug("Favorite column clicked") diff --git a/Scripts/CtrlInventoryStackedlistHeaderItem.gd b/Scripts/CtrlInventoryStackedlistHeaderItem.gd new file mode 100644 index 00000000..4a1cecc7 --- /dev/null +++ b/Scripts/CtrlInventoryStackedlistHeaderItem.gd @@ -0,0 +1,72 @@ +extends Control + + +# This script is intended to be used by the CtrlInventoryStackedListHeaderItem +# It is meant to be a container for a label that displays a column header +# When the mouse cursor hover over this item, it will change color +# When this item is clicked, it will change color to indicate it is selected +# When this item is clicked, it will emit a signal that it is clicked + + +@export var myBackgroundRect: ColorRect +@export var myLabel: Label + +# Colors for different states +var default_color: Color = Color(0.4, 0.4, 0.4, 1) # Default color +var hover_color: Color = Color(0.8, 0.8, 0.8, 1) # Hover color +var selected_color: Color = Color(0.5, 0.5, 0.8, 1) # Selected color + +var is_selected: bool = false + +signal header_clicked(item: Control) + +# Called when the node enters the scene tree for the first time. +func _ready(): + myBackgroundRect.color = default_color + connect("mouse_entered", _on_mouse_entered) + connect("mouse_exited", _on_mouse_exited) + +func select_item(): + is_selected = true + myBackgroundRect.color = selected_color + +func is_item_selected() -> bool: + return is_selected + +func unselect_item(): + is_selected = false + myBackgroundRect.color = default_color + +func _on_mouse_entered(): + highlight() + +func _on_mouse_exited(): + unhighlight() + +func highlight(): + if not is_selected: + myBackgroundRect.color = hover_color + +func unhighlight(): + if not is_selected: + myBackgroundRect.color = default_color + +# Function to set the text of the label. This hides the icon and shows the label. +func set_label_text(text: String): + myLabel.text = text + myLabel.visible = true + +# Function to get the text of the label. +func get_label_text() -> String: + return myLabel.text + +func _on_gui_input(event): + if event is InputEventMouseButton: + match event.button_index: + MOUSE_BUTTON_LEFT: + if event.pressed: + if is_selected: + unselect_item() + else: + select_item() + header_clicked.emit(self) From 6df96293eb01d369311d2df8fc282aa67b543601 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sat, 27 Jan 2024 21:28:24 +0100 Subject: [PATCH 08/26] Attempt to sort by column, need fix --- Scripts/CtrlInventoryStackedCustom.gd | 134 ++++++++++++++++++-------- 1 file changed, 93 insertions(+), 41 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index d4b0bb4e..09c59f90 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -35,6 +35,8 @@ extends Control var selectedItem: InventoryItem = null var selectedItems: Array = [] var last_selected_item: Control = null +var group_to_item_mapping: Dictionary = {} + signal item_selected(item) signal items_selected(items) @@ -50,7 +52,6 @@ func _ready(): var last_hovered_item: Node = null - func _process(_delta): var mouse_pos = get_global_mouse_position() var hovered_item: Node = null @@ -63,28 +64,30 @@ func _process(_delta): # Apply highlight effect if hovered_item and hovered_item != last_hovered_item: - if last_hovered_item: + if last_hovered_item and is_instance_valid(last_hovered_item): _remove_highlight(last_hovered_item) _apply_highlight(hovered_item) last_hovered_item = hovered_item - elif last_hovered_item and not hovered_item: + elif last_hovered_item and not hovered_item and is_instance_valid(last_hovered_item): # Remove highlight effect when cursor moves away _remove_highlight(last_hovered_item) last_hovered_item = null -func _apply_highlight(item: Node): - if item is Control: +func _remove_highlight(item: Node): + if item is Control and is_instance_valid(item): var group_name = _get_group_name(item) for group_item in get_tree().get_nodes_in_group(group_name): if group_item is Control: - group_item.highlight() + group_item.unhighlight() -func _remove_highlight(item: Node): - if item is Control: + + +func _apply_highlight(item: Node): + if item is Control and is_instance_valid(item): var group_name = _get_group_name(item) for group_item in get_tree().get_nodes_in_group(group_name): if group_item is Control: - group_item.unhighlight() + group_item.highlight() func _get_group_name(item: Control) -> String: for group in item.get_groups(): @@ -92,7 +95,6 @@ func _get_group_name(item: Control) -> String: return group return "" - func connect_signals(): # Connect each item for selection for item_index in range(inventoryGrid.get_child_count()): @@ -202,10 +204,21 @@ func _is_group_selected(group_name: String) -> bool: return false return true - - - - +# This function will return a dictionary with 5 keys +# The 5 keys are icon, name, weight, volume, favorite +func _get_group_data(group_name: String) -> Dictionary: + var group_item = group_to_item_mapping[group_name] + if group_item: + # Now use group_item to get the data + return { + "icon": group_item.get_icon(), + "name": group_item.get_title(), + "weight": group_item.get_property("weight", 0), + "volume": group_item.get_property("volume", 0), + "favorite": group_item.is_favorite() # Assuming is_favorite() method exists + } + else: + return {"icon": null, "name": "", "weight": 0, "volume": 0, "favorite": false} func _select_row_items(item: Control): @@ -264,6 +277,7 @@ func _deselect_all_except(except_item: Control): func add_item_to_grid(item: InventoryItem): # Define a unique group name for this set of items var group_name = "item_group_" + str(item.get_name()) + group_to_item_mapping[group_name] = item # Add the item icon var item_icon = listItemContainer.instantiate() as Control @@ -333,28 +347,6 @@ func _check_inventory_capacity(): if is_empty: emit_signal("inventory_empty") - -func sort_inventory_by_property(property_name: String): - # Create an array of items with additional data for sorting - var items_with_data = [] - for item in myInventory.get_children(): - var prop_value = item.get_property(property_name, null) - items_with_data.append({ - "item": item, - "sort_value": prop_value - }) - - # Sort the array based on the property value - items_with_data.sort_custom(_sort_items) - - # Clear and repopulate the grid with sorted items - inventoryGrid.queue_free_children() - add_header_row_to_grid() - for item_data in items_with_data: - add_item_to_grid(item_data["item"]) - - emit_signal("inventory_sorted", property_name) - func _sort_items(a, b): var value_a = a["sort_value"] var value_b = b["sort_value"] @@ -367,12 +359,72 @@ func _sort_items(a, b): func _on_header_clicked(headerItem: Control) -> void: var header_label = headerItem.get_label_text() if header_label == "I": - print_debug("Icon column clicked") + sort_inventory_by_property("icon") elif header_label == "Name": - print_debug("Name column clicked") + sort_inventory_by_property("name") elif header_label == "W": - print_debug("Weight column clicked") + sort_inventory_by_property("weight") elif header_label == "V": - print_debug("Volume column clicked") + sort_inventory_by_property("volume") elif header_label == "F": - print_debug("Favorite column clicked") + sort_inventory_by_property("favorite") + + +func sort_inventory_by_property(property_name: String): + var group_data = [] + var group_names = [] + + # Aggregate data by group + for item in inventoryGrid.get_children(): + var group_name = _get_group_name(item) + if not group_names.has(group_name): + group_names.append(group_name) + var representative_value = _get_representative_value_for_group(group_name, property_name) + group_data.append({ + "group_name": group_name, + "sort_value": representative_value + }) + + # Sort the array based on the property value + group_data.sort_custom(_sort_groups) + + # Clear and repopulate the grid with sorted groups + _clear_grid_children() + add_header_row_to_grid() + for group in group_data: + _add_group_to_grid(group["group_name"]) + emit_signal("inventory_sorted", property_name) + +func _clear_grid_children(): + while inventoryGrid.get_child_count() > 0: + var child = inventoryGrid.get_child(0) + inventoryGrid.remove_child(child) + child.queue_free() + +func _sort_groups(a, b): + var value_a = a["sort_value"] + var value_b = b["sort_value"] + if typeof(value_a) == TYPE_STRING: + return value_a.nocasecmp_to(value_b) < 0 + else: + return value_a < value_b + +func _get_representative_value_for_group(group_name: String, property_name: String): + if group_to_item_mapping.has(group_name): + var group_item = group_to_item_mapping[group_name] + if group_item: + var property_value = group_item.get_property(property_name, null) + if property_value != null: + return property_value + # Return a default value based on the property type + if property_name == "name" or property_name == "favorite": + return "" # Default value for string properties + else: + return 0 # Default value for numeric properties + + +func _add_group_to_grid(group_name: String): + # Logic to add all items of the group to the grid in their sorted order + var group_items = get_tree().get_nodes_in_group(group_name) + for item in group_items: + add_item_to_grid(item) From e7ddc2edea619a3cc073eebaf0dab2473220d74d Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 07:15:21 +0100 Subject: [PATCH 09/26] Refactor --- Scripts/CtrlInventoryStackedCustom.gd | 180 ++++++++++---------------- 1 file changed, 67 insertions(+), 113 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index 09c59f90..525e8d62 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -54,24 +54,20 @@ var last_hovered_item: Node = null func _process(_delta): var mouse_pos = get_global_mouse_position() - var hovered_item: Node = null + var hovered_item = get_hovered_item(mouse_pos) - # Check each child in the GridContainer - for child in inventoryGrid.get_children(): - if child is Control and child.get_global_rect().has_point(mouse_pos): - hovered_item = child - break - - # Apply highlight effect - if hovered_item and hovered_item != last_hovered_item: + if hovered_item != last_hovered_item: if last_hovered_item and is_instance_valid(last_hovered_item): _remove_highlight(last_hovered_item) - _apply_highlight(hovered_item) + if hovered_item: + _apply_highlight(hovered_item) last_hovered_item = hovered_item - elif last_hovered_item and not hovered_item and is_instance_valid(last_hovered_item): - # Remove highlight effect when cursor moves away - _remove_highlight(last_hovered_item) - last_hovered_item = null + +func get_hovered_item(mouse_pos: Vector2) -> Node: + for child in inventoryGrid.get_children(): + if child is Control and child.get_global_rect().has_point(mouse_pos): + return child + return null func _remove_highlight(item: Node): if item is Control and is_instance_valid(item): @@ -80,8 +76,6 @@ func _remove_highlight(item: Node): if group_item is Control: group_item.unhighlight() - - func _apply_highlight(item: Node): if item is Control and is_instance_valid(item): var group_name = _get_group_name(item) @@ -121,51 +115,21 @@ func _on_item_gui_input(event): selectedItems = [item] emit_signal("item_selected", item) -func populate_inventory_list(): - # Clear current grid - for child in inventoryGrid.get_children(): - child.queue_free() - - # Add header row - add_header_row_to_grid() - - # Add items to grid - for item in myInventory.get_children(): - add_item_to_grid(item) +# Helper function to create a header +func create_header(text: String, signal_name: Callable) -> void: + var header: Control = listHeaderContainer.instantiate() + header.set_label_text(text) + header.connect("header_clicked", signal_name) + inventoryGrid.add_child(header) +# Simplified function for adding headers func add_header_row_to_grid(): - # Create header elements and add them to the grid - - # Already given: header for Icon - var header_icon = listHeaderContainer.instantiate() as Control - header_icon.set_label_text("I") - inventoryGrid.add_child(header_icon) - header_icon.connect("header_clicked", _on_header_clicked) - - # Add header for Name - var header_name = listHeaderContainer.instantiate() as Control - header_name.set_label_text("Name") - inventoryGrid.add_child(header_name) - header_name.connect("header_clicked", _on_header_clicked) - - # Add header for Weight - var header_weight = listHeaderContainer.instantiate() as Control - header_weight.set_label_text("W") - inventoryGrid.add_child(header_weight) - header_weight.connect("header_clicked", _on_header_clicked) - - # Add header for Volume - var header_volume = listHeaderContainer.instantiate() as Control - header_volume.set_label_text("V") - inventoryGrid.add_child(header_volume) - header_volume.connect("header_clicked", _on_header_clicked) - - # Add header for Favorite (If applicable) - var header_favorite = listHeaderContainer.instantiate() as Control - header_favorite.set_label_text("F") - inventoryGrid.add_child(header_favorite) - header_favorite.connect("header_clicked", _on_header_clicked) + create_header("I", _on_header_clicked) + create_header("Name", _on_header_clicked) + create_header("W", _on_header_clicked) + create_header("V", _on_header_clicked) + create_header("F", _on_header_clicked) @@ -271,58 +235,53 @@ func _deselect_all_except(except_item: Control): selectedItems.clear() selectedItems = [except_item] +# Generic function to create a UI element +func create_ui_element(property: String, item: InventoryItem, group_name: String) -> Control: + var element = listItemContainer.instantiate() as Control + match property: + "icon": + element.set_icon(item.get_texture()) + element.custom_minimum_size = Vector2(32, 32) + "name": + element.set_label_text(item.get_title()) + # We give the most space to the name, expand it horizontally + element.size_flags_horizontal = Control.SIZE_EXPAND_FILL + _, "weight", "volume", "favorite": + # Fill in the value for the rest of the properties + element.set_label_text(str(item.get_property(property, 0))) + # The name will be something like weight_Node_211748 or icon_Node_211748 + # Now we can use the name to get information about the property + element.name = property + "_" + str(item.get_name()) + element.connect("item_clicked", _on_item_clicked) + # We use groups to keep track of the items + element.add_to_group(group_name) + return element + +# Refactored function to add an item to the grid +func add_item_to_grid(item: InventoryItem, group_name: String): + # Each item has these 5 columns to fill, so we loop over each of the properties + for property in ["icon", "name", "weight", "volume", "favorite"]: + var element = create_ui_element(property, item, group_name) + inventoryGrid.add_child(element) +func _add_group_to_grid(group_name: String): + # Logic to add all items of the group to the grid in their sorted order + var group_items = get_tree().get_nodes_in_group(group_name) + for item in group_items: + add_item_to_grid(item, group_name) - -func add_item_to_grid(item: InventoryItem): - # Define a unique group name for this set of items - var group_name = "item_group_" + str(item.get_name()) - group_to_item_mapping[group_name] = item - - # Add the item icon - var item_icon = listItemContainer.instantiate() as Control - item_icon.set_icon(item.get_texture()) - inventoryGrid.add_child(item_icon) - item_icon.connect("item_clicked", _on_item_clicked) - item_icon.add_to_group(group_name) - - # Add the item name - var item_name = listItemContainer.instantiate() as Control - item_name.set_label_text(item.get_title()) - inventoryGrid.add_child(item_name) - item_name.connect("item_clicked", _on_item_clicked) - item_name.add_to_group(group_name) - - # Add the item weight - var item_weight = listItemContainer.instantiate() as Control - item_weight.set_label_text(str(item.get_property("weight", 0))) - inventoryGrid.add_child(item_weight) - item_weight.connect("item_clicked", _on_item_clicked) - item_weight.add_to_group(group_name) - - # Add the item volume - var item_volume = listItemContainer.instantiate() as Control - item_volume.set_label_text(str(item.get_property("volume", 0))) - inventoryGrid.add_child(item_volume) - item_volume.connect("item_clicked", _on_item_clicked) - item_volume.add_to_group(group_name) - - # Add the item favorite - var item_favorite = listItemContainer.instantiate() as Control - item_favorite.set_label_text(str(item.get_property("favorite", 0))) - inventoryGrid.add_child(item_favorite) - item_favorite.connect("item_clicked", _on_item_clicked) - item_favorite.add_to_group(group_name) - - # Assign a unique name to each UI element - item_icon.name = "icon_" + str(item.get_name()) - item_name.name = "name_" + str(item.get_name()) - item_weight.name = "weight_" + str(item.get_name()) - item_volume.name = "volume_" + str(item.get_name()) - item_favorite.name = "favorite_" + str(item.get_name()) - item_name.size_flags_horizontal = Control.SIZE_EXPAND_FILL - item_icon.custom_minimum_size = Vector2(32,32) - +# Populate the inventory list +func populate_inventory_list(): + # Clear current grid + for child in inventoryGrid.get_children(): + child.queue_free() + # Add header + add_header_row_to_grid() + # Loop over inventory items and add them to the grid + for item in myInventory.get_children(): + var group_name = "item_group_" + str(item.get_name()) + group_to_item_mapping[group_name] = item + add_item_to_grid(item, group_name) func update_bars(): var total_weight = 0 @@ -423,8 +382,3 @@ func _get_representative_value_for_group(group_name: String, property_name: Stri return 0 # Default value for numeric properties -func _add_group_to_grid(group_name: String): - # Logic to add all items of the group to the grid in their sorted order - var group_items = get_tree().get_nodes_in_group(group_name) - for item in group_items: - add_item_to_grid(item) From dc8ad304801a8b435a15ca37147d19195f5fc52c Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 07:53:53 +0100 Subject: [PATCH 10/26] Sorting works --- Scenes/InventoryWindow.tscn | 14 ++--- Scripts/CtrlInventoryStackedCustom.gd | 86 +++++++++++++-------------- 2 files changed, 47 insertions(+), 53 deletions(-) diff --git a/Scenes/InventoryWindow.tscn b/Scenes/InventoryWindow.tscn index c1a91c8b..390e4d0c 100644 --- a/Scenes/InventoryWindow.tscn +++ b/Scenes/InventoryWindow.tscn @@ -61,25 +61,25 @@ script = ExtResource("5_qidb6") protoset = ExtResource("3_sqsc0") prototype_id = "bullet_9mm" -[node name="_Node_211710" type="Node" parent="InventoryStacked"] +[node name="_Node_211767" type="Node" parent="InventoryStacked"] script = ExtResource("5_qidb6") protoset = ExtResource("3_sqsc0") -prototype_id = "pistol_magazine" +prototype_id = "rifle_m4a1" -[node name="_Node_211729" type="Node" parent="InventoryStacked"] +[node name="_Node_23006" type="Node" parent="InventoryStacked"] script = ExtResource("5_qidb6") protoset = ExtResource("3_sqsc0") prototype_id = "pistol_9mm" -[node name="_Node_211748" type="Node" parent="InventoryStacked"] +[node name="_Node_23025" type="Node" parent="InventoryStacked"] script = ExtResource("5_qidb6") protoset = ExtResource("3_sqsc0") -prototype_id = "pistol_9mm" +prototype_id = "pistol_magazine" -[node name="_Node_211767" type="Node" parent="InventoryStacked"] +[node name="_Node_23044" type="Node" parent="InventoryStacked"] script = ExtResource("5_qidb6") protoset = ExtResource("3_sqsc0") -prototype_id = "rifle_m4a1" +prototype_id = "pistol_9mm" [node name="InventoryStackedProx" type="Node" parent="."] script = ExtResource("3_l8xgt") diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index 525e8d62..d5234a8d 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -96,7 +96,6 @@ func connect_signals(): if child is TextureRect or child is Label: child.connect("gui_input", _on_item_gui_input) - # Function to handle GUI input on an item func _on_item_gui_input(event): if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed: @@ -115,7 +114,6 @@ func _on_item_gui_input(event): selectedItems = [item] emit_signal("item_selected", item) - # Helper function to create a header func create_header(text: String, signal_name: Callable) -> void: var header: Control = listHeaderContainer.instantiate() @@ -132,7 +130,6 @@ func add_header_row_to_grid(): create_header("F", _on_header_clicked) - func _on_item_clicked(clickedItem: Control): var group_name = _get_group_name(clickedItem) if Input.is_key_pressed(KEY_CTRL): @@ -146,7 +143,6 @@ func _on_item_clicked(clickedItem: Control): for selected_group in selectedItems.duplicate(): _toggle_group_selection(selected_group, false) _toggle_group_selection(group_name, true) - # Update last selected item last_selected_item = clickedItem @@ -184,14 +180,12 @@ func _get_group_data(group_name: String) -> Dictionary: else: return {"icon": null, "name": "", "weight": 0, "volume": 0, "favorite": false} - func _select_row_items(item: Control): var group_name = _get_group_name(item) for group_item in get_tree().get_nodes_in_group(group_name): if group_item is Control and not group_item.is_item_selected(): group_item.select_item() - func _select_range(start_item: Control, end_item: Control): var start_group_name = _get_group_name(start_item) var end_group_name = _get_group_name(end_item) @@ -217,17 +211,12 @@ func _find_group_start_index(group_name: String) -> int: return i return -1 - - - func _find_child_index(item: Control) -> int: for i in range(inventoryGrid.get_child_count()): if inventoryGrid.get_child(i) == item: return i return -1 - - func _deselect_all_except(except_item: Control): for item in selectedItems: if item != except_item: @@ -255,20 +244,17 @@ func create_ui_element(property: String, item: InventoryItem, group_name: String element.connect("item_clicked", _on_item_clicked) # We use groups to keep track of the items element.add_to_group(group_name) + print("Element added to group: ", group_name) # Debugging line return element # Refactored function to add an item to the grid func add_item_to_grid(item: InventoryItem, group_name: String): + print("Adding item to group: ", group_name) # Debugging line # Each item has these 5 columns to fill, so we loop over each of the properties for property in ["icon", "name", "weight", "volume", "favorite"]: var element = create_ui_element(property, item, group_name) inventoryGrid.add_child(element) -func _add_group_to_grid(group_name: String): - # Logic to add all items of the group to the grid in their sorted order - var group_items = get_tree().get_nodes_in_group(group_name) - for item in group_items: - add_item_to_grid(item, group_name) # Populate the inventory list func populate_inventory_list(): @@ -314,46 +300,40 @@ func _sort_items(a, b): else: return value_a < value_b -# When the header is clicked +# Improved header click handling func _on_header_clicked(headerItem: Control) -> void: + var header_mapping = {"I": "icon", "Name": "name", "W": "weight", "V": "volume", "F": "favorite"} var header_label = headerItem.get_label_text() - if header_label == "I": - sort_inventory_by_property("icon") - elif header_label == "Name": - sort_inventory_by_property("name") - elif header_label == "W": - sort_inventory_by_property("weight") - elif header_label == "V": - sort_inventory_by_property("volume") - elif header_label == "F": - sort_inventory_by_property("favorite") + if header_label in header_mapping: + sort_inventory_by_property(header_mapping[header_label]) func sort_inventory_by_property(property_name: String): - var group_data = [] - var group_names = [] - - # Aggregate data by group - for item in inventoryGrid.get_children(): - var group_name = _get_group_name(item) - if not group_names.has(group_name): - group_names.append(group_name) - var representative_value = _get_representative_value_for_group(group_name, property_name) - group_data.append({ - "group_name": group_name, - "sort_value": representative_value - }) - - # Sort the array based on the property value + var group_data = get_group_data_with_property(property_name) + print("Before sorting: ", group_data) # Debugging line group_data.sort_custom(_sort_groups) + print("After sorting: ", group_data) # Debugging line - # Clear and repopulate the grid with sorted groups - _clear_grid_children() - add_header_row_to_grid() for group in group_data: + _clear_group_items(group["group_name"]) _add_group_to_grid(group["group_name"]) + emit_signal("inventory_sorted", property_name) +func _clear_group_items(group_name: String): + var group_items = get_tree().get_nodes_in_group(group_name) + for item in group_items: + if item is Control: + item.queue_free() + +func _add_group_to_grid(group_name: String): + print("Adding group to grid: ", group_name) # Debugging line + if group_to_item_mapping.has(group_name): + var group_item = group_to_item_mapping[group_name] + add_item_to_grid(group_item, group_name) + else: + print("Group item not found in mapping: ", group_name) + func _clear_grid_children(): while inventoryGrid.get_child_count() > 0: var child = inventoryGrid.get_child(0) @@ -363,6 +343,7 @@ func _clear_grid_children(): func _sort_groups(a, b): var value_a = a["sort_value"] var value_b = b["sort_value"] + print("Comparing: ", value_a, " with ", value_b) # Debugging line if typeof(value_a) == TYPE_STRING: return value_a.nocasecmp_to(value_b) < 0 else: @@ -381,4 +362,17 @@ func _get_representative_value_for_group(group_name: String, property_name: Stri else: return 0 # Default value for numeric properties - +# Function to get group data with a specific property value +func get_group_data_with_property(property_name: String) -> Array: + var data = [] + for item in myInventory.get_children(): + var group_name = "item_group_" + str(item.get_name()) + var value = item.get_property(property_name, get_default_value_for_property(property_name)) + data.append({"group_name": group_name, "sort_value": value}) + return data + +# Helper function to get default values for properties +func get_default_value_for_property(property_name: String) -> Variant: + match property_name: + "name", "favorite": return "" + _ : return 0 From fa1b65c76f49b5f048399a84f94b962882b9991b Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 08:26:09 +0100 Subject: [PATCH 11/26] Only one header can be selected --- Scripts/CtrlInventoryStackedCustom.gd | 41 +++++++++++++++++++++------ 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index d5234a8d..54721e14 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -37,6 +37,9 @@ var selectedItems: Array = [] var last_selected_item: Control = null var group_to_item_mapping: Dictionary = {} +# Dictionary to store header controls +var header_controls: Dictionary = {} +var selected_header: String = "" signal item_selected(item) signal items_selected(items) @@ -114,20 +117,24 @@ func _on_item_gui_input(event): selectedItems = [item] emit_signal("item_selected", item) + + # Helper function to create a header -func create_header(text: String, signal_name: Callable) -> void: +func create_header(text: String) -> void: var header: Control = listHeaderContainer.instantiate() header.set_label_text(text) - header.connect("header_clicked", signal_name) + header.connect("header_clicked", _on_header_clicked) inventoryGrid.add_child(header) + # Store the header control in the dictionary + header_controls[text] = header # Simplified function for adding headers func add_header_row_to_grid(): - create_header("I", _on_header_clicked) - create_header("Name", _on_header_clicked) - create_header("W", _on_header_clicked) - create_header("V", _on_header_clicked) - create_header("F", _on_header_clicked) + create_header("I") + create_header("Name") + create_header("W") + create_header("V") + create_header("F") func _on_item_clicked(clickedItem: Control): @@ -300,13 +307,30 @@ func _sort_items(a, b): else: return value_a < value_b -# Improved header click handling +# Header click handling func _on_header_clicked(headerItem: Control) -> void: var header_mapping = {"I": "icon", "Name": "name", "W": "weight", "V": "volume", "F": "favorite"} var header_label = headerItem.get_label_text() + var property_name = header_mapping[header_label] + + if selected_header != header_label: + # Update the visual state of the previously selected header + if selected_header in header_controls: + _update_header_visual_state(header_controls[selected_header], false) + selected_header = header_label + _update_header_visual_state(headerItem, true) if header_label in header_mapping: sort_inventory_by_property(header_mapping[header_label]) +# Method to update the visual state of a header +func _update_header_visual_state(header: Control, is_selected: bool): + # Apply visual changes to the header based on whether it is selected + if is_selected: + # Visual changes for selected state + header.select_item() + else: + # Visual changes for non-selected state + header.unselect_item() func sort_inventory_by_property(property_name: String): var group_data = get_group_data_with_property(property_name) @@ -376,3 +400,4 @@ func get_default_value_for_property(property_name: String) -> Variant: match property_name: "name", "favorite": return "" _ : return 0 + From 5b2a185ff49ff0833d296ed7194480eca4318b4f Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 08:30:10 +0100 Subject: [PATCH 12/26] Refactor --- Scripts/CtrlInventoryStackedCustom.gd | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index 54721e14..cb88ca78 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -316,22 +316,12 @@ func _on_header_clicked(headerItem: Control) -> void: if selected_header != header_label: # Update the visual state of the previously selected header if selected_header in header_controls: - _update_header_visual_state(header_controls[selected_header], false) + header_controls[selected_header].unselect_item() selected_header = header_label - _update_header_visual_state(headerItem, true) + headerItem.select_item() if header_label in header_mapping: sort_inventory_by_property(header_mapping[header_label]) -# Method to update the visual state of a header -func _update_header_visual_state(header: Control, is_selected: bool): - # Apply visual changes to the header based on whether it is selected - if is_selected: - # Visual changes for selected state - header.select_item() - else: - # Visual changes for non-selected state - header.unselect_item() - func sort_inventory_by_property(property_name: String): var group_data = get_group_data_with_property(property_name) print("Before sorting: ", group_data) # Debugging line From c2591bebb042f52af21fed0555995f13350137d2 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 08:49:12 +0100 Subject: [PATCH 13/26] Sorting refactor --- Scripts/CtrlInventoryStackedCustom.gd | 53 ++++++++++++++++++++------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index cb88ca78..885df67a 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -36,11 +36,13 @@ var selectedItem: InventoryItem = null var selectedItems: Array = [] var last_selected_item: Control = null var group_to_item_mapping: Dictionary = {} +var group_controls: Dictionary = {} # Dictionary to store header controls var header_controls: Dictionary = {} var selected_header: String = "" + signal item_selected(item) signal items_selected(items) signal inventory_sorted(column) @@ -261,7 +263,9 @@ func add_item_to_grid(item: InventoryItem, group_name: String): for property in ["icon", "name", "weight", "volume", "favorite"]: var element = create_ui_element(property, item, group_name) inventoryGrid.add_child(element) - + if not group_controls.has(group_name): + group_controls[group_name] = [] + group_controls[group_name].append(element) # Populate the inventory list func populate_inventory_list(): @@ -321,18 +325,18 @@ func _on_header_clicked(headerItem: Control) -> void: headerItem.select_item() if header_label in header_mapping: sort_inventory_by_property(header_mapping[header_label]) - -func sort_inventory_by_property(property_name: String): - var group_data = get_group_data_with_property(property_name) - print("Before sorting: ", group_data) # Debugging line - group_data.sort_custom(_sort_groups) - print("After sorting: ", group_data) # Debugging line - - for group in group_data: - _clear_group_items(group["group_name"]) - _add_group_to_grid(group["group_name"]) - - emit_signal("inventory_sorted", property_name) +# +#func sort_inventory_by_property(property_name: String): + #var group_data = get_group_data_with_property(property_name) + #print("Before sorting: ", group_data) # Debugging line + #group_data.sort_custom(_sort_groups) + #print("After sorting: ", group_data) # Debugging line +# + #for group in group_data: + #_clear_group_items(group["group_name"]) + #_add_group_to_grid(group["group_name"]) +# + #emit_signal("inventory_sorted", property_name) func _clear_group_items(group_name: String): var group_items = get_tree().get_nodes_in_group(group_name) @@ -391,3 +395,26 @@ func get_default_value_for_property(property_name: String) -> Variant: "name", "favorite": return "" _ : return 0 +func sort_inventory_by_property(property_name: String): + var sorted_groups = get_sorted_groups(property_name) + for group_name in sorted_groups: + move_group_to_end(group_name) + emit_signal("inventory_sorted", property_name) + +func move_group_to_end(group_name: String): + for control in group_controls[group_name]: + inventoryGrid.move_child(control, inventoryGrid.get_child_count() - 1) + +func get_sorted_groups(property_name: String) -> Array: + var group_data = [] + for group_name in group_controls.keys(): + var representative_value = _get_representative_value_for_group(group_name, property_name) + group_data.append({"group_name": group_name, "sort_value": representative_value}) + + group_data.sort_custom(_sort_groups) + + var sorted_group_names = [] + for gd in group_data: + sorted_group_names.append(gd["group_name"]) + + return sorted_group_names From 8e5cfb017c3a46c7815feacfcd2eb0a9d32bcdef Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 09:10:52 +0100 Subject: [PATCH 14/26] More refactor --- Scripts/CtrlInventoryStackedCustom.gd | 74 ++++++++++++--------------- 1 file changed, 32 insertions(+), 42 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index 885df67a..97011551 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -74,19 +74,17 @@ func get_hovered_item(mouse_pos: Vector2) -> Node: return child return null -func _remove_highlight(item: Node): - if item is Control and is_instance_valid(item): - var group_name = _get_group_name(item) - for group_item in get_tree().get_nodes_in_group(group_name): - if group_item is Control: - group_item.unhighlight() - -func _apply_highlight(item: Node): - if item is Control and is_instance_valid(item): - var group_name = _get_group_name(item) - for group_item in get_tree().get_nodes_in_group(group_name): - if group_item is Control: - group_item.highlight() +func _apply_highlight(item: Control): + var group_name = _get_group_name(item) + if group_controls.has(group_name): + for control in group_controls[group_name]: + control.highlight() + +func _remove_highlight(item: Control): + var group_name = _get_group_name(item) + if group_controls.has(group_name): + for control in group_controls[group_name]: + control.unhighlight() func _get_group_name(item: Control) -> String: for group in item.get_groups(): @@ -155,23 +153,6 @@ func _on_item_clicked(clickedItem: Control): # Update last selected item last_selected_item = clickedItem -func _toggle_group_selection(group_name: String, select: bool): - for group_item in get_tree().get_nodes_in_group(group_name): - if group_item is Control: - if select: - group_item.select_item() - else: - group_item.unselect_item() - if select: - selectedItems.append(group_name) - else: - selectedItems.erase(group_name) - -func _is_group_selected(group_name: String) -> bool: - for group_item in get_tree().get_nodes_in_group(group_name): - if group_item is Control and not group_item.is_item_selected(): - return false - return true # This function will return a dictionary with 5 keys # The 5 keys are icon, name, weight, volume, favorite @@ -325,18 +306,6 @@ func _on_header_clicked(headerItem: Control) -> void: headerItem.select_item() if header_label in header_mapping: sort_inventory_by_property(header_mapping[header_label]) -# -#func sort_inventory_by_property(property_name: String): - #var group_data = get_group_data_with_property(property_name) - #print("Before sorting: ", group_data) # Debugging line - #group_data.sort_custom(_sort_groups) - #print("After sorting: ", group_data) # Debugging line -# - #for group in group_data: - #_clear_group_items(group["group_name"]) - #_add_group_to_grid(group["group_name"]) -# - #emit_signal("inventory_sorted", property_name) func _clear_group_items(group_name: String): var group_items = get_tree().get_nodes_in_group(group_name) @@ -418,3 +387,24 @@ func get_sorted_groups(property_name: String) -> Array: sorted_group_names.append(gd["group_name"]) return sorted_group_names + + + +func _toggle_group_selection(group_name: String, select: bool): + for group_item in get_tree().get_nodes_in_group(group_name): + if group_item is Control: + if select: + group_item.select_item() + else: + group_item.unselect_item() + if select: + selectedItems.append(group_name) + else: + selectedItems.erase(group_name) + + +func _is_group_selected(group_name: String) -> bool: + for group_item in get_tree().get_nodes_in_group(group_name): + if group_item is Control and not group_item.is_item_selected(): + return false + return true From f12fb0a970623d9d8785ece233ac323e3d8e3da8 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 09:17:23 +0100 Subject: [PATCH 15/26] Remove unused functions --- Scripts/CtrlInventoryStackedCustom.gd | 72 +-------------------------- 1 file changed, 1 insertion(+), 71 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index 97011551..d6c61c9a 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -153,29 +153,6 @@ func _on_item_clicked(clickedItem: Control): # Update last selected item last_selected_item = clickedItem - -# This function will return a dictionary with 5 keys -# The 5 keys are icon, name, weight, volume, favorite -func _get_group_data(group_name: String) -> Dictionary: - var group_item = group_to_item_mapping[group_name] - if group_item: - # Now use group_item to get the data - return { - "icon": group_item.get_icon(), - "name": group_item.get_title(), - "weight": group_item.get_property("weight", 0), - "volume": group_item.get_property("volume", 0), - "favorite": group_item.is_favorite() # Assuming is_favorite() method exists - } - else: - return {"icon": null, "name": "", "weight": 0, "volume": 0, "favorite": false} - -func _select_row_items(item: Control): - var group_name = _get_group_name(item) - for group_item in get_tree().get_nodes_in_group(group_name): - if group_item is Control and not group_item.is_item_selected(): - group_item.select_item() - func _select_range(start_item: Control, end_item: Control): var start_group_name = _get_group_name(start_item) var end_group_name = _get_group_name(end_item) @@ -201,19 +178,6 @@ func _find_group_start_index(group_name: String) -> int: return i return -1 -func _find_child_index(item: Control) -> int: - for i in range(inventoryGrid.get_child_count()): - if inventoryGrid.get_child(i) == item: - return i - return -1 - -func _deselect_all_except(except_item: Control): - for item in selectedItems: - if item != except_item: - item.unselect_item() - selectedItems.clear() - selectedItems = [except_item] - # Generic function to create a UI element func create_ui_element(property: String, item: InventoryItem, group_name: String) -> Control: var element = listItemContainer.instantiate() as Control @@ -250,9 +214,7 @@ func add_item_to_grid(item: InventoryItem, group_name: String): # Populate the inventory list func populate_inventory_list(): - # Clear current grid - for child in inventoryGrid.get_children(): - child.queue_free() + _clear_grid_children() # Add header add_header_row_to_grid() # Loop over inventory items and add them to the grid @@ -307,20 +269,6 @@ func _on_header_clicked(headerItem: Control) -> void: if header_label in header_mapping: sort_inventory_by_property(header_mapping[header_label]) -func _clear_group_items(group_name: String): - var group_items = get_tree().get_nodes_in_group(group_name) - for item in group_items: - if item is Control: - item.queue_free() - -func _add_group_to_grid(group_name: String): - print("Adding group to grid: ", group_name) # Debugging line - if group_to_item_mapping.has(group_name): - var group_item = group_to_item_mapping[group_name] - add_item_to_grid(group_item, group_name) - else: - print("Group item not found in mapping: ", group_name) - func _clear_grid_children(): while inventoryGrid.get_child_count() > 0: var child = inventoryGrid.get_child(0) @@ -349,21 +297,6 @@ func _get_representative_value_for_group(group_name: String, property_name: Stri else: return 0 # Default value for numeric properties -# Function to get group data with a specific property value -func get_group_data_with_property(property_name: String) -> Array: - var data = [] - for item in myInventory.get_children(): - var group_name = "item_group_" + str(item.get_name()) - var value = item.get_property(property_name, get_default_value_for_property(property_name)) - data.append({"group_name": group_name, "sort_value": value}) - return data - -# Helper function to get default values for properties -func get_default_value_for_property(property_name: String) -> Variant: - match property_name: - "name", "favorite": return "" - _ : return 0 - func sort_inventory_by_property(property_name: String): var sorted_groups = get_sorted_groups(property_name) for group_name in sorted_groups: @@ -388,8 +321,6 @@ func get_sorted_groups(property_name: String) -> Array: return sorted_group_names - - func _toggle_group_selection(group_name: String, select: bool): for group_item in get_tree().get_nodes_in_group(group_name): if group_item is Control: @@ -402,7 +333,6 @@ func _toggle_group_selection(group_name: String, select: bool): else: selectedItems.erase(group_name) - func _is_group_selected(group_name: String) -> bool: for group_item in get_tree().get_nodes_in_group(group_name): if group_item is Control and not group_item.is_item_selected(): From efd85eeed7ac95a9b6af2f0e6f086bc9c1277815 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 09:25:24 +0100 Subject: [PATCH 16/26] More refactoring --- Scripts/CtrlInventoryStackedCustom.gd | 32 +++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index d6c61c9a..fc6c6168 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -117,8 +117,6 @@ func _on_item_gui_input(event): selectedItems = [item] emit_signal("item_selected", item) - - # Helper function to create a header func create_header(text: String) -> void: var header: Control = listHeaderContainer.instantiate() @@ -163,12 +161,12 @@ func _select_range(start_item: Control, end_item: Control): var min_index = min(start_index, end_index) var max_index = max(start_index, end_index) - # Iterate through the grid and select groups within the range for i in range(min_index, max_index + 1): var item = inventoryGrid.get_child(i) if item: var group_name = _get_group_name(item) - _toggle_group_selection(group_name, true) + if group_controls.has(group_name): + _toggle_group_selection(group_name, true) # Find the index of the first item in a group func _find_group_start_index(group_name: String) -> int: @@ -322,19 +320,21 @@ func get_sorted_groups(property_name: String) -> Array: return sorted_group_names func _toggle_group_selection(group_name: String, select: bool): - for group_item in get_tree().get_nodes_in_group(group_name): - if group_item is Control: + if group_controls.has(group_name): + for control in group_controls[group_name]: if select: - group_item.select_item() + control.select_item() else: - group_item.unselect_item() - if select: - selectedItems.append(group_name) - else: - selectedItems.erase(group_name) + control.unselect_item() + if select: + selectedItems.append(group_name) + else: + selectedItems.erase(group_name) func _is_group_selected(group_name: String) -> bool: - for group_item in get_tree().get_nodes_in_group(group_name): - if group_item is Control and not group_item.is_item_selected(): - return false - return true + if group_controls.has(group_name): + for control in group_controls[group_name]: + if not control.is_item_selected(): + return false + return true + return false From 1f0987d07643873a46e88400d857b5c5c5fcf7d0 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 10:00:36 +0100 Subject: [PATCH 17/26] Single items can be de-selected --- Scripts/CtrlInventoryStackedCustom.gd | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index fc6c6168..322f039f 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -137,17 +137,25 @@ func add_header_row_to_grid(): func _on_item_clicked(clickedItem: Control): var group_name = _get_group_name(clickedItem) + if Input.is_key_pressed(KEY_CTRL): - # Toggle the entire group selection + # CTRL is held: toggle selection of the group _toggle_group_selection(group_name, not _is_group_selected(group_name)) elif Input.is_key_pressed(KEY_SHIFT) and last_selected_item: - # Select a range of items (handled as before) + # SHIFT is held: select a range of items _select_range(last_selected_item, clickedItem) else: - # Select only the clicked group - for selected_group in selectedItems.duplicate(): - _toggle_group_selection(selected_group, false) - _toggle_group_selection(group_name, true) + # No modifier key: select or deselect the clicked group + # Check if the clicked item's group is selected + if not _is_group_selected(group_name): + if selectedItems.size() == 1 and selectedItems[0] == group_name: + _toggle_group_selection(group_name, false) + else: + # Deselect all other items and select the clicked group + for selected_group in selectedItems.duplicate(): + _toggle_group_selection(selected_group, false) + _toggle_group_selection(group_name, true) + # Update last selected item last_selected_item = clickedItem @@ -256,7 +264,6 @@ func _sort_items(a, b): func _on_header_clicked(headerItem: Control) -> void: var header_mapping = {"I": "icon", "Name": "name", "W": "weight", "V": "volume", "F": "favorite"} var header_label = headerItem.get_label_text() - var property_name = header_mapping[header_label] if selected_header != header_label: # Update the visual state of the previously selected header @@ -338,3 +345,4 @@ func _is_group_selected(group_name: String) -> bool: return false return true return false + From 81a03f26eb0fc184603132eb620c48df5aeb190c Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 10:13:28 +0100 Subject: [PATCH 18/26] Selection works again --- Scripts/CtrlInventoryStackedCustom.gd | 30 ++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index 322f039f..d3cb70ac 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -139,8 +139,33 @@ func _on_item_clicked(clickedItem: Control): var group_name = _get_group_name(clickedItem) if Input.is_key_pressed(KEY_CTRL): - # CTRL is held: toggle selection of the group - _toggle_group_selection(group_name, not _is_group_selected(group_name)) + print_debug("_is_group_selected(group_name) = " + str(_is_group_selected(group_name))) + print_debug(" selectedItems.size() > 1 = " + str( selectedItems.size() > 1)) + print_debug("clickedItem.is_item_selected() = " + str(clickedItem.is_item_selected())) + # CTRL is held: check if current group is selected and if there are other groups selected + if _is_group_selected(group_name): + if selectedItems.size() > 1: + # Deselect the current group + _toggle_group_selection(group_name, false) + else: + if selectedItems.size() > 1: + if clickedItem.is_item_selected(): + # Deselect the current group + _toggle_group_selection(group_name, true) + else: + # select the current group + _toggle_group_selection(group_name, false) + else: + if clickedItem.is_item_selected(): + # Toggle selection of the group (either select or deselect) + _toggle_group_selection(group_name, true) + #_toggle_group_selection(group_name, not _is_group_selected(group_name)) + else: + # select the current group + _toggle_group_selection(group_name, false) + + ## CTRL is held: toggle selection of the group + #_toggle_group_selection(group_name, not _is_group_selected(group_name)) elif Input.is_key_pressed(KEY_SHIFT) and last_selected_item: # SHIFT is held: select a range of items _select_range(last_selected_item, clickedItem) @@ -204,7 +229,6 @@ func create_ui_element(property: String, item: InventoryItem, group_name: String element.connect("item_clicked", _on_item_clicked) # We use groups to keep track of the items element.add_to_group(group_name) - print("Element added to group: ", group_name) # Debugging line return element # Refactored function to add an item to the grid From 8e30e1183f64037164176c43be40134e55c02026 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 10:15:19 +0100 Subject: [PATCH 19/26] Clean up item selection --- Scripts/CtrlInventoryStackedCustom.gd | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index d3cb70ac..cade42ac 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -139,33 +139,20 @@ func _on_item_clicked(clickedItem: Control): var group_name = _get_group_name(clickedItem) if Input.is_key_pressed(KEY_CTRL): - print_debug("_is_group_selected(group_name) = " + str(_is_group_selected(group_name))) - print_debug(" selectedItems.size() > 1 = " + str( selectedItems.size() > 1)) - print_debug("clickedItem.is_item_selected() = " + str(clickedItem.is_item_selected())) # CTRL is held: check if current group is selected and if there are other groups selected if _is_group_selected(group_name): if selectedItems.size() > 1: # Deselect the current group _toggle_group_selection(group_name, false) else: - if selectedItems.size() > 1: - if clickedItem.is_item_selected(): - # Deselect the current group - _toggle_group_selection(group_name, true) - else: - # select the current group - _toggle_group_selection(group_name, false) + if clickedItem.is_item_selected(): + # select the current group + _toggle_group_selection(group_name, true) else: - if clickedItem.is_item_selected(): - # Toggle selection of the group (either select or deselect) - _toggle_group_selection(group_name, true) - #_toggle_group_selection(group_name, not _is_group_selected(group_name)) - else: - # select the current group - _toggle_group_selection(group_name, false) + # de-select the current group + _toggle_group_selection(group_name, false) ## CTRL is held: toggle selection of the group - #_toggle_group_selection(group_name, not _is_group_selected(group_name)) elif Input.is_key_pressed(KEY_SHIFT) and last_selected_item: # SHIFT is held: select a range of items _select_range(last_selected_item, clickedItem) From ec8565b0b3eb00581d284bfdcd810674b45a1bcc Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 10:23:34 +0100 Subject: [PATCH 20/26] Reverse sorting --- Scripts/CtrlInventoryStackedCustom.gd | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index cade42ac..269dd4da 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -41,7 +41,7 @@ var group_controls: Dictionary = {} # Dictionary to store header controls var header_controls: Dictionary = {} var selected_header: String = "" - +var header_sort_order: Dictionary = {} signal item_selected(item) signal items_selected(items) @@ -271,19 +271,25 @@ func _sort_items(a, b): else: return value_a < value_b -# Header click handling func _on_header_clicked(headerItem: Control) -> void: var header_mapping = {"I": "icon", "Name": "name", "W": "weight", "V": "volume", "F": "favorite"} var header_label = headerItem.get_label_text() + var reverse_order = false + if selected_header == header_label and header_label in header_sort_order: + # Reverse the sort order if the same header is clicked again + reverse_order = !header_sort_order[header_label] + if selected_header != header_label: # Update the visual state of the previously selected header if selected_header in header_controls: header_controls[selected_header].unselect_item() selected_header = header_label headerItem.select_item() + if header_label in header_mapping: - sort_inventory_by_property(header_mapping[header_label]) + sort_inventory_by_property(header_mapping[header_label], reverse_order) + header_sort_order[header_label] = reverse_order func _clear_grid_children(): while inventoryGrid.get_child_count() > 0: @@ -313,8 +319,10 @@ func _get_representative_value_for_group(group_name: String, property_name: Stri else: return 0 # Default value for numeric properties -func sort_inventory_by_property(property_name: String): +func sort_inventory_by_property(property_name: String, reverse_order: bool = false): var sorted_groups = get_sorted_groups(property_name) + if reverse_order: + sorted_groups.reverse() # Reverse the order of the sorted groups for group_name in sorted_groups: move_group_to_end(group_name) emit_signal("inventory_sorted", property_name) @@ -323,6 +331,7 @@ func move_group_to_end(group_name: String): for control in group_controls[group_name]: inventoryGrid.move_child(control, inventoryGrid.get_child_count() - 1) + func get_sorted_groups(property_name: String) -> Array: var group_data = [] for group_name in group_controls.keys(): From 1162a2bbf1d9ac961411511f80333d3ad5e85fc1 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 10:27:25 +0100 Subject: [PATCH 21/26] Remove excess functions --- Scripts/CtrlInventoryStackedCustom.gd | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index 269dd4da..c950fd7d 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -52,7 +52,6 @@ signal inventory_empty func _ready(): populate_inventory_list() - connect_signals() update_bars() var last_hovered_item: Node = null @@ -92,31 +91,6 @@ func _get_group_name(item: Control) -> String: return group return "" -func connect_signals(): - # Connect each item for selection - for item_index in range(inventoryGrid.get_child_count()): - var child = inventoryGrid.get_child(item_index) - if child is TextureRect or child is Label: - child.connect("gui_input", _on_item_gui_input) - -# Function to handle GUI input on an item -func _on_item_gui_input(event): - if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed: - var item = inventoryGrid.get_selected_item() - # Check if CTRL is held for multiple selections - if Input.is_key_pressed(KEY_CTRL): - # Add or remove from the selection - if item in selectedItems: - selectedItems.erase(item) - else: - selectedItems.append(item) - emit_signal("items_selected", selectedItems) - else: - # Single selection - selectedItem = item - selectedItems = [item] - emit_signal("item_selected", item) - # Helper function to create a header func create_header(text: String) -> void: var header: Control = listHeaderContainer.instantiate() From 4741931f549b0f4e4f5c38997308ddc0a3b29eb2 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 10:44:32 +0100 Subject: [PATCH 22/26] Add comments --- Scripts/CtrlInventoryStackedCustom.gd | 47 +++++++++++++++++---------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index c950fd7d..b09e6e31 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -37,6 +37,7 @@ var selectedItems: Array = [] var last_selected_item: Control = null var group_to_item_mapping: Dictionary = {} var group_controls: Dictionary = {} +var last_hovered_item: Node = null # Dictionary to store header controls var header_controls: Dictionary = {} @@ -54,8 +55,7 @@ func _ready(): populate_inventory_list() update_bars() -var last_hovered_item: Node = null - +# Take care of the hovering over items in the grid func _process(_delta): var mouse_pos = get_global_mouse_position() var hovered_item = get_hovered_item(mouse_pos) @@ -85,6 +85,8 @@ func _remove_highlight(item: Control): for control in group_controls[group_name]: control.unhighlight() +# Gets the group name from an item +# An item is a control element in the inventory grid func _get_group_name(item: Control) -> String: for group in item.get_groups(): if group.begins_with("item_group_"): @@ -108,25 +110,19 @@ func add_header_row_to_grid(): create_header("V") create_header("F") - +# When an item in the inventory is clicked +# There are 5 items per row in the grid, but they are treated as a group of 5 +# So clicking one item will select the whole row func _on_item_clicked(clickedItem: Control): var group_name = _get_group_name(clickedItem) if Input.is_key_pressed(KEY_CTRL): # CTRL is held: check if current group is selected and if there are other groups selected - if _is_group_selected(group_name): - if selectedItems.size() > 1: - # Deselect the current group - _toggle_group_selection(group_name, false) + if _is_group_selected(group_name) and selectedItems.size() > 1: + # Deselect the current group + _toggle_group_selection(group_name, false) else: - if clickedItem.is_item_selected(): - # select the current group - _toggle_group_selection(group_name, true) - else: - # de-select the current group - _toggle_group_selection(group_name, false) - - ## CTRL is held: toggle selection of the group + _toggle_group_selection(group_name, clickedItem.is_item_selected()) elif Input.is_key_pressed(KEY_SHIFT) and last_selected_item: # SHIFT is held: select a range of items _select_range(last_selected_item, clickedItem) @@ -135,8 +131,9 @@ func _on_item_clicked(clickedItem: Control): # Check if the clicked item's group is selected if not _is_group_selected(group_name): if selectedItems.size() == 1 and selectedItems[0] == group_name: - _toggle_group_selection(group_name, false) + _toggle_group_selection(group_name, false) # De-select else: + # More then one group is selected # Deselect all other items and select the clicked group for selected_group in selectedItems.duplicate(): _toggle_group_selection(selected_group, false) @@ -145,6 +142,8 @@ func _on_item_clicked(clickedItem: Control): # Update last selected item last_selected_item = clickedItem +# Select a range of items. This is called when the user +# selects an item and then holds shift and selects another item func _select_range(start_item: Control, end_item: Control): var start_group_name = _get_group_name(start_item) var end_group_name = _get_group_name(end_item) @@ -170,7 +169,7 @@ func _find_group_start_index(group_name: String) -> int: return i return -1 -# Generic function to create a UI element +# Generic function to create an item in the grid func create_ui_element(property: String, item: InventoryItem, group_name: String) -> Control: var element = listItemContainer.instantiate() as Control match property: @@ -199,6 +198,7 @@ func add_item_to_grid(item: InventoryItem, group_name: String): for property in ["icon", "name", "weight", "volume", "favorite"]: var element = create_ui_element(property, item, group_name) inventoryGrid.add_child(element) + # Keep track of the list items by group name if not group_controls.has(group_name): group_controls[group_name] = [] group_controls[group_name].append(element) @@ -245,6 +245,7 @@ func _sort_items(a, b): else: return value_a < value_b +# When a header is clicked, we will apply sorting to that column func _on_header_clicked(headerItem: Control) -> void: var header_mapping = {"I": "icon", "Name": "name", "W": "weight", "V": "volume", "F": "favorite"} var header_label = headerItem.get_label_text() @@ -280,6 +281,8 @@ func _sort_groups(a, b): else: return value_a < value_b +# Returns the value of the provided property for the provided group +# Essentially, the group_name is a row and the property_name is a column in the grid func _get_representative_value_for_group(group_name: String, property_name: String): if group_to_item_mapping.has(group_name): var group_item = group_to_item_mapping[group_name] @@ -293,6 +296,7 @@ func _get_representative_value_for_group(group_name: String, property_name: Stri else: return 0 # Default value for numeric properties +# Will sort the order of the items baased on the selected column (property_name) func sort_inventory_by_property(property_name: String, reverse_order: bool = false): var sorted_groups = get_sorted_groups(property_name) if reverse_order: @@ -305,7 +309,10 @@ func move_group_to_end(group_name: String): for control in group_controls[group_name]: inventoryGrid.move_child(control, inventoryGrid.get_child_count() - 1) - +# Constructs an array of the group name and the provided property +# The group_data is essentially all the rows in the grid +# The property_name is the column of the grid +# With this new array of group_name and property_name, the items can be sorted func get_sorted_groups(property_name: String) -> Array: var group_data = [] for group_name in group_controls.keys(): @@ -320,6 +327,8 @@ func get_sorted_groups(property_name: String) -> Array: return sorted_group_names +# A group is made up of 5 items (a row). +# This will select or deselect a group func _toggle_group_selection(group_name: String, select: bool): if group_controls.has(group_name): for control in group_controls[group_name]: @@ -332,6 +341,8 @@ func _toggle_group_selection(group_name: String, select: bool): else: selectedItems.erase(group_name) +# If any of the controls is un-selected, the group is not selected +# Otherwise the group is selected func _is_group_selected(group_name: String) -> bool: if group_controls.has(group_name): for control in group_controls[group_name]: From 56b639adcee22da4045712b03ab83542deba47d5 Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 10:54:52 +0100 Subject: [PATCH 23/26] Basic context menu --- Scripts/CtrlInventoryStackedCustom.gd | 47 ++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index b09e6e31..c39e7d4d 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -39,6 +39,9 @@ var group_to_item_mapping: Dictionary = {} var group_controls: Dictionary = {} var last_hovered_item: Node = null +# Context menu that will show actions for selected items +var context_menu: PopupMenu + # Dictionary to store header controls var header_controls: Dictionary = {} var selected_header: String = "" @@ -51,9 +54,18 @@ signal inventory_updated signal inventory_reached_capacity signal inventory_empty + +# Signals for context menu actions +signal equip_left(items) +signal equip_right(items) +signal drop_item(items) +signal wear_item(items) +signal disassemble_item(items) + func _ready(): populate_inventory_list() update_bars() + setup_context_menu() # Take care of the hovering over items in the grid func _process(_delta): @@ -85,6 +97,40 @@ func _remove_highlight(item: Control): for control in group_controls[group_name]: control.unhighlight() +func setup_context_menu(): + # Initialize and configure the context menu + context_menu = PopupMenu.new() + add_child(context_menu) + context_menu.add_item("Equip (left)", 0) + context_menu.add_item("Equip (right)", 1) + context_menu.add_item("Drop", 2) + context_menu.add_item("Wear", 3) + context_menu.add_item("Disassemble", 4) + context_menu.connect("id_pressed", _on_context_menu_item_selected) + + +# Function to show context menu +func show_context_menu(): + context_menu.popup_centered_clamped(Vector2(200, 250)) + +# Handle context menu item selection +func _on_context_menu_item_selected(id): + var selected_inventory_items = get_selected_inventory_items() + match id: + 0: emit_signal("equip_left", selected_inventory_items) + 1: emit_signal("equip_right", selected_inventory_items) + 2: emit_signal("drop_item", selected_inventory_items) + 3: emit_signal("wear_item", selected_inventory_items) + 4: emit_signal("disassemble_item", selected_inventory_items) + +# Function to get selected inventory items +func get_selected_inventory_items() -> Array: + var items = [] + for group_name in selectedItems: + if group_to_item_mapping.has(group_name): + items.append(group_to_item_mapping[group_name]) + return items + # Gets the group name from an item # An item is a control element in the inventory grid func _get_group_name(item: Control) -> String: @@ -350,4 +396,3 @@ func _is_group_selected(group_name: String) -> bool: return false return true return false - From 701a89b711d3fddabf0e7509fc274bbcc505d82e Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 10:59:23 +0100 Subject: [PATCH 24/26] Add inventory signals --- Scripts/CtrlInventoryStackedCustom.gd | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index c39e7d4d..55c96dc4 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -66,6 +66,7 @@ func _ready(): populate_inventory_list() update_bars() setup_context_menu() + connect_inventory_signals() # Take care of the hovering over items in the grid func _process(_delta): @@ -131,6 +132,40 @@ func get_selected_inventory_items() -> Array: items.append(group_to_item_mapping[group_name]) return items +func connect_inventory_signals(): + # Connect signals from InventoryStacked to this control script + myInventory.connect("item_added", _on_inventory_item_added) + myInventory.connect("item_removed", _on_inventory_item_removed) + myInventory.connect("item_modified", _on_inventory_item_modified) + myInventory.connect("contents_changed", _on_inventory_contents_changed) + + +func _on_inventory_item_added(_item: InventoryItem): + # Handle item added to inventory + update_inventory_list() + +func _on_inventory_item_removed(_item: InventoryItem): + # Handle item removed from inventory + update_inventory_list() + +func _on_inventory_item_modified(_item: InventoryItem): + # Handle item modified in inventory + update_inventory_list() + +func _on_inventory_contents_changed(): + # Handle inventory contents changed + update_inventory_list() + +func update_inventory_list(): + # Clear and repopulate the inventory list + _clear_grid_children() + add_header_row_to_grid() + for item in myInventory.get_children(): + var group_name = "item_group_" + str(item.get_name()) + group_to_item_mapping[group_name] = item + add_item_to_grid(item, group_name) + update_bars() + # Gets the group name from an item # An item is a control element in the inventory grid func _get_group_name(item: Control) -> String: From 166c020d1049d6c079e6d493bf72cf95369f357d Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 11:06:35 +0100 Subject: [PATCH 25/26] Show the context menu --- Scripts/CtrlInventoryStackedCustom.gd | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index 55c96dc4..597ea673 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -67,6 +67,17 @@ func _ready(): update_bars() setup_context_menu() connect_inventory_signals() + + +func _input(event): + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT and event.pressed: + # Check if the right mouse button was pressed + var mouse_pos = get_global_mouse_position() + var hovered_item = get_hovered_item(mouse_pos) + if hovered_item: + # If the mouse is over an inventory item, show the context menu + show_context_menu() + # Take care of the hovering over items in the grid func _process(_delta): @@ -109,10 +120,11 @@ func setup_context_menu(): context_menu.add_item("Disassemble", 4) context_menu.connect("id_pressed", _on_context_menu_item_selected) - # Function to show context menu func show_context_menu(): - context_menu.popup_centered_clamped(Vector2(200, 250)) + # Show the context menu at the center of the screen + context_menu.popup_centered() + # Handle context menu item selection func _on_context_menu_item_selected(id): From 79d1ade0c105fed7937935aee9c69d1f2938540e Mon Sep 17 00:00:00 2001 From: snipercup <50166150+snipercup@users.noreply.github.com> Date: Sun, 28 Jan 2024 11:37:58 +0100 Subject: [PATCH 26/26] Context menu shows up --- Scenes/UI/CtrlInventoryStackedCustom.tscn | 19 ++++++++++- Scripts/CtrlInventoryStackedCustom.gd | 40 +++++++---------------- Scripts/CtrlInventoryStackedListItem.gd | 12 +++++-- Scripts/InventoryWindow.gd | 5 --- 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Scenes/UI/CtrlInventoryStackedCustom.tscn b/Scenes/UI/CtrlInventoryStackedCustom.tscn index d6d0433b..ed979b09 100644 --- a/Scenes/UI/CtrlInventoryStackedCustom.tscn +++ b/Scenes/UI/CtrlInventoryStackedCustom.tscn @@ -4,7 +4,7 @@ [ext_resource type="PackedScene" uid="uid://bgnxsnv6ltej8" path="res://Scenes/UI/CtrlInventoryStackedListItem.tscn" id="2_woew4"] [ext_resource type="PackedScene" uid="uid://dxgl4vkc313we" path="res://Scenes/UI/CtrlInventoryStackedlistHeaderItem.tscn" id="3_svicc"] -[node name="CtrlInventoryStackedCustom" type="Control" node_paths=PackedStringArray("inventoryGrid", "WeightBar", "VolumeBar")] +[node name="CtrlInventoryStackedCustom" type="Control" node_paths=PackedStringArray("inventoryGrid", "WeightBar", "VolumeBar", "context_menu")] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -19,6 +19,7 @@ WeightBar = NodePath("VBoxContainer/HBoxContainer/WeightBar") VolumeBar = NodePath("VBoxContainer/HBoxContainer/VolumeBar") listItemContainer = ExtResource("2_woew4") listHeaderContainer = ExtResource("3_svicc") +context_menu = NodePath("ContextMenu") [node name="ColorRect" type="ColorRect" parent="."] layout_mode = 1 @@ -65,3 +66,19 @@ text = "Volume:" [node name="VolumeBar" type="ProgressBar" parent="VBoxContainer/HBoxContainer"] layout_mode = 2 size_flags_horizontal = 3 + +[node name="ContextMenu" type="PopupMenu" parent="."] +size = Vector2i(112, 100) +item_count = 5 +item_0/text = "Equip (left)" +item_0/id = 0 +item_1/text = "Equip (right)" +item_1/id = 1 +item_2/text = "Drop" +item_2/id = 2 +item_3/text = "Wear" +item_3/id = 3 +item_4/text = "Disassemble" +item_4/id = 4 + +[connection signal="id_pressed" from="ContextMenu" to="." method="_on_context_menu_item_selected"] diff --git a/Scripts/CtrlInventoryStackedCustom.gd b/Scripts/CtrlInventoryStackedCustom.gd index 597ea673..b0907dce 100644 --- a/Scripts/CtrlInventoryStackedCustom.gd +++ b/Scripts/CtrlInventoryStackedCustom.gd @@ -31,6 +31,8 @@ extends Control @export var max_volume: int = 1000 @export var listItemContainer: PackedScene @export var listHeaderContainer: PackedScene +# Context menu that will show actions for selected items +@export var context_menu: PopupMenu var selectedItem: InventoryItem = null var selectedItems: Array = [] @@ -39,8 +41,6 @@ var group_to_item_mapping: Dictionary = {} var group_controls: Dictionary = {} var last_hovered_item: Node = null -# Context menu that will show actions for selected items -var context_menu: PopupMenu # Dictionary to store header controls var header_controls: Dictionary = {} @@ -65,19 +65,7 @@ signal disassemble_item(items) func _ready(): populate_inventory_list() update_bars() - setup_context_menu() connect_inventory_signals() - - -func _input(event): - if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT and event.pressed: - # Check if the right mouse button was pressed - var mouse_pos = get_global_mouse_position() - var hovered_item = get_hovered_item(mouse_pos) - if hovered_item: - # If the mouse is over an inventory item, show the context menu - show_context_menu() - # Take care of the hovering over items in the grid func _process(_delta): @@ -109,21 +97,11 @@ func _remove_highlight(item: Control): for control in group_controls[group_name]: control.unhighlight() -func setup_context_menu(): - # Initialize and configure the context menu - context_menu = PopupMenu.new() - add_child(context_menu) - context_menu.add_item("Equip (left)", 0) - context_menu.add_item("Equip (right)", 1) - context_menu.add_item("Drop", 2) - context_menu.add_item("Wear", 3) - context_menu.add_item("Disassemble", 4) - context_menu.connect("id_pressed", _on_context_menu_item_selected) - -# Function to show context menu -func show_context_menu(): - # Show the context menu at the center of the screen - context_menu.popup_centered() +# Function to show context menu at specified position +func show_context_menu(myposition: Vector2): + # Create a small Rect2i around the position + var popup_rect = Rect2i(myposition.x, myposition.y, 1, 1) + context_menu.popup(popup_rect) # Handle context menu item selection @@ -202,6 +180,9 @@ func add_header_row_to_grid(): create_header("W") create_header("V") create_header("F") + +func _on_item__right_clicked(clickedItem: Control): + show_context_menu(clickedItem.global_position) # When an item in the inventory is clicked # There are 5 items per row in the grid, but they are treated as a group of 5 @@ -280,6 +261,7 @@ func create_ui_element(property: String, item: InventoryItem, group_name: String # Now we can use the name to get information about the property element.name = property + "_" + str(item.get_name()) element.connect("item_clicked", _on_item_clicked) + element.connect("item_right_clicked", _on_item__right_clicked) # We use groups to keep track of the items element.add_to_group(group_name) return element diff --git a/Scripts/CtrlInventoryStackedListItem.gd b/Scripts/CtrlInventoryStackedListItem.gd index 819a8161..ba421e36 100644 --- a/Scripts/CtrlInventoryStackedListItem.gd +++ b/Scripts/CtrlInventoryStackedListItem.gd @@ -22,6 +22,8 @@ var selected_color: Color = Color(0.5, 0.5, 0.8, 1) # Selected color var is_selected: bool = false signal item_clicked(item: Control) +signal item_right_clicked(item: Control) + # Called when the node enters the scene tree for the first time. func _ready(): @@ -78,11 +80,15 @@ func get_icon() -> Texture: func _on_gui_input(event): if event is InputEventMouseButton: - match event.button_index: - MOUSE_BUTTON_LEFT: - if event.pressed: + if event.pressed: # Check if the mouse button was pressed down + match event.button_index: + MOUSE_BUTTON_LEFT: + # Handle left mouse button click if is_selected: unselect_item() else: select_item() item_clicked.emit(self) + MOUSE_BUTTON_RIGHT: + # Handle right mouse button click + item_right_clicked.emit(self) # Emit a new signal for right-click diff --git a/Scripts/InventoryWindow.gd b/Scripts/InventoryWindow.gd index c3d5da1b..07710942 100644 --- a/Scripts/InventoryWindow.gd +++ b/Scripts/InventoryWindow.gd @@ -44,7 +44,6 @@ func _process(_delta): else: tooltip.visible = false - func _on_inventory_item_mouse_entered(item): is_showing_tooltip = true tooltip_item_name.text = str(item.get_property("name", "")) @@ -244,19 +243,15 @@ func _on_left_hand_equipment_slot_cleared(): func _on_right_hand_equipment_slot_cleared(): item_was_cleared.emit("RightHand") - func _on_equip_right_button_button_up(): RightHandEquipmentSlot.equip(inventory_control.get_selected_inventory_item()) - func _on_equip_left_button_button_up(): LeftHandEquipmentSlot.equip(inventory_control.get_selected_inventory_item()) - func _on_transfer_left_button_button_up(): inventory.transfer(inventory_control.get_selected_inventory_item(), proximity_inventory_control.inventory) - func _on_transfer_right_button_button_up(): var selected_inventory_item: InventoryItem = proximity_inventory_control.get_selected_inventory_item() proximity_inventory_control.inventory.transfer(selected_inventory_item, inventory)