~starkingdoms/starkingdoms

ref: 93b350fc44934524b95c9f80884d921c53fe7981 starkingdoms/crates/client/src/ui/mod.rs -rw-r--r-- 5.8 KiB
93b350fc — ghostly_zsh chassis change merge 8 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
mod colors;
mod widgets;

use std::f32;

use crate::components::{Camera, Chat, Menu, Player, PlayerResources, SendPacket, Transform};
use crate::ui::widgets::{progress_bar, RichTextExt};
use bevy_ecs::entity::Entity;
use bevy_ecs::event::Events;
use bevy_ecs::prelude::With;
use bevy_ecs::world::World;
use egui::{Align, Align2, CursorIcon, Layout, Margin, Order, RichText, Shadow, Visuals};
use starkingdoms_common::packet::Packet;

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<SendPacket>,
) {
    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<Player>>();
    let player_position = player.single(&world);
    let player_resources = world.resource::<PlayerResources>();

    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<SendPacket>,
) {
    let mut chat = world.get_resource_mut::<Chat>().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<Menu>>();
    let camera = world.resource::<Camera>();
    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| {});
    }
}