use crate::app::TextEditor; use eframe::egui; pub(crate) fn find_window(app: &mut TextEditor, ctx: &egui::Context) { let visuals = &ctx.style().visuals; let mut should_close = false; let mut query_changed = false; let mut should_focus_editor = false; let just_opened = app.show_find && !app.prev_show_find; if just_opened && !app.find_query.is_empty() { app.update_find_matches(); if app.current_match_index.is_some() { app.select_current_match(ctx); app.should_select_current_match = true; } } let focus_requested = ctx.memory(|mem| { mem.data .get_temp::(egui::Id::new("focus_find_input")) .unwrap_or(false) }); let top_right_pos = egui::Pos2::new(ctx.available_rect().right(), 22.0); egui::Window::new("") .collapsible(false) .resizable(false) .movable(true) .title_bar(false) .default_pos(top_right_pos) .fade_in(true) .fade_out(true) .frame(egui::Frame { fill: visuals.window_fill, stroke: visuals.window_stroke, corner_radius: egui::CornerRadius::same(8), shadow: visuals.window_shadow, inner_margin: egui::Margin::same(16), outer_margin: egui::Margin::same(0), }) .show(ctx, |ui| { ui.vertical(|ui| { ui.horizontal(|ui| { let arrow_text = if app.show_replace_section { "⏷" } else { "⏵" }; if ui.button(arrow_text).clicked() { app.show_replace_section = !app.show_replace_section; } ui.label("Find:"); let response = ui.add( egui::TextEdit::singleline(&mut app.find_query) .desired_width(250.0) .hint_text("Enter search text..."), ); if response.changed() { query_changed = true; } if just_opened || focus_requested || app.focus_find { response.request_focus(); app.focus_find = false; } if response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) { app.find_next(ctx); response.request_focus(); } }); if app.show_replace_section { ui.horizontal(|ui| { ui.add_space(4.0); ui.label("Replace:"); let _replace_response = ui.add( egui::TextEdit::singleline(&mut app.replace_query) .desired_width(250.0) .hint_text("Enter replacement text..."), ); }); } ui.add_space(8.0); ui.horizontal(|ui| { let case_sensitive_changed = ui .checkbox(&mut app.case_sensitive_search, "Case sensitive") .changed(); if case_sensitive_changed { query_changed = true; } if app.show_replace_section { ui.add_space(8.0); let replace_current_enabled = !app.find_matches.is_empty() && app.current_match_index.is_some(); ui.add_enabled_ui(replace_current_enabled, |ui| { if ui.button("Replace").clicked() { app.replace_current_match(ctx); } }); let replace_all_enabled = !app.find_matches.is_empty(); ui.add_enabled_ui(replace_all_enabled, |ui| { if ui.button("Replace All").clicked() { app.replace_all(ctx); } }); } }); ui.add_space(8.0); ui.horizontal(|ui| { let match_text = if app.find_matches.is_empty() { if app.find_query.is_empty() { "".to_string() } else { "No matches found".to_string() } } else if let Some(current) = app.current_match_index { format!("{} of {} matches", current + 1, app.find_matches.len()) } else { format!("{} matches found", app.find_matches.len()) }; ui.label(egui::RichText::new(match_text).weak()); ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { if ui.button("❌").clicked() { should_close = true; } ui.add_space(4.0); let next_enabled = !app.find_matches.is_empty(); ui.add_enabled_ui(next_enabled, |ui| { if ui.button("Next").clicked() { app.find_next(ctx); } }); let prev_enabled = !app.find_matches.is_empty(); ui.add_enabled_ui(prev_enabled, |ui| { if ui.button("Previous").clicked() { app.find_previous(ctx); } }); }); }); }); }); if query_changed { app.update_find_matches(); if app.current_match_index.is_some() { app.select_current_match(ctx); app.should_select_current_match = true; } } if should_close { app.select_current_match(ctx); app.should_select_current_match = true; app.show_find = false; } ctx.input(|i| { if i.key_pressed(egui::Key::Enter) && i.modifiers.ctrl && app.show_find { should_focus_editor = true; app.should_select_current_match = true; } }); if should_focus_editor { ctx.memory_mut(|mem| { mem.request_focus(egui::Id::new("main_text_editor")); }); } }