nightshade 0.13.3

A cross-platform data-oriented game engine.
Documentation
use crate::ecs::world::World;

use super::ShellState;

#[cfg(feature = "egui")]
pub fn shell_ui<C>(shell: &mut ShellState<C>, ui_context: &egui::Context, world: &mut World) {
    if !shell.should_render() {
        return;
    }

    let screen_rect = ui_context.input(|i| i.viewport_rect());
    let shell_height = shell.height.min(screen_rect.height() * 0.9);
    let current_height = shell_height * shell.animation_progress;

    let panel_rect = egui::Rect::from_min_size(
        egui::pos2(0.0, 0.0),
        egui::vec2(screen_rect.width(), current_height),
    );

    egui::Area::new(egui::Id::new("shell_console"))
        .fixed_pos(egui::pos2(0.0, 0.0))
        .order(egui::Order::Foreground)
        .show(ui_context, |ui| {
            ui.set_clip_rect(panel_rect);

            egui::Frame::new()
                .fill(egui::Color32::from_rgba_unmultiplied(15, 15, 20, 230))
                .show(ui, |ui| {
                    ui.set_min_size(egui::vec2(screen_rect.width(), shell_height));
                    ui.set_max_size(egui::vec2(screen_rect.width(), shell_height));

                    ui.vertical(|ui| {
                        ui.add_space(4.0);

                        ui.horizontal(|ui| {
                            ui.add_space(8.0);
                            ui.label(
                                egui::RichText::new("Console")
                                    .color(egui::Color32::from_rgb(100, 200, 100))
                                    .strong(),
                            );
                            ui.with_layout(
                                egui::Layout::right_to_left(egui::Align::Center),
                                |ui| {
                                    ui.add_space(8.0);
                                    ui.label(
                                        egui::RichText::new("Alt+C or Escape to close")
                                            .color(egui::Color32::from_rgb(120, 120, 120))
                                            .small(),
                                    );
                                },
                            );
                        });

                        ui.add_space(2.0);
                        ui.separator();

                        let available_height = shell_height - 70.0;
                        egui::ScrollArea::vertical()
                            .max_height(available_height)
                            .auto_shrink([false, false])
                            .stick_to_bottom(shell.scroll_to_bottom)
                            .show(ui, |ui| {
                                ui.add_space(4.0);
                                for line in &shell.output {
                                    ui.horizontal(|ui| {
                                        ui.add_space(8.0);
                                        let color = if line.is_command {
                                            egui::Color32::from_rgb(150, 200, 255)
                                        } else {
                                            egui::Color32::from_rgb(200, 200, 200)
                                        };
                                        ui.label(
                                            egui::RichText::new(&line.text)
                                                .color(color)
                                                .family(egui::FontFamily::Monospace),
                                        );
                                    });
                                }
                                ui.add_space(4.0);
                            });

                        shell.scroll_to_bottom = false;

                        ui.separator();

                        ui.horizontal(|ui| {
                            ui.add_space(8.0);
                            ui.label(
                                egui::RichText::new(">")
                                    .color(egui::Color32::from_rgb(100, 200, 100))
                                    .family(egui::FontFamily::Monospace),
                            );

                            let response = ui.add(
                                egui::TextEdit::singleline(&mut shell.input_buffer)
                                    .desired_width(screen_rect.width() - 40.0)
                                    .font(egui::FontId::monospace(14.0))
                                    .text_color(egui::Color32::from_rgb(220, 220, 220))
                                    .frame(egui::Frame::NONE),
                            );

                            if shell.visible && shell.animation_progress > 0.9 {
                                response.request_focus();
                            }

                            if response.has_focus() {
                                if ui.input(|i| i.key_pressed(egui::Key::Enter)) {
                                    shell.execute_command(world);
                                }

                                if ui.input(|i| i.key_pressed(egui::Key::ArrowUp)) {
                                    shell.history_up();
                                }

                                if ui.input(|i| i.key_pressed(egui::Key::ArrowDown)) {
                                    shell.history_down();
                                }

                                if ui.input(|i| i.key_pressed(egui::Key::Escape)) {
                                    shell.visible = false;
                                }

                                if ui.input(|i| i.modifiers.alt && i.key_pressed(egui::Key::C)) {
                                    shell.visible = false;
                                }
                            }
                        });

                        ui.add_space(4.0);
                    });
                });
        });
}