mod band;
mod focus;
mod standing;
use bevy_app::{App, PostUpdate};
use bevy_ecs::hierarchy::ChildOf;
use bevy_ecs::prelude::{Commands, Entity};
use bevy_input::keyboard::Key;
use plurimus::core::ratatui_core::layout::Size;
use plurimus::ui::{KeyBinding, ModalOpen, ScrollArea};
use plurimus::widgets::listbox;
use super::hints::Hints;
use super::layout::{filling, list_cursor, placed};
use super::pane::Framed;
use bevy_ecs::change_detection::{DetectChanges, Ref};
use bevy_ecs::prelude::{Component, IntoScheduleConfigs, Query, With};
use bevy_ui::{FlexDirection, Node, Overflow, PositionType, UiRect, UiSystems, Val};
use plurimus::bui::ComputedNodeRect;
pub use focus::Focus;
pub use standing::Standing;
use super::layout::Body;
pub fn plugin(app: &mut App) {
app.init_resource::<Focus>();
app.add_plugins(band::plugin);
app.add_systems(PostUpdate, centre_boxes.before(UiSystems::Layout));
}
pub const CHROME: u16 = 2;
const BOTTOM_SHARE: f32 = 40.0;
pub const CLOSE_KEYS: &[(KeyBinding, ())] = &[(KeyBinding::new(Key::Escape), ())];
#[derive(Component, Clone, Copy, Debug)]
pub struct Centred {
cols: u16,
rows: u16,
}
#[must_use]
pub fn centred(cols: u16, rows: u16) -> (Node, Centred) {
let rows = rows.saturating_add(CHROME);
let node = Node {
position_type: PositionType::Absolute,
width: Val::Px(f32::from(cols)),
height: Val::Px(f32::from(rows)),
max_height: Val::Percent(100.0),
padding: UiRect::all(Val::Px(1.0)),
flex_direction: FlexDirection::Column,
overflow: Overflow::clip(),
..Node::default()
};
(node, Centred { cols, rows })
}
pub fn bottom_panel(commands: &mut Commands, root: Entity, title: &str, hints: Hints) -> Entity {
commands.entity(root).insert((
Node {
position_type: PositionType::Absolute,
left: Val::Px(0.0),
right: Val::Px(0.0),
bottom: Val::Px(0.0),
height: Val::Percent(BOTTOM_SHARE),
padding: UiRect::all(Val::Px(1.0)),
flex_direction: FlexDirection::Column,
..Node::default()
},
Framed::over(title),
ModalOpen,
hints,
));
commands
.spawn((
listbox(),
list_cursor(),
ScrollArea::new(Size::default()),
filling(),
placed(),
ChildOf(root),
))
.id()
}
fn centre_boxes(
bodies: Query<Ref<ComputedNodeRect>, With<Body>>,
mut boxes: Query<(Ref<Centred>, &mut Node)>,
) {
let Ok(body) = bodies.single() else {
return;
};
let room = body.visible;
for (centred, mut node) in &mut boxes {
if !body.is_changed() && !centred.is_added() {
continue;
}
let rows = centred.rows.min(room.height);
node.left = Val::Px(f32::from(room.width.saturating_sub(centred.cols) / 2));
node.top = Val::Px(f32::from(room.height.saturating_sub(rows).div_ceil(2)));
}
}