extends TouchVerticalContainer class_name Stage signal save # (database_entry: Dictionary) signal discard # () const OPTION_SETS_FILE_PATH: String = "user://option_sets.json" const OPTION_SETS_NOT_AVAILABLE: String = "--" const OPTION_SETS_TREE_STRUCTURE := { "place": null, "anesthesia": null, "first_assistant": null, "type": { "sub_type": { "sub_sub_type": null, "pathology": null, "intervention": null, } } } var staged_entry_hash: int var option_sets: Dictionary onready var confirm_action := get_node("/root/main/confirm_action") as ConfirmationDialog onready var process_id := get_node("controls/process_id") as LineEdit onready var surgery_id := get_node("controls/surgery_id") as LineEdit onready var date := get_node("controls/date_picker") as DatePicker onready var place := get_node("controls/place") as OptionSet onready var anesthesia := get_node("controls/anesthesia") as OptionSet onready var first_assistant := get_node("controls/first_assistant") as OptionSet onready var type := get_node("controls/type") as OptionSet onready var sub_type := get_node("controls/sub_type") as OptionSet onready var sub_sub_type := get_node("controls/sub_sub_type") as OptionSet onready var pathology := get_node("controls/pathology") as OptionSet onready var intervention := get_node("controls/intervention") as OptionSet onready var is_urgency := get_node("controls/is_urgency") as Button onready var notes := get_node("controls/notes") as LineEdit onready var save_button := get_node("controls/save") as Button onready var discard_button := get_node("controls/discard") as Button func _init(): exclude_controls = ["date_picker", "save", "discard"] load_option_sets() func _ready(): save_button.connect("pressed", self, "save_action") discard_button.connect("pressed", self, "discard_action") for it in get_node("controls").get_children(): if it is LineEdit: it.connect("focus_entered", it, "set", ["caret_position", it.max_length]) it.connect("focus_exited", it, "deselect") # Map option sets buttons. var option_sets_map := { "place": place, "anesthesia": anesthesia, "first_assistant": first_assistant, "type": type, "sub_type": sub_type, "sub_sub_type": sub_sub_type, "pathology": pathology, "intervention": intervention } for key in option_sets_map: var button := option_sets_map[key].get_node("options") as Button # @DAM Maybe rename "options". Also requires rename on option_set. button.connect("pressed", self, "show_options", [key]) func show_options(field: String): var option_set_field := self[field] as OptionSet var options: Array match field: "sub_type": options = option_sets.get("type", {}).get(type.text, {}).get(field, {}).keys() "sub_sub_type", "pathology", "intervention": options = option_sets.get("type", {}).get(type.text, {}).get("sub_type", {}).get(sub_type.text, {}).get(field, {}).keys() _: options = option_sets.get(field, {}).keys() if options.size() == 0: options.append(OPTION_SETS_NOT_AVAILABLE) options.sort() option_set_field.show_options(options) func save_action(): self.visible = false var staged_entry := get_stage() gather_option_sets(staged_entry) store_option_sets() emit_signal("save", staged_entry) func discard_action(): if get_stage().hash() != staged_entry_hash: confirm_action.window_title = "DISCARD ENTRY" confirm_action.dialog_text = "Do you want to discard the changes made?" confirm_action.connect("confirmed", self, "discard_action_confirmed", [], CONNECT_ONESHOT) confirm_action.show_modal(true) else: discard_action_confirmed() func discard_action_confirmed(): self.visible = false emit_signal("discard") func set_stage(entry: Dictionary): staged_entry_hash = entry.hash() process_id.text = entry.process_id surgery_id.text = entry.surgery_id date.set_date(entry.date_year, entry.date_month, entry.date_day) place.text = entry.place anesthesia.text = entry.anesthesia first_assistant.text = entry.first_assistant type.text = entry.type sub_type.text = entry.sub_type sub_sub_type.text = entry.sub_sub_type pathology.text = entry.pathology intervention.text = entry.intervention is_urgency.pressed = entry.is_urgency notes.text = entry.notes self.scroll_vertical = 0 func get_stage() -> Dictionary: var entry := { "process_id": process_id.text, "surgery_id": surgery_id.text, "date_year": date.get_year(), "date_month": date.get_month(), "date_day": date.get_day(), "place": place.text, "anesthesia": anesthesia.text, "first_assistant": first_assistant.text, "type": type.text, "sub_type": sub_type.text, "sub_sub_type": sub_sub_type.text, "pathology": pathology.text, "intervention": intervention.text, "is_urgency": is_urgency.pressed, "notes": notes.text, } return entry func sanitize_option_sets(entry: Dictionary, blueprint: Dictionary = OPTION_SETS_TREE_STRUCTURE): # Delete extra keys. var keys_to_delete: Array for key in entry: if blueprint.has(key) == false: keys_to_delete.append(key) for key in keys_to_delete: entry.erase(key) for key in blueprint: # Add missing keys. if typeof(entry.get(key)) != TYPE_DICTIONARY: entry[key] = {} # Process sub-keys if blueprint[key] != null: for sub_key in entry[key]: if typeof(entry[key][sub_key]) != TYPE_DICTIONARY: entry[key][sub_key] = {} sanitize_option_sets(entry[key][sub_key], blueprint[key]) func gather_option_sets(entry: Dictionary, target: Dictionary = option_sets, blueprint: Dictionary = OPTION_SETS_TREE_STRUCTURE): for key in blueprint: if target.get(key) == null: target[key] = {} var value := (entry[key] as String).strip_edges() if value == "" || value == OPTION_SETS_NOT_AVAILABLE: continue if target[key].has(value) == false: target[key][value] = null if blueprint[key] == null else {} if blueprint[key] != null: gather_option_sets(entry, target[key][value], blueprint[key]) func import_option_sets(file_path: String = OPTION_SETS_FILE_PATH): load_option_sets(file_path) sanitize_option_sets(option_sets) store_option_sets() func load_option_sets(file_path: String = OPTION_SETS_FILE_PATH): var file := File.new() file.open(file_path, File.READ_WRITE) var file_content = file.get_as_text() file.close() var parse_result = JSON.parse(file_content) if parse_result.error == OK && typeof(parse_result.result) == TYPE_DICTIONARY: option_sets = parse_result.result else: option_sets = {} push_error("Failed to parse option sets file: '%s'.") func store_option_sets(file_path: String = OPTION_SETS_FILE_PATH): var file := File.new() file.open(file_path, File.WRITE) file.store_string(JSON.print(option_sets, "" if file_path == OPTION_SETS_FILE_PATH else "\t")) file.close() func clear_option_sets(save_changes: bool = false): option_sets = {} if save_changes: store_option_sets()