3939#include " scene/gui/box_container.h"
4040#include " scene/gui/button.h"
4141#include " scene/gui/check_box.h"
42+ #include " scene/gui/check_button.h"
4243#include " scene/gui/file_dialog.h"
4344#include " scene/gui/grid_container.h"
4445#include " scene/gui/label.h"
4546#include " scene/gui/line_edit.h"
4647#include " scene/gui/progress_bar.h"
48+ #include " scene/gui/tab_container.h"
4749#include " scene/gui/tree.h"
4850
4951const char *FindInFiles::SIGNAL_RESULT_FOUND = " result_found" ;
@@ -700,10 +702,11 @@ FindInFilesPanel::FindInFilesPanel() {
700702
701703 {
702704 HBoxContainer *hbc = memnew (HBoxContainer);
705+ hbc->set_alignment (BoxContainer::ALIGNMENT_END);
703706
704- Label *find_label = memnew (Label);
705- find_label ->set_text (TTRC (" Find:" ));
706- hbc->add_child (find_label );
707+ _find_label = memnew (Label);
708+ _find_label ->set_text (TTRC (" Find:" ));
709+ hbc->add_child (_find_label );
707710
708711 _search_text_label = memnew (Label);
709712 _search_text_label->set_text_overrun_behavior (TextServer::OVERRUN_TRIM_ELLIPSIS);
@@ -724,6 +727,12 @@ FindInFilesPanel::FindInFilesPanel() {
724727 _status_label->set_focus_mode (FOCUS_ACCESSIBILITY);
725728 hbc->add_child (_status_label);
726729
730+ _keep_results_button = memnew (CheckButton);
731+ _keep_results_button->set_text (TTRC (" Keep Results" ));
732+ _keep_results_button->set_tooltip_text (TTRC (" Keep these results and show subsequent results in a new window" ));
733+ _keep_results_button->set_pressed (false );
734+ hbc->add_child (_keep_results_button);
735+
727736 _refresh_button = memnew (Button);
728737 _refresh_button->set_text (TTRC (" Refresh" ));
729738 _refresh_button->connect (SceneStringName (pressed), callable_mp (this , &FindInFilesPanel::_on_refresh_button_clicked));
@@ -804,6 +813,16 @@ void FindInFilesPanel::set_replace_text(const String &text) {
804813 _replace_line_edit->set_text (text);
805814}
806815
816+ bool FindInFilesPanel::is_keep_results () const {
817+ return _keep_results_button->is_pressed ();
818+ }
819+
820+ void FindInFilesPanel::set_search_labels_visibility (bool p_visible) {
821+ _find_label->set_visible (p_visible);
822+ _search_text_label->set_visible (p_visible);
823+ _close_button->set_visible (p_visible);
824+ }
825+
807826void FindInFilesPanel::clear () {
808827 _file_items.clear ();
809828 _file_items_results_count.clear ();
@@ -1244,3 +1263,205 @@ void FindInFilesPanel::_bind_methods() {
12441263
12451264 ADD_SIGNAL (MethodInfo (SIGNAL_CLOSE_BUTTON_CLICKED));
12461265}
1266+
1267+ // -----------------------------------------------------------------------------
1268+
1269+ FindInFilesContainer::FindInFilesContainer () {
1270+ const Ref<StyleBox> bottom_panel_style = EditorNode::get_singleton ()->get_editor_theme ()->get_stylebox (SNAME (" BottomPanel" ), EditorStringName (EditorStyles));
1271+ if (bottom_panel_style.is_valid ()) {
1272+ add_theme_constant_override (" margin_top" , -bottom_panel_style->get_margin (SIDE_TOP));
1273+ add_theme_constant_override (" margin_left" , -bottom_panel_style->get_margin (SIDE_LEFT));
1274+ add_theme_constant_override (" margin_right" , -bottom_panel_style->get_margin (SIDE_RIGHT));
1275+ add_theme_constant_override (" margin_bottom" , -bottom_panel_style->get_margin (SIDE_BOTTOM));
1276+ }
1277+
1278+ _tabs = memnew (TabContainer);
1279+ _tabs->set_tabs_visible (false );
1280+ add_child (_tabs);
1281+
1282+ _tabs->set_drag_to_rearrange_enabled (true );
1283+ _tabs->get_tab_bar ()->set_select_with_rmb (true );
1284+ _tabs->get_tab_bar ()->set_tab_close_display_policy (TabBar::CLOSE_BUTTON_SHOW_ACTIVE_ONLY);
1285+ _tabs->get_tab_bar ()->connect (" tab_close_pressed" , callable_mp (this , &FindInFilesContainer::_on_tab_close_pressed));
1286+ _tabs->get_tab_bar ()->connect (SceneStringName (gui_input), callable_mp (this , &FindInFilesContainer::_bar_input));
1287+
1288+ _tabs_context_menu = memnew (PopupMenu);
1289+ add_child (_tabs_context_menu);
1290+ _tabs_context_menu->add_item (TTRC (" Close Tab" ), PANEL_CLOSE);
1291+ _tabs_context_menu->add_item (TTRC (" Close Other Tabs" ), PANEL_CLOSE_OTHERS);
1292+ _tabs_context_menu->add_item (TTRC (" Close Tabs to the Right" ), PANEL_CLOSE_RIGHT);
1293+ _tabs_context_menu->add_item (TTRC (" Close All Tabs" ), PANEL_CLOSE_ALL);
1294+ _tabs_context_menu->connect (SceneStringName (id_pressed), callable_mp (this , &FindInFilesContainer::_bar_menu_option));
1295+ }
1296+
1297+ FindInFilesPanel *FindInFilesContainer::_create_new_panel () {
1298+ int index = _tabs->get_current_tab ();
1299+ FindInFilesPanel *panel = memnew (FindInFilesPanel);
1300+ _tabs->add_child (panel);
1301+ _tabs->move_child (panel, index + 1 ); // New panel is added after the current activated panel.
1302+ _tabs->set_current_tab (index + 1 );
1303+ _update_bar_visibility ();
1304+
1305+ panel->connect (FindInFilesPanel::SIGNAL_RESULT_SELECTED, callable_mp (this , &FindInFilesContainer::_on_find_in_files_result_selected));
1306+ panel->connect (FindInFilesPanel::SIGNAL_FILES_MODIFIED, callable_mp (this , &FindInFilesContainer::_on_find_in_files_modified_files));
1307+ panel->connect (FindInFilesPanel::SIGNAL_CLOSE_BUTTON_CLICKED, callable_mp (this , &FindInFilesContainer::_on_find_in_files_close_button_clicked).bind (panel));
1308+ return panel;
1309+ }
1310+
1311+ FindInFilesPanel *FindInFilesContainer::_get_current_panel () {
1312+ return Object::cast_to<FindInFilesPanel>(_tabs->get_current_tab_control ());
1313+ }
1314+
1315+ FindInFilesPanel *FindInFilesContainer::get_panel_for_results (const String &p_label) {
1316+ FindInFilesPanel *panel = nullptr ;
1317+ // Prefer the current panel.
1318+ if (_get_current_panel () && !_get_current_panel ()->is_keep_results ()) {
1319+ panel = _get_current_panel ();
1320+ } else {
1321+ // Find the first panel which does not keep results.
1322+ for (int i = 0 ; i < _tabs->get_tab_count (); i++) {
1323+ FindInFilesPanel *p = Object::cast_to<FindInFilesPanel>(_tabs->get_tab_control (i));
1324+ if (p && !p->is_keep_results ()) {
1325+ panel = p;
1326+ _tabs->set_current_tab (i);
1327+ break ;
1328+ }
1329+ }
1330+
1331+ if (!panel) {
1332+ panel = _create_new_panel ();
1333+ }
1334+ }
1335+ _tabs->set_tab_title (_tabs->get_current_tab (), p_label);
1336+ return panel;
1337+ }
1338+
1339+ void FindInFilesContainer::_bind_methods () {
1340+ ADD_SIGNAL (MethodInfo (" result_selected" ,
1341+ PropertyInfo (Variant::STRING, " path" ),
1342+ PropertyInfo (Variant::INT, " line_number" ),
1343+ PropertyInfo (Variant::INT, " begin" ),
1344+ PropertyInfo (Variant::INT, " end" )));
1345+
1346+ ADD_SIGNAL (MethodInfo (" files_modified" , PropertyInfo (Variant::STRING, " paths" )));
1347+
1348+ ADD_SIGNAL (MethodInfo (" close_button_clicked" ));
1349+ }
1350+
1351+ void FindInFilesContainer::_notification (int p_what) {
1352+ switch (p_what) {
1353+ case NOTIFICATION_THEME_CHANGED: {
1354+ const Ref<StyleBox> bottom_panel_style = EditorNode::get_singleton ()->get_editor_theme ()->get_stylebox (SNAME (" BottomPanel" ), EditorStringName (EditorStyles));
1355+ if (bottom_panel_style.is_valid ()) {
1356+ const int margin_top = -bottom_panel_style->get_margin (SIDE_TOP);
1357+ const int margin_left = -bottom_panel_style->get_margin (SIDE_LEFT);
1358+ const int margin_right = -bottom_panel_style->get_margin (SIDE_RIGHT);
1359+ const int margin_bottom = -bottom_panel_style->get_margin (SIDE_BOTTOM);
1360+
1361+ if (get_theme_constant (" margin_top" ) != margin_top) {
1362+ add_theme_constant_override (" margin_top" , margin_top);
1363+ }
1364+ if (get_theme_constant (" margin_left" ) != margin_left) {
1365+ add_theme_constant_override (" margin_left" , margin_left);
1366+ }
1367+ if (get_theme_constant (" margin_right" ) != margin_right) {
1368+ add_theme_constant_override (" margin_right" , margin_right);
1369+ }
1370+ if (get_theme_constant (" margin_bottom" ) != margin_bottom) {
1371+ add_theme_constant_override (" margin_bottom" , margin_bottom);
1372+ }
1373+ }
1374+ } break ;
1375+ }
1376+ }
1377+
1378+ void FindInFilesContainer::_on_find_in_files_result_selected (const String &p_fpath, int p_line_number, int p_begin, int p_end) {
1379+ emit_signal (SNAME (" result_selected" ), p_fpath, p_line_number, p_begin, p_end);
1380+ }
1381+
1382+ void FindInFilesContainer::_on_find_in_files_modified_files (const PackedStringArray &p_paths) {
1383+ emit_signal (SNAME (" files_modified" ), p_paths);
1384+ }
1385+
1386+ void FindInFilesContainer::_on_find_in_files_close_button_clicked (FindInFilesPanel *p_panel) {
1387+ ERR_FAIL_COND_MSG (p_panel->get_parent () != _tabs, " This panel is not a child!" );
1388+ _tabs->remove_child (p_panel);
1389+ p_panel->queue_free ();
1390+ _update_bar_visibility ();
1391+ if (_tabs->get_tab_count () == 0 ) {
1392+ emit_signal (SNAME (" close_button_clicked" ));
1393+ }
1394+ }
1395+
1396+ void FindInFilesContainer::_on_tab_close_pressed (int p_tab) {
1397+ FindInFilesPanel *panel = Object::cast_to<FindInFilesPanel>(_tabs->get_tab_control (p_tab));
1398+ if (panel) {
1399+ _on_find_in_files_close_button_clicked (panel);
1400+ }
1401+ }
1402+
1403+ void FindInFilesContainer::_update_bar_visibility () {
1404+ if (!_update_bar) {
1405+ return ;
1406+ }
1407+
1408+ // If tab count <= 1, behaves like this is not a TabContainer and the bar is hidden.
1409+ bool bar_visible = _tabs->get_tab_count () > 1 ;
1410+ _tabs->set_tabs_visible (bar_visible);
1411+
1412+ // Hide or show the search labels based on the visibility of the bar, as the search terms are displayed in the title of each tab.
1413+ for (int i = 0 ; i < _tabs->get_tab_count (); i++) {
1414+ FindInFilesPanel *panel = Object::cast_to<FindInFilesPanel>(_tabs->get_tab_control (i));
1415+ if (panel) {
1416+ panel->set_search_labels_visibility (!bar_visible);
1417+ }
1418+ }
1419+ }
1420+
1421+ void FindInFilesContainer::_bar_menu_option (int p_option) {
1422+ int tab_index = _tabs->get_current_tab ();
1423+ switch (p_option) {
1424+ case PANEL_CLOSE: {
1425+ _on_tab_close_pressed (tab_index);
1426+ } break ;
1427+ case PANEL_CLOSE_OTHERS: {
1428+ _update_bar = false ;
1429+ FindInFilesPanel *panel = Object::cast_to<FindInFilesPanel>(_tabs->get_tab_control (tab_index));
1430+ for (int i = _tabs->get_tab_count () - 1 ; i >= 0 ; i--) {
1431+ FindInFilesPanel *p = Object::cast_to<FindInFilesPanel>(_tabs->get_tab_control (i));
1432+ if (p != panel) {
1433+ _on_find_in_files_close_button_clicked (p);
1434+ }
1435+ }
1436+ _update_bar = true ;
1437+ _update_bar_visibility ();
1438+ } break ;
1439+ case PANEL_CLOSE_RIGHT: {
1440+ _update_bar = false ;
1441+ for (int i = _tabs->get_tab_count () - 1 ; i > tab_index; i--) {
1442+ _on_tab_close_pressed (i);
1443+ }
1444+ _update_bar = true ;
1445+ _update_bar_visibility ();
1446+ } break ;
1447+ case PANEL_CLOSE_ALL: {
1448+ _update_bar = false ;
1449+ for (int i = _tabs->get_tab_count () - 1 ; i >= 0 ; i--) {
1450+ _on_tab_close_pressed (i);
1451+ }
1452+ _update_bar = true ;
1453+ } break ;
1454+ }
1455+ }
1456+
1457+ void FindInFilesContainer::_bar_input (const Ref<InputEvent> &p_input) {
1458+ int tab_id = _tabs->get_tab_bar ()->get_hovered_tab ();
1459+ Ref<InputEventMouseButton> mb = p_input;
1460+
1461+ if (tab_id >= 0 && mb.is_valid () && mb->is_pressed () && mb->get_button_index () == MouseButton::RIGHT) {
1462+ _tabs_context_menu->set_item_disabled (_tabs_context_menu->get_item_index (PANEL_CLOSE_RIGHT), tab_id == _tabs->get_tab_count () - 1 );
1463+ _tabs_context_menu->set_position (_tabs->get_tab_bar ()->get_screen_position () + mb->get_position ());
1464+ _tabs_context_menu->reset_size ();
1465+ _tabs_context_menu->popup ();
1466+ }
1467+ }
0 commit comments