mod colors; mod widgets; use std::f32; use bevy_ecs::entity::Entity; use bevy_ecs::event::Events; use bevy_ecs::prelude::With; use bevy_ecs::world::World; use egui::{Align, Align2, CornerRadius, CursorIcon, Layout, Margin, Order, ProgressBar, RichText, Shadow, Stroke, Visuals}; use starkingdoms_common::packet::Packet; use crate::components::{Camera, Chat, Menu, Player, PlayerResources, SendPacket, Transform}; use crate::ui::widgets::{progress_bar, RichTextExt}; pub fn init_ui(ctx: egui::Context) { // set colors let mut style = egui::Style::default(); let mut visuals = Visuals::default(); visuals.dark_mode = true; // TODO(core): code_bg_colors visuals.warn_fg_color = colors::YELLOW; // used for warning text visuals.error_fg_color = colors::RED; // used for error text visuals.window_shadow = Shadow::NONE; visuals.window_fill = colors::MANTLE; // window background color visuals.extreme_bg_color = colors::CRUST; // must be darker than window_fill visuals.faint_bg_color = colors::BASE; // slightly different than window background color visuals.window_stroke.color = colors::SURFACE_0; visuals.window_highlight_topmost = false; visuals.text_cursor.stroke.color = colors::ROSEWATER; // TODO(core): button_frame, collapsing_header_frame visuals.striped = true; visuals.interact_cursor = Some(CursorIcon::PointingHand); visuals.selection.bg_fill = colors::OVERLAY_2.gamma_multiply(0.2); // selection background visuals.hyperlink_color = colors::BLUE; visuals.widgets.noninteractive.fg_stroke.color = colors::TEXT; // standard text color style.visuals = visuals; ctx.set_style(style); } pub fn draw_ui(ctx: &egui::Context, world: &mut World, send_packet_events: &mut Events) { draw_status_bar(ctx, world); draw_chat(ctx, world, send_packet_events); draw_crafting(ctx, world); } pub fn draw_status_bar(ctx: &egui::Context, world: &mut World) { let mut player = world.query_filtered::<&Transform, With>(); let player_position = player.single(&world); let player_resources = world.resource::(); egui::Window::new("status_bar") .title_bar(false) .movable(false) .resizable(false) .order(Order::Foreground) .anchor(Align2::CENTER_BOTTOM, [0.0, -5.0]) .show(ctx, |ui| { ui.horizontal(|ui| { ui.vertical(|ui| { ui.label(RichText::new("Position:").stk_weak()); ui.label(RichText::new(format!("{:.0}, {:.0}", player_position.translation.x / 10.0, player_position.translation.y / 10.0))) }); ui.add_space(8.0); ui.vertical(|ui| { ui.horizontal(|ui| { ui.label(RichText::new("Fuel:").stk_weak()); ui.with_layout(Layout::right_to_left(Align::Center), |ui| { ui.label(RichText::new(format!("{}/{} ({:.2}%)", player_resources.fuel_amount, player_resources.fuel_max, player_resources.fuel_amount as f32 / player_resources.fuel_max as f32 * 100.0))) }); }); ui.add( progress_bar(player_resources.fuel_amount as f32 / player_resources.fuel_max as f32) ); }) }); }); } pub fn draw_chat(ctx: &egui::Context, world: &mut World, send_packet_events: &mut Events) { let mut chat = world.get_resource_mut::().unwrap(); egui::Window::new("Chat") .movable(true) .order(Order::Foreground) .show(ctx, |ui| { egui::Frame::new() .inner_margin(Margin::same(5)) .corner_radius(2) .fill(colors::CRUST) .show(ui, |ui| { egui::ScrollArea::vertical() .max_width(f32::INFINITY) .max_height(100.0) .auto_shrink(false) .stick_to_bottom(true) .show(ui, |ui| { for message in &chat.messages { ui.label(message); } }); }); ui.horizontal(|ui| { let output = egui::TextEdit::singleline(&mut chat.textbox).show(ui); if ui.button("Send").clicked() || (ctx.input(|i| i.key_pressed(egui::Key::Enter)) && output.response.lost_focus()) { send_packet_events.send(SendPacket(Packet::SendMessage { target: None, content: chat.textbox.clone(), })); chat.textbox.clear(); } }); }); } pub fn draw_crafting(ctx: &egui::Context, world: &mut World) { let mut menus = world.query_filtered::<(Entity, &Transform), With>(); let camera = world.resource::(); for (entity, menu) in menus.iter(&world) { egui::Window::new("Crafting") .id(format!("Crafting{}", entity.index()).into()) .pivot(Align2::LEFT_BOTTOM) .fixed_pos(((menu.translation.x + camera.x) * camera.zoom + camera.width as f32 / 2.0, (menu.translation.y + camera.y) * camera.zoom + camera.height as f32 / 2.0)) .show(ctx, |ui| { }); } }