mirror of
https://github.com/storytold/gridcraft.git
synced 2026-11-15 14:52:26 +00:00
95 lines
3.4 KiB
Rust
95 lines
3.4 KiB
Rust
use super::{Dialog, Key, SheetApp, json, vec2};
|
||
|
||
/// Shows enabled commands and their shortcuts from engine metadata.
|
||
pub(super) fn command_search(app: &mut SheetApp, ui: &mut egui::Ui, d: &mut Dialog, confirm: &mut bool) {
|
||
let (down, up, home, end, pgup, pgdn) = ui.input_mut(|i| {
|
||
(
|
||
i.consume_key(egui::Modifiers::NONE, Key::ArrowDown),
|
||
i.consume_key(egui::Modifiers::NONE, Key::ArrowUp),
|
||
i.consume_key(egui::Modifiers::CTRL, Key::Home),
|
||
i.consume_key(egui::Modifiers::CTRL, Key::End),
|
||
i.consume_key(egui::Modifiers::NONE, Key::PageUp),
|
||
i.consume_key(egui::Modifiers::NONE, Key::PageDown),
|
||
)
|
||
});
|
||
let width = ui.available_width();
|
||
let r = ui.add(egui::TextEdit::singleline(&mut d.search).desired_width(width).hint_text("Type a command, e.g. freeze, chart, bold…"));
|
||
|
||
if !d.focus_initialized {
|
||
r.request_focus();
|
||
d.focus_initialized = true;
|
||
}
|
||
|
||
let mac = ui.ctx().os() == egui::os::OperatingSystem::Mac;
|
||
let q = d.search.to_ascii_lowercase();
|
||
let cmds: Vec<(String, String, String, Option<String>)> = app
|
||
.session
|
||
.commands()
|
||
.into_iter()
|
||
.filter(|c| c.enabled)
|
||
.filter(|c| q.is_empty() || c.label.to_ascii_lowercase().contains(&q) || c.id.to_ascii_lowercase().contains(&q))
|
||
.map(|c| (c.id.to_string(), c.label.to_string(), c.menu.join(" › "), c.shortcut_for_platform(mac)))
|
||
.take(40)
|
||
.collect();
|
||
|
||
let last = cmds.len().saturating_sub(1);
|
||
|
||
let row_h = ui.spacing().interact_size.y.max(20.0);
|
||
let row_step = row_h + ui.spacing().item_spacing.y;
|
||
|
||
const LIST_HEIGHT: f32 = 320.0;
|
||
|
||
let page_size = ((LIST_HEIGHT / row_step).floor() as usize).saturating_sub(1).max(1);
|
||
|
||
if down {
|
||
d.list_index = (d.list_index + 1).min(last);
|
||
}
|
||
if up {
|
||
d.list_index = d.list_index.saturating_sub(1);
|
||
}
|
||
if pgdn {
|
||
d.list_index = (d.list_index + page_size).min(last);
|
||
}
|
||
if pgup {
|
||
d.list_index = d.list_index.saturating_sub(page_size);
|
||
}
|
||
if home {
|
||
d.list_index = 0;
|
||
}
|
||
if end {
|
||
d.list_index = last;
|
||
}
|
||
|
||
d.list_index = d.list_index.min(last);
|
||
|
||
egui::ScrollArea::vertical().max_height(LIST_HEIGHT).auto_shrink([true, false]).show(ui, |ui| {
|
||
let scroll_area_width = ui.available_width();
|
||
for (i, (id, label, menu, shortcut)) in cmds.iter().enumerate() {
|
||
let text = match shortcut {
|
||
Some(keys) => format!("{label} ({keys}) {menu}"),
|
||
None => format!("{label} {menu}"),
|
||
};
|
||
let r = ui.add(egui::Button::selectable(i == d.list_index, text.clone()).truncate().min_size(vec2(scroll_area_width, 20.0)));
|
||
|
||
if (down || up || home || end || pgup || pgdn) && i == d.list_index && !ui.clip_rect().contains_rect(r.rect) {
|
||
r.scroll_to_me(Some(if down || end || pgdn { egui::Align::Max } else { egui::Align::Min }));
|
||
}
|
||
|
||
if r.clicked() {
|
||
d.list_index = i;
|
||
*confirm = true;
|
||
}
|
||
|
||
r.on_hover_text(format!("{text}\n{id}"));
|
||
}
|
||
});
|
||
if ui.input(|i| i.key_pressed(Key::Enter)) {
|
||
*confirm = true;
|
||
}
|
||
if *confirm && let Some((id, ..)) = cmds.get(d.list_index) {
|
||
let id = id.clone();
|
||
app.dialog = None;
|
||
app.run_or_alert(&id, json!({}));
|
||
}
|
||
}
|