use crate::ecs::ui::types::Rect;
use crate::ecs::world::World;
use crate::render::wgpu::passes::geometry::UiLayer;
use nalgebra_glm::{Vec2, Vec4};
use super::ShellState;
pub fn shell_retained_ui<C>(shell: &mut ShellState<C>, world: &mut World) {
if !shell.should_render() {
return;
}
let screen_size = world
.resources
.window
.handle
.as_ref()
.map(|handle| {
let size = handle.inner_size();
Vec2::new(size.width as f32, size.height as f32)
})
.unwrap_or(Vec2::new(1920.0, 1080.0));
let screen_width = screen_size.x;
let screen_height = screen_size.y;
let mouse_pos = Vec2::new(
world.resources.input.mouse.position.x,
world.resources.input.mouse.position.y,
);
let mouse_down = world
.resources
.input
.mouse
.state
.contains(crate::ecs::world::resources::MouseState::LEFT_CLICKED);
let mouse_just_pressed = world
.resources
.input
.mouse
.state
.contains(crate::ecs::world::resources::MouseState::LEFT_JUST_PRESSED);
let min_height = 100.0;
let max_height = screen_height * 0.9;
shell.height = shell.height.clamp(min_height, max_height);
let shell_height = shell.height;
let current_height = shell_height * shell.animation_progress;
let resize_handle_height = 8.0;
let resize_area = Rect::new(
0.0,
current_height - resize_handle_height,
screen_width,
resize_handle_height * 2.0,
);
let mouse_in_resize = resize_area.contains(mouse_pos) && shell.animation_progress > 0.95;
if mouse_in_resize && mouse_just_pressed && !shell.dragging_resize {
shell.dragging_resize = true;
shell.drag_start_y = mouse_pos.y;
shell.drag_start_height = shell.height;
}
if shell.dragging_resize {
if mouse_down {
let delta = mouse_pos.y - shell.drag_start_y;
shell.height = (shell.drag_start_height + delta).clamp(min_height, max_height);
} else {
shell.dragging_resize = false;
}
}
let bg_color = Vec4::new(0.06, 0.06, 0.08, 0.95);
let header_color = Vec4::new(0.39, 0.78, 0.39, 1.0);
let hint_color = Vec4::new(0.47, 0.47, 0.47, 1.0);
let command_color = Vec4::new(0.59, 0.78, 1.0, 1.0);
let output_color = Vec4::new(0.78, 0.78, 0.78, 1.0);
let border_color = Vec4::new(0.4, 0.4, 0.45, 1.0);
let transparent = Vec4::new(0.0, 0.0, 0.0, 0.0);
let panel_clip = Rect::new(0.0, 0.0, screen_width, current_height);
let ui = &mut world.resources.retained_ui;
ui.draw_overlay_rect(crate::render::wgpu::passes::geometry::UiRect {
position: Vec2::new(0.0, 0.0),
size: Vec2::new(screen_width, current_height),
color: bg_color,
corner_radius: 0.0,
border_width: 0.0,
border_color: transparent,
rotation: 0.0,
clip_rect: Some(panel_clip),
layer: UiLayer::Tooltips,
z_index: 0,
});
let padding = 10.0;
let font_size = 14.0;
let line_height = font_size + 6.0;
let header_height = 24.0;
let input_height = 28.0;
let separator_height = 1.0;
let header_y = 4.0;
ui.draw_overlay_text(
"Console",
Vec2::new(padding, header_y),
crate::ecs::text::components::TextProperties {
font_size,
color: header_color,
..Default::default()
},
Some(panel_clip),
UiLayer::Tooltips,
1,
);
let hint_text = "Alt+C to close";
let hint_width = hint_text.len() as f32 * font_size * 0.5;
ui.draw_overlay_text(
hint_text,
Vec2::new(screen_width - hint_width - padding, header_y + 2.0),
crate::ecs::text::components::TextProperties {
font_size: font_size * 0.85,
color: hint_color,
..Default::default()
},
Some(panel_clip),
UiLayer::Tooltips,
1,
);
let top_separator_y = header_height;
ui.draw_overlay_rect(crate::render::wgpu::passes::geometry::UiRect {
position: Vec2::new(0.0, top_separator_y),
size: Vec2::new(screen_width, separator_height),
color: border_color,
corner_radius: 0.0,
border_width: 0.0,
border_color: transparent,
rotation: 0.0,
clip_rect: Some(panel_clip),
layer: UiLayer::Tooltips,
z_index: 1,
});
let bottom_separator_y = current_height - input_height - separator_height;
ui.draw_overlay_rect(crate::render::wgpu::passes::geometry::UiRect {
position: Vec2::new(0.0, bottom_separator_y),
size: Vec2::new(screen_width, separator_height),
color: border_color,
corner_radius: 0.0,
border_width: 0.0,
border_color: transparent,
rotation: 0.0,
clip_rect: Some(panel_clip),
layer: UiLayer::Tooltips,
z_index: 1,
});
let output_top = top_separator_y + separator_height + 2.0;
let output_bottom = bottom_separator_y - 2.0;
let output_height = (output_bottom - output_top).max(0.0);
let output_clip = Rect::new(0.0, output_top, screen_width, output_height);
let mut total_content_height = 0.0;
for line in &shell.output {
let line_count = line.text.lines().count().max(1);
total_content_height += line_count as f32 * line_height;
}
if shell.scroll_to_bottom {
shell.scroll_offset = (total_content_height - output_height).max(0.0);
shell.scroll_to_bottom = false;
}
shell.scroll_offset = shell
.scroll_offset
.clamp(0.0, (total_content_height - output_height).max(0.0));
if output_height > 0.0 {
let mut y_pos = output_top - shell.scroll_offset;
for line in &shell.output {
let color = if line.is_command {
command_color
} else {
output_color
};
for text_line in line.text.lines() {
if y_pos + line_height > output_top && y_pos < output_bottom {
ui.draw_overlay_text(
text_line,
Vec2::new(padding, y_pos),
crate::ecs::text::components::TextProperties {
font_size,
color,
..Default::default()
},
Some(output_clip),
UiLayer::Tooltips,
2,
);
}
y_pos += line_height;
}
}
}
let input_y = current_height - input_height + (input_height - font_size) * 0.5;
ui.draw_overlay_text(
">",
Vec2::new(padding, input_y),
crate::ecs::text::components::TextProperties {
font_size,
color: header_color,
..Default::default()
},
Some(panel_clip),
UiLayer::Tooltips,
2,
);
let cursor = if shell.visible && shell.animation_progress > 0.9 {
"_"
} else {
""
};
let input_display = format!("{}{}", shell.input_buffer, cursor);
ui.draw_overlay_text(
&input_display,
Vec2::new(padding + font_size + 4.0, input_y),
crate::ecs::text::components::TextProperties {
font_size,
color: output_color,
..Default::default()
},
Some(panel_clip),
UiLayer::Tooltips,
2,
);
ui.draw_overlay_rect(crate::render::wgpu::passes::geometry::UiRect {
position: Vec2::new(0.0, current_height - 2.0),
size: Vec2::new(screen_width, 2.0),
color: border_color,
corner_radius: 0.0,
border_width: 0.0,
border_color: transparent,
rotation: 0.0,
clip_rect: Some(panel_clip),
layer: UiLayer::Tooltips,
z_index: 3,
});
if shell.animation_progress > 0.95 {
let handle_color = if shell.dragging_resize || mouse_in_resize {
Vec4::new(0.6, 0.8, 1.0, 1.0)
} else {
Vec4::new(0.5, 0.5, 0.55, 0.8)
};
let handle_width = 40.0;
let handle_height_px = 3.0;
ui.draw_overlay_rect(crate::render::wgpu::passes::geometry::UiRect {
position: Vec2::new((screen_width - handle_width) * 0.5, current_height + 4.0),
size: Vec2::new(handle_width, handle_height_px),
color: handle_color,
corner_radius: 1.5,
border_width: 0.0,
border_color: transparent,
rotation: 0.0,
clip_rect: None,
layer: UiLayer::Tooltips,
z_index: 10,
});
}
if shell.visible && shell.animation_progress > 0.9 {
if shell.pending_enter {
shell.pending_enter = false;
shell.execute_command(world);
}
if shell.pending_up {
shell.pending_up = false;
shell.history_up();
}
if shell.pending_down {
shell.pending_down = false;
shell.history_down();
}
if shell.pending_escape {
shell.pending_escape = false;
shell.visible = false;
}
}
}