use concinnity_core::components::FrameInput;
use concinnity_core::components::InputKey;
use concinnity_core::ecs::World;
use crate::editor::behavior::navigate;
use crate::editor::hook::{EditorHook, scroll_step};
use crate::editor::palette::panel::{PaletteHit, PaletteView};
use crate::editor::palette::providers;
use crate::editor::palette::{self, PaletteAction};
use crate::editor::panels::registry::{self, PanelKey};
use crate::editor::view_menu;
use crate::editor::widget::{self, point_in};
const WINDOW: usize = palette::panel::ROW_POOL;
impl EditorHook {
pub(in crate::editor::hook) fn drive_palette_toggle(
&mut self,
input: &FrameInput,
world: &mut World,
) {
if !input.pressed_fresh(InputKey::K) || !(input.ctrl || input.cmd) || self.sim.playing() {
return;
}
self.toggle_palette(world);
if self.open[PanelKey::Palette] {
self.palette.blur = true;
}
}
pub(in crate::editor::hook) fn toggle_palette(&mut self, world: &mut World) {
if self.open[PanelKey::Palette] {
self.close_palette();
return;
}
self.open[PanelKey::Palette] = true;
self.refresh_tree_if_needed();
self.palette.items = providers::all_items(&self.assets.groups);
self.palette.query = String::new();
widget::seed_field(world, palette::panel::INPUT, "");
self.palette.rerank();
self.focus_panel(PanelKey::Palette);
}
pub(in crate::editor::hook) fn close_palette(&mut self) {
self.open[PanelKey::Palette] = false;
}
pub(in crate::editor::hook) fn sample_palette_query(&mut self, world: &World) {
if !self.open[PanelKey::Palette] {
return;
}
let typed = widget::field_text(world, palette::panel::INPUT);
if typed != self.palette.query {
self.palette.query = typed;
self.palette.rerank();
}
}
pub(in crate::editor::hook) fn route_palette_dismiss(
&mut self,
input: &FrameInput,
vp: [f32; 2],
) -> bool {
if !self.open[PanelKey::Palette] {
return false;
}
let o = self.origin(PanelKey::Palette, vp);
let over = point_in(
input.mouse_x,
input.mouse_y,
widget::outer_rect(o, palette::panel::size()),
);
if over {
return false;
}
self.close_palette();
true
}
pub(in crate::editor::hook) fn make_palette_view(&self, mouse: [f32; 2]) -> PaletteView<'_> {
let rows = self
.palette
.matches
.iter()
.skip(self.palette.scroll)
.take(WINDOW)
.map(|&at| {
let item = &self.palette.items[at];
palette::panel::PaletteRow {
caption: &item.label,
hint: &item.hint,
tag: item.category.tag(),
}
})
.collect();
PaletteView {
rows,
selected: self.palette.pick,
scroll: self.palette.scroll,
total: self.palette.matches.len(),
focus: self.open[PanelKey::Palette]
&& !self.palette.blur
&& self.panel_order.last() == Some(&PanelKey::Palette),
mouse,
}
}
pub(in crate::editor::hook) fn scroll_palette(&mut self, delta: f32) {
let max = self.palette.matches.len().saturating_sub(WINDOW);
self.palette.scroll = scroll_step(self.palette.scroll, delta, max);
}
pub(in crate::editor::hook) fn palette_keys(&mut self, world: &mut World, input: &FrameInput) {
for press in input.key_presses() {
let key = press.key;
match key {
InputKey::Enter if !press.repeat => self.commit_palette(world),
InputKey::Up | InputKey::Down => {
let delta = if key == InputKey::Up { -1 } else { 1 };
let total = self.palette.matches.len();
let Some(at) = navigate::step(Some(self.palette.pick), delta, total) else {
continue;
};
self.palette.pick = at;
self.palette.scroll = navigate::scroll_to(at, self.palette.scroll, WINDOW);
}
_ => {}
}
}
}
pub(in crate::editor::hook) fn apply_palette_hit(
&mut self,
hit: PaletteHit,
world: &mut World,
) {
match hit {
PaletteHit::FocusInput | PaletteHit::Consume => {}
PaletteHit::Row(slot) => {
if let Some(&at) = self.palette.matches.get(self.palette.scroll + slot) {
self.commit_palette_item(at, world);
}
}
}
}
fn commit_palette(&mut self, world: &mut World) {
let query = self.palette.query.trim().to_string();
if query.starts_with('/') && query.contains(char::is_whitespace) {
self.close_palette();
self.dispatch_palette_command(world, &query);
return;
}
let Some(&at) = self.palette.matches.get(self.palette.pick) else {
return;
};
self.commit_palette_item(at, world);
}
fn commit_palette_item(&mut self, at: usize, world: &mut World) {
let item = self.palette.items[at].clone();
self.palette.note_recent(item.label);
self.apply_palette_action(item.action, world);
}
fn apply_palette_action(&mut self, action: PaletteAction, world: &mut World) {
match action {
PaletteAction::OpenPanel(key) => {
self.close_palette();
if !registry::panel(key).is_open(self) {
registry::panel(key).toggle(self, world);
}
self.focus_panel(key);
}
PaletteAction::SelectEntity(name) => {
self.close_palette();
self.select_named(&name);
self.pick_last = None;
self.focus_ui_on(&name, world);
self.frame_selection(self.viewport, world);
}
PaletteAction::OpenAsset(name) => {
self.close_palette();
self.open_behavior_named(&name, world);
}
PaletteAction::CommandMode(name) => {
widget::focus_field_with(world, palette::panel::INPUT, &format!("/{name} "));
}
PaletteAction::RunCommand(line) => {
self.close_palette();
self.dispatch_palette_command(world, &line);
}
PaletteAction::SetOption(row) => {
self.close_palette();
match row {
view_menu::MenuRow::Mode(m) => self.view_mode = m,
view_menu::MenuRow::Heading(_) => {}
view_menu::MenuRow::Flag(f, _) => self.show_flags = self.show_flags.toggled(f),
view_menu::MenuRow::Billboards => self.show_billboards = !self.show_billboards,
view_menu::MenuRow::Extent(c, _) => {
self.extent_show = self.extent_show.toggled(c);
}
}
}
}
}
fn dispatch_palette_command(&mut self, world: &mut World, line: &str) {
if !self.open[PanelKey::Console] {
self.toggle_console(world);
}
self.run_console_line(world, line);
}
}