diff --git a/editor/tree_search.cpp b/editor/tree_search.cpp index d9cf2ef..e33ce44 100644 --- a/editor/tree_search.cpp +++ b/editor/tree_search.cpp @@ -348,10 +348,55 @@ void TreeSearch::_select_first_match() { } } +void TreeSearch::_select_last_match() { + if (matching_entries.size() == 0) { + return; + } + for (int i = ordered_tree_items.size() - 1; i >= 0; i--) { + TreeItem *item = ordered_tree_items[i]; + if (!_vector_has_bsearch(matching_entries, item)) { + continue; + } + _select_item(item); + return; + } +} + +void TreeSearch::_select_previous_match() { + if (matching_entries.size() == 0) { + return; + } + + TreeItem *selected = tree_reference->get_selected(); + if (!selected) { + _select_last_match(); + return; + } + // find [selected_idx] among ordered_tree_items + int selected_idx; + for (int i = ordered_tree_items.size() - 1; i >= 0; i--) { + if (ordered_tree_items[i] == selected) { + selected_idx = i; + break; + } + } + // find first entry before [selected_idx]. + for (int i = MIN(ordered_tree_items.size() - 1, selected_idx) - 1; i >= 0; i--) { + TreeItem *item = ordered_tree_items[i]; + if (_vector_has_bsearch(matching_entries, item)) { + _select_item(item); + return; + } + } + // wrap around. + _select_last_match(); +} + void TreeSearch::_select_next_match() { if (matching_entries.size() == 0) { return; } + TreeItem *selected = tree_reference->get_selected(); if (!selected) { _select_first_match(); @@ -359,7 +404,7 @@ void TreeSearch::_select_next_match() { } // find [selected_idx] among ordered_tree_items - int selected_idx = -1; + int selected_idx; for (int i = 0; i < ordered_tree_items.size(); i++) { if (ordered_tree_items[i] == selected) { selected_idx = i; @@ -443,6 +488,7 @@ TreeSearch::TreeSearch(TreeSearchPanel *p_search_panel) { search_panel = p_search_panel; search_panel->connect(LW_NAME(text_submitted), callable_mp(this, &TreeSearch::_select_next_match)); search_panel->connect(LW_NAME(Close), callable_mp(this, &TreeSearch::_on_search_panel_closed)); + search_panel->connect("select_previous_match", callable_mp(this, &TreeSearch::_select_previous_match)); } /* !TreeSearch */ @@ -453,11 +499,19 @@ void TreeSearchPanel::_initialize_controls() { line_edit_search = memnew(LineEdit); check_button_filter_highlight = memnew(CheckBox); close_button = memnew(Button); + find_next_button = memnew(Button); + find_prev_button = memnew(Button); label_filter = memnew(Label); line_edit_search->set_placeholder(TTR("Search tree")); close_button->set_theme_type_variation(LW_NAME(FlatButton)); + find_next_button->set_theme_type_variation(LW_NAME(FlatButton)); + find_prev_button->set_theme_type_variation(LW_NAME(FlatButton)); + + close_button->set_tooltip_text("Hide"); + find_next_button->set_tooltip_text("Next Match"); + find_prev_button->set_tooltip_text("Previous Match"); // positioning and sizing set_anchors_and_offsets_preset(LayoutPreset::PRESET_BOTTOM_WIDE); @@ -467,6 +521,8 @@ void TreeSearchPanel::_initialize_controls() { _add_spacer(0.25); // otherwise the lineedits expand margin touches the left border. add_child(line_edit_search); + add_child(find_prev_button); + add_child(find_next_button); _add_spacer(0.25); add_child(check_button_filter_highlight); @@ -489,10 +545,13 @@ void TreeSearchPanel::_notification(int p_what) { // close callbacks close_button->connect(LW_NAME(pressed), Callable(this, LW_NAME(set_visible)).bind(false)); close_button->connect(LW_NAME(pressed), Callable(this, LW_NAME(emit_signal)).bind(LW_NAME(Close))); - close_button->set_shortcut(LW_GET_SHORTCUT("limbo_ai/hide_tree_search")); + close_button->set_shortcut(LW_GET_SHORTCUT("limbo_ai/hide_tree_search")); // TODO: use internal shortcut. // search callbacks Callable c_update_requested = Callable(this, LW_NAME(emit_signal)).bind("update_requested"); - Callable c_text_submitted = Callable((Object *)this, LW_NAME(emit_signal)).bind(LW_NAME(text_submitted)); + Callable c_text_submitted = Callable(this, LW_NAME(emit_signal)).bind(LW_NAME(text_submitted)); + Callable c_select_previous_match = Callable(this, LW_NAME(emit_signal)).bind("select_previous_match"); + find_next_button->connect(LW_NAME(pressed), c_text_submitted); + find_prev_button->connect(LW_NAME(pressed), c_select_previous_match); line_edit_search->connect(LW_NAME(text_changed), c_update_requested.unbind(1)); check_button_filter_highlight->connect(LW_NAME(pressed), c_update_requested); @@ -501,6 +560,8 @@ void TreeSearchPanel::_notification(int p_what) { } case NOTIFICATION_THEME_CHANGED: { BUTTON_SET_ICON(close_button, get_theme_icon(LW_NAME(Close), LW_NAME(EditorIcons))); + BUTTON_SET_ICON(find_prev_button, get_theme_icon("MoveUp", LW_NAME(EditorIcons))); + BUTTON_SET_ICON(find_next_button, get_theme_icon("MoveDown", LW_NAME(EditorIcons))); label_filter->set_text(TTR("Filter")); break; } @@ -510,6 +571,7 @@ void TreeSearchPanel::_notification(int p_what) { void TreeSearchPanel::_bind_methods() { ADD_SIGNAL(MethodInfo("update_requested")); ADD_SIGNAL(MethodInfo(LW_NAME(text_submitted))); + ADD_SIGNAL(MethodInfo("select_previous_match")); ADD_SIGNAL(MethodInfo(LW_NAME(Close))); } diff --git a/editor/tree_search.h b/editor/tree_search.h index fec49e1..9f85f3e 100644 --- a/editor/tree_search.h +++ b/editor/tree_search.h @@ -89,6 +89,9 @@ private: void _select_item(TreeItem *p_item); void _select_first_match(); + void _select_last_match(); + + void _select_previous_match(); void _select_next_match(); void _on_search_panel_closed(); @@ -127,6 +130,8 @@ class TreeSearchPanel : public HFlowContainer { private: Button *toggle_button_filter_highlight; Button *close_button; + Button *find_next_button; + Button *find_prev_button; Label *label_filter; LineEdit *line_edit_search; CheckBox *check_button_filter_highlight;