search_menu.gd 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. extends PopupPanel
  2. @onready var item_container: VBoxContainer = $VBoxContainer/ScrollContainer/ItemContainer
  3. @onready var scroll_container: ScrollContainer = $VBoxContainer/ScrollContainer
  4. @onready var search_bar = $VBoxContainer/SearchBar
  5. var node_data = {} #stores node data for each node to display in help popup
  6. signal make_node(command)
  7. func _ready() -> void:
  8. #parse json
  9. var file = FileAccess.open("res://scenes/main/process_help.json", FileAccess.READ)
  10. if file:
  11. var result = JSON.parse_string(file.get_as_text())
  12. if typeof(result) == TYPE_DICTIONARY:
  13. node_data = result
  14. else:
  15. push_error("Invalid JSON")
  16. #honestly not sure what of these is actually doing things
  17. item_container.custom_minimum_size.x = scroll_container.size.x
  18. scroll_container.size_flags_vertical = Control.SIZE_EXPAND_FILL
  19. scroll_container.set("theme_override_constants/maximum_height", 400)
  20. func _on_about_to_popup() -> void:
  21. display_items("") #populate menu when needed
  22. search_bar.clear()
  23. search_bar.grab_focus()
  24. func display_items(filter: String):
  25. # Remove all existing items from the VBoxContainer
  26. for child in item_container.get_children():
  27. child.queue_free()
  28. for key in node_data.keys():
  29. var item = node_data[key]
  30. var title = item.get("title", "")
  31. #filter out input and output nodes
  32. if title == "Input File" or title == "Output File":
  33. continue
  34. var category = item.get("category", "")
  35. var subcategory = item.get("subcategory", "")
  36. var short_desc = item.get("short_description", "")
  37. # If filter is not empty, skip non-matches populate all other buttons
  38. if filter != "":
  39. var filter_lc = filter.to_lower()
  40. if not (filter_lc in title.to_lower() or filter_lc in short_desc.to_lower() or filter_lc in category.to_lower() or filter_lc in subcategory.to_lower()):
  41. continue
  42. var btn = Button.new()
  43. btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL #make buttons wide
  44. btn.alignment = 0 #left align text
  45. btn.clip_text = true #clip off labels that are too long
  46. btn.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS #and replace with ...
  47. if category.to_lower() == "pvoc": #format node names correctly, only show the category for PVOC
  48. btn.text = "%s %s: %s - %s" % [category.to_upper(), subcategory.to_pascal_case(), title, short_desc]
  49. else:
  50. btn.text = "%s: %s - %s" % [subcategory.to_pascal_case(), title, short_desc]
  51. btn.connect("pressed", Callable(self, "_on_item_selected").bind(key)) #pass key (process name) when button is pressed
  52. item_container.add_child(btn)
  53. #resize menu within certain bounds
  54. await get_tree().process_frame
  55. self.size.y = min((item_container.size.y * DisplayServer.screen_get_scale()) + search_bar.size.y + 50, 410 * DisplayServer.screen_get_scale()) #i think this will scale for retina screens but might be wrong
  56. func _on_search_bar_text_changed(new_text: String) -> void:
  57. display_items(new_text)
  58. func _on_item_selected(key: String):
  59. make_node.emit(key) # send out signal to main patch