use crate::graph::MessageFlowGraph;
use egui::{Pos2, Rect, Vec2};
use std::collections::HashMap;
pub fn find_matching_modules(graph: &MessageFlowGraph, query: &str) -> Vec<String> {
if query.is_empty() {
return Vec::new();
}
let query_lower = query.to_lowercase();
graph
.graph
.node_weights()
.filter(|node| {
let name_lower = node.name.to_lowercase();
if name_lower.contains(&query_lower) {
return true;
}
fuzzy_match(&name_lower, &query_lower)
})
.map(|node| node.name.clone())
.collect()
}
fn fuzzy_match(target: &str, query: &str) -> bool {
let mut target_chars = target.chars();
for query_char in query.chars() {
loop {
match target_chars.next() {
Some(c) if c == query_char => break,
Some(_) => continue,
None => return false,
}
}
}
true
}
pub fn get_best_match(matches: &[String], query: &str) -> Option<String> {
if matches.is_empty() {
return None;
}
let query_lower = query.to_lowercase();
for m in matches {
if m.to_lowercase().starts_with(&query_lower) {
return Some(m.clone());
}
}
Some(matches[0].clone())
}
pub fn focus_on_node(
node_name: &str,
positions: &HashMap<String, Pos2>,
viewport_rect: Rect,
pan: &mut Vec2,
zoom: &mut f32,
) {
if let Some(node_pos) = positions.get(node_name) {
let center = viewport_rect.center();
*pan = center - *node_pos;
if *zoom < 1.0 {
*zoom = 1.0;
}
}
}
pub fn draw_search_box(
ui: &mut egui::Ui,
query: &mut String,
focused: &mut bool,
matches: &[String],
) -> Option<String> {
let mut selected = None;
ui.horizontal(|ui| {
ui.label("Search:");
let response = ui.add(
egui::TextEdit::singleline(query)
.hint_text("Type to search... (Ctrl+F)")
.desired_width(150.0),
);
if *focused {
response.request_focus();
*focused = false;
}
if response.changed() && !query.is_empty() {
if let Some(best) = get_best_match(matches, query) {
selected = Some(best);
}
}
if !query.is_empty() {
ui.label(format!("({} matches)", matches.len()));
}
if !query.is_empty() && ui.button("x").clicked() {
query.clear();
selected = None;
}
});
if !query.is_empty() && matches.len() > 1 {
ui.horizontal(|ui| {
ui.label(" ");
for (i, m) in matches.iter().take(5).enumerate() {
if ui.selectable_label(false, m).clicked() {
selected = Some(m.clone());
}
if i < matches.len().min(5) - 1 {
ui.label("|");
}
}
if matches.len() > 5 {
ui.label(format!("... +{}", matches.len() - 5));
}
});
}
selected
}