improvements
This commit is contained in:
Generated
+19
@@ -2047,6 +2047,15 @@ dependencies = [
|
|||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fuzzy-matcher"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94"
|
||||||
|
dependencies = [
|
||||||
|
"thread_local",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.14.7"
|
version = "0.14.7"
|
||||||
@@ -5450,6 +5459,7 @@ dependencies = [
|
|||||||
"egui",
|
"egui",
|
||||||
"egui_ltreeview",
|
"egui_ltreeview",
|
||||||
"egui_plot",
|
"egui_plot",
|
||||||
|
"fuzzy-matcher",
|
||||||
"libsvld",
|
"libsvld",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -5595,6 +5605,15 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thread_local"
|
||||||
|
version = "1.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiff"
|
name = "tiff"
|
||||||
version = "0.11.3"
|
version = "0.11.3"
|
||||||
|
|||||||
@@ -16,3 +16,4 @@ eframe = "0.34"
|
|||||||
egui = "0.34"
|
egui = "0.34"
|
||||||
egui_plot = "0.35"
|
egui_plot = "0.35"
|
||||||
egui_ltreeview = "0.7"
|
egui_ltreeview = "0.7"
|
||||||
|
fuzzy-matcher = "0.3"
|
||||||
|
|||||||
@@ -30,6 +30,24 @@ pub fn remove_plot(plots: &mut Vec<PlotGroup>, plot_id: u64) {
|
|||||||
plots.retain(|p| p.id != plot_id);
|
plots.retain(|p| p.id != plot_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Keep at most one empty plot; drop any further empties (keeps the
|
||||||
|
/// first one encountered so the user's stable reference doesn't vanish).
|
||||||
|
fn dedupe_empty(plots: &mut Vec<PlotGroup>) {
|
||||||
|
let mut seen_empty = false;
|
||||||
|
plots.retain(|p| {
|
||||||
|
if p.signals.is_empty() {
|
||||||
|
if seen_empty {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
seen_empty = true;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Most common unit in the plot (first-wins on ties). Returns `None`
|
/// Most common unit in the plot (first-wins on ties). Returns `None`
|
||||||
/// when the plot is empty.
|
/// when the plot is empty.
|
||||||
pub fn majority_unit(signals: &[PlottedSignal]) -> Option<&str> {
|
pub fn majority_unit(signals: &[PlottedSignal]) -> Option<&str> {
|
||||||
@@ -50,13 +68,14 @@ pub fn contains_signal(plots: &[PlotGroup], signal_id: u64) -> bool {
|
|||||||
.any(|p| p.signals.iter().any(|s| s.id == signal_id))
|
.any(|p| p.signals.iter().any(|s| s.id == signal_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_signal(plots: &mut [PlotGroup], signal_id: u64) {
|
pub fn remove_signal(plots: &mut Vec<PlotGroup>, signal_id: u64) {
|
||||||
for plot in plots {
|
for plot in plots.iter_mut() {
|
||||||
if let Some(pos) = plot.signals.iter().position(|s| s.id == signal_id) {
|
if let Some(pos) = plot.signals.iter().position(|s| s.id == signal_id) {
|
||||||
plot.signals.remove(pos);
|
plot.signals.remove(pos);
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dedupe_empty(plots);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Place `sig` into the first plot whose majority unit matches and that
|
/// Place `sig` into the first plot whose majority unit matches and that
|
||||||
@@ -67,11 +86,18 @@ pub fn add_signal_auto(
|
|||||||
sig: PlottedSignal,
|
sig: PlottedSignal,
|
||||||
) {
|
) {
|
||||||
let unit = sig.unit.as_str();
|
let unit = sig.unit.as_str();
|
||||||
let slot = plots.iter_mut().find(|p| {
|
// Prefer an existing empty plot, then a unit-matching plot under cap.
|
||||||
p.signals.len() < MAX_SIGNALS_PER_PLOT && majority_unit(&p.signals) == Some(unit)
|
let slot = plots
|
||||||
});
|
.iter()
|
||||||
if let Some(plot) = slot {
|
.position(|p| p.signals.is_empty())
|
||||||
plot.signals.push(sig);
|
.or_else(|| {
|
||||||
|
plots.iter().position(|p| {
|
||||||
|
p.signals.len() < MAX_SIGNALS_PER_PLOT
|
||||||
|
&& majority_unit(&p.signals) == Some(unit)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if let Some(i) = slot {
|
||||||
|
plots[i].signals.push(sig);
|
||||||
} else {
|
} else {
|
||||||
plots.push(PlotGroup {
|
plots.push(PlotGroup {
|
||||||
id: *next_plot_id,
|
id: *next_plot_id,
|
||||||
@@ -82,6 +108,9 @@ pub fn add_signal_auto(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_plot(plots: &mut Vec<PlotGroup>, next_plot_id: &mut u64) {
|
pub fn new_plot(plots: &mut Vec<PlotGroup>, next_plot_id: &mut u64) {
|
||||||
|
if plots.iter().any(|p| p.signals.is_empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
plots.push(PlotGroup {
|
plots.push(PlotGroup {
|
||||||
id: *next_plot_id,
|
id: *next_plot_id,
|
||||||
signals: Vec::new(),
|
signals: Vec::new(),
|
||||||
@@ -111,11 +140,10 @@ pub fn show_plot_list(
|
|||||||
let unit = majority_unit(&plot.signals).unwrap_or("empty");
|
let unit = majority_unit(&plot.signals).unwrap_or("empty");
|
||||||
let label = format!("Plot {} [{}]", i + 1, unit);
|
let label = format!("Plot {} [{}]", i + 1, unit);
|
||||||
let plot_id = plot.id;
|
let plot_id = plot.id;
|
||||||
let is_empty = plot.signals.is_empty();
|
let node = NodeBuilder::dir(plot_node_id(plot.id))
|
||||||
let mut node =
|
.label(label)
|
||||||
NodeBuilder::dir(plot_node_id(plot.id)).label(label);
|
.activatable(true)
|
||||||
if is_empty {
|
.context_menu(|ui| {
|
||||||
node = node.context_menu(|ui| {
|
|
||||||
if ui.button("Remove plot").clicked() {
|
if ui.button("Remove plot").clicked() {
|
||||||
events
|
events
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
@@ -123,7 +151,6 @@ pub fn show_plot_list(
|
|||||||
ui.close();
|
ui.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
builder.node(node);
|
builder.node(node);
|
||||||
for sig in &plot.signals {
|
for sig in &plot.signals {
|
||||||
let sig_id = sig.id;
|
let sig_id = sig.id;
|
||||||
@@ -144,8 +171,24 @@ pub fn show_plot_list(
|
|||||||
builder.close_dir();
|
builder.close_dir();
|
||||||
});
|
});
|
||||||
for action in actions {
|
for action in actions {
|
||||||
if let Action::Move(dd) = action {
|
match action {
|
||||||
events.borrow_mut().push(PlotListAction::Move(dd));
|
Action::Move(dd) => {
|
||||||
|
events.borrow_mut().push(PlotListAction::Move(dd));
|
||||||
|
}
|
||||||
|
Action::Activate(act) => {
|
||||||
|
for id in act.selected {
|
||||||
|
if id & SIGNAL_FLAG != 0 {
|
||||||
|
events
|
||||||
|
.borrow_mut()
|
||||||
|
.push(PlotListAction::RemoveSignal(id));
|
||||||
|
} else if let Some(plot_id) = decode_plot_node_id(id) {
|
||||||
|
events
|
||||||
|
.borrow_mut()
|
||||||
|
.push(PlotListAction::RemovePlot(plot_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -164,6 +207,7 @@ pub fn apply_move(plots: &mut Vec<PlotGroup>, dd: DragAndDrop<u64>) {
|
|||||||
apply_plot_move(plots, source & !PLOT_FLAG, dd.target, &dd.position);
|
apply_plot_move(plots, source & !PLOT_FLAG, dd.target, &dd.position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dedupe_empty(plots);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_signal_move(
|
fn apply_signal_move(
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ use can_dbc::Dbc;
|
|||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
use egui::ScrollArea;
|
use egui::ScrollArea;
|
||||||
use egui_ltreeview::{Action, TreeView, TreeViewBuilder};
|
use egui_ltreeview::{Action, TreeView, TreeViewBuilder};
|
||||||
|
use fuzzy_matcher::FuzzyMatcher;
|
||||||
|
use fuzzy_matcher::skim::SkimMatcherV2;
|
||||||
use libsvld::DecodeResult;
|
use libsvld::DecodeResult;
|
||||||
|
|
||||||
pub struct SigNode {
|
pub struct SigNode {
|
||||||
@@ -89,7 +91,8 @@ pub fn show_dbc_tree(
|
|||||||
.hint_text("Filter messages/signals")
|
.hint_text("Filter messages/signals")
|
||||||
.desired_width(f32::INFINITY),
|
.desired_width(f32::INFINITY),
|
||||||
);
|
);
|
||||||
let needle = filter.trim().to_lowercase();
|
let needle = filter.trim();
|
||||||
|
let matcher = SkimMatcherV2::default();
|
||||||
ScrollArea::both()
|
ScrollArea::both()
|
||||||
.scroll([true, true])
|
.scroll([true, true])
|
||||||
.scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::VisibleWhenNeeded)
|
.scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::VisibleWhenNeeded)
|
||||||
@@ -100,13 +103,15 @@ pub fn show_dbc_tree(
|
|||||||
.show(ui, |builder: &mut TreeViewBuilder<'_, u64>| {
|
.show(ui, |builder: &mut TreeViewBuilder<'_, u64>| {
|
||||||
for msg in tree {
|
for msg in tree {
|
||||||
let msg_hit = needle.is_empty()
|
let msg_hit = needle.is_empty()
|
||||||
|| msg.label.to_lowercase().contains(&needle);
|
|| matcher.fuzzy_match(&msg.label, needle).is_some();
|
||||||
let matching: Vec<&SigNode> = if msg_hit {
|
let matching: Vec<&SigNode> = if msg_hit {
|
||||||
msg.signals.iter().collect()
|
msg.signals.iter().collect()
|
||||||
} else {
|
} else {
|
||||||
msg.signals
|
msg.signals
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|s| s.name.to_lowercase().contains(&needle))
|
.filter(|s| {
|
||||||
|
matcher.fuzzy_match(&s.name, needle).is_some()
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
if !msg_hit && matching.is_empty() {
|
if !msg_hit && matching.is_empty() {
|
||||||
|
|||||||
Reference in New Issue
Block a user