extends Object var tts var node var position_in_children = 0 var column_in_row = 0 func get_siblings(): var parent = node.get_parent() if parent: return parent.get_children() return null func singular_or_plural(count, singular, plural): if count == 1: return singular else: return plural func left_click(item := node): var click = InputEventMouseButton.new() click.button_index = BUTTON_LEFT click.pressed = true if item is Node: click.position = item.rect_global_position node.get_tree().input_event(click) click.pressed = false node.get_tree().input_event(click) func close_key_event_dialog(): node.get_ok().emit_signal("pressed") var dialog_close_timer = Timer.new() func accept_dialog_focus(): if not dialog_close_timer.is_connected("timeout", self, "close_key_event_dialog"): dialog_close_timer.connect("timeout", self, "close_key_event_dialog") dialog_close_timer.one_shot = true dialog_close_timer.start(5) if dialog_close_timer.get_parent() == null: node.add_child(dialog_close_timer) func button_focus(): var text if node.text: text = node.text if text: tts.speak("%s: button" % text, false) else: tts.speak("button", false) func texturebutton_focus(): tts.speak("button", false) func item_list_focus(): var count = node.get_item_count() var selected = node.get_selected_items() tts.speak("list, %s %s" % [count, singular_or_plural(count, "item", "items")], false) tts.speak(selected, false) func item_list_item_selected(index): tts.speak("Selected", false) func item_list_multi_selected(index, selected): tts.speak("Multiselect", false) func item_list_nothing_selected(): tts.speak("Nothing selected", false) func item_list_input(event): var old_pos = position_in_children if event.is_action_pressed("ui_up"): node.accept_event() if position_in_children == 0: return position_in_children -= 1 elif event.is_action_pressed("ui_down"): node.accept_event() if position_in_children >= node.get_item_count()-1: return position_in_children += 1 elif event.is_action_pressed("ui_home"): node.accept_event() position_in_children = 0 elif event.is_action_pressed("ui_end"): node.accept_event() position_in_children = node.get_item_count()-1 if old_pos != position_in_children: var text = node.get_item_text(position_in_children) tts.speak("%s: %s of %s" % [text, position_in_children+1, node.get_item_count()], false) func label_focus(): var text = node.text if text == "": text = "blank" tts.speak(text, false) func line_edit_focus(): var text = "blank" if node.secret: text = "password" elif node.text != "": text = node.text elif node.placeholder_text != "": text = node.placeholder_text var type = "editable text" if not node.editable: type = "text" tts.speak("%s: %s" % [text, type], false) func text_deleted(text): tts.speak("%s deleted" % text, true) func text_inserted(text): tts.speak(text, true) var old_pos func check_caret_moved(): var pos = node.caret_position if old_pos != null and old_pos != pos: var text = node.text if pos > len(text)-1: tts.speak("blank", true) else: tts.speak(text[pos], true) old_pos = pos elif old_pos == null: old_pos = pos func menu_button_focus(): tts.speak(node.text + ": menu", false) func popup_menu_focus(): tts.speak("menu", false) func popup_menu_item_id_focus(id): print("id: %s" % id) print("count: %s" % node.get_item_count()) var item = node.get_item_text(id) var submenu = node.get_item_submenu(id) var tooltip = node.get_item_tooltip(position_in_children) var disabled = node.is_item_disabled(id) if item and tooltip: item += ": " item += tooltip elif tooltip: item = tooltip var shortcut = node.get_item_shortcut(position_in_children) if shortcut != null and shortcut.get_as_text() != "None": item += ": "+shortcut.get_as_text() if item == "": item = "Unlabelled" if submenu: item += ": menu" if disabled: item += ": disabled" item += ": " + str(id + 1) + " of " + str(node.get_item_count()) tts.speak(item, true) func tree_item_render(): var focused_tree_item = node.get_selected() var result = "" for i in range(node.columns): result += focused_tree_item.get_text(i) + ": " if focused_tree_item.get_children(): if focused_tree_item.collapsed: result += "collapsed " else: result += "expanded " result += "tree item" if focused_tree_item.is_selected(0): result += ": selected" tts.speak(result, true) var prev_selected_cell var button_index func tree_item_selected(): button_index = null var cell = node.get_selected() if cell != prev_selected_cell: tree_item_render() prev_selected_cell = cell else: var text = "" for i in range(node.columns): if cell.is_selected(i): var title = node.get_column_title(i) if title: text += title + ": " var column_text = cell.get_text(i) if column_text: text += column_text + ", " var button_count = cell.get_button_count(i) if button_count != 0: button_index = 0 text += str(button_count) + " " + singular_or_plural(button_count, "button", "buttons") + ", " var button_tooltip = cell.get_button_tooltip(i, button_index) if button_tooltip: text += button_tooltip + ": button, " if button_count > 1: text += "Use Home and End to switch focus, " if text != "": tts.speak(text, true) else: tts.speak("blank", true) func tree_item_multi_select(item, column, selected): if selected: tts.speak("selected", true) else: tts.speak("unselected", true) func tree_input(event): var item = node.get_selected() var column if item: for i in range(node.columns): if item.is_selected(i): column = i break if item and column and button_index != null: if event.is_action_pressed("ui_accept"): node.accept_event() return node.emit_signal("button_pressed", item, column, button_index + 1) var new_button_index = button_index if event.is_action_pressed("ui_home"): node.accept_event() new_button_index += 1 if new_button_index >= item.get_button_count(column): new_button_index = 0 elif event.is_action_pressed("ui_end"): node.accept_event() new_button_index -= 1 if new_button_index < 0: new_button_index = item.get_button_count(column) - 1 if new_button_index != button_index: button_index = new_button_index var tooltip = item.get_button_tooltip(column, button_index) var text = "" if tooltip: text += tooltip + ": " text += "button" tts.speak(text, true) func tree_focus(): if node.get_selected(): tree_item_render() else: tts.speak("tree", true) func tree_item_collapse(item): if node.has_focus(): if item.collapsed: tts.speak("collapsed", true) else: tts.speak("expanded", true) func tab_container_focus(): var text = node.get_tab_title(node.current_tab) text += ": tab: " + str(node.current_tab + 1) + " of " + str(node.get_tab_count()) tts.speak(text, false) func tab_container_tab_changed(tab): tts.stop() tab_container_focus() func tab_container_input(event): var new_tab = node.current_tab if event.is_action_pressed("ui_right"): node.accept_event() new_tab += 1 elif event.is_action_pressed("ui_left"): node.accept_event() new_tab -= 1 if new_tab < 0: new_tab = node.get_tab_count() - 1 elif new_tab >= node.get_tab_count(): new_tab = 0 if node.current_tab != new_tab: node.current_tab = new_tab func focused(): print("Focus: %s" % node) tts.stop() var parent = node.get_parent() if parent is EditorProperty and parent.label: tts.speak(parent.label, false) if node is MenuButton: menu_button_focus() elif node is AcceptDialog: accept_dialog_focus() elif node is Button: button_focus() elif node.get_class() == "EditorInspectorSection": editor_inspector_section_focus() elif node is ItemList: item_list_focus() elif node is Label: label_focus() elif node is LineEdit: line_edit_focus() elif node is PopupMenu: popup_menu_focus() elif node is TabContainer: tab_container_focus() elif node is TextureButton: texturebutton_focus() elif node is Tree: tree_focus() else: print("No handler") if node.hint_tooltip: tts.speak(node.hint_tooltip, false) func unfocused(): print("Unfocused") position_in_children = 0 func gui_input(event): if node is TabContainer: return tab_container_input(event) elif node is ItemList: return item_list_input(event) elif node is LineEdit: return check_caret_moved() elif node is Tree: return tree_input(event) elif node.get_class() == "EditorInspectorSection": return editor_inspector_section_input(event) elif event.is_action_pressed("ui_left"): return node.accept_event() elif event.is_action_pressed("ui_right"): return node.accept_event() elif event.is_action_pressed("ui_up"): return node.accept_event() elif event.is_action_pressed("ui_down"): return node.accept_event() func is_in_bar(): var parent = node.get_parent() if parent and parent is Container: for child in parent.get_children(): if child and not is_focusable(child): return false return true return false func is_focusable(node): if node is TabContainer: return true if node.get_class() == "EditorInspectorSection": return true if node is Container or node is Panel or node is Separator or node is ScrollBar or node is Popup or node.get_class() == "Control": return false return true func editor_inspector_section_focus(): var child = node.get_children()[0] var expanded = child.is_visible_in_tree() tts.speak("editor inspector section:", true) if expanded: tts.speak("expanded", false) else: tts.speak("collapsed", false) func editor_inspector_section_input(event): if event.is_action_pressed("ui_accept"): left_click() var child = node.get_children()[0] var expanded = child.is_visible_in_tree() if expanded: tts.speak("expanded", true) else: tts.speak("collapsed", true) func _init(tts, node): if node.is_in_group("accessible"): return node.add_to_group("accessible") self.tts = tts self.node = node if is_focusable(node): node.set_focus_mode(Control.FOCUS_ALL) node.connect("focus_entered", self, "focused") node.connect("mouse_entered", self, "focused") node.connect("focus_exited", self, "unfocused") node.connect("mouse_exited", self, "unfocused") node.connect("gui_input", self, "gui_input") if node is ItemList: node.connect("item_selected", self, "item_list_item_selected") node.connect("multi_selected", self, "item_list_multi_selected") node.connect("nothing_selected", self, "item_list_nothing_selected") # elif node is LineEdit: # node.connect("text_deleted", self, "text_deleted") # node.connect("text_inserted", self, "text_inserted") elif node is PopupMenu: node.connect("id_focused", self, "popup_menu_item_id_focus") elif node is TabContainer: node.connect("tab_changed", self, "tab_container_tab_changed") elif node is Tree: node.connect("item_collapsed", self, "tree_item_collapse") node.connect("multi_selected", self, "tree_item_multi_select") if node.select_mode == Tree.SELECT_MULTI: node.connect("cell_selected", self, "tree_item_selected") else: node.connect("item_selected", self, "tree_item_selected") node.connect("tree_exiting", self, "free")