pages are fun

This commit is contained in:
2026-02-25 18:32:48 +01:00
parent e258e59a75
commit 07720507f4
15 changed files with 1056 additions and 99 deletions

View File

@@ -32,7 +32,10 @@ use bevy_egui::{
};
use bevy_mod_openxr::session::OxrSession;
use bevy_pkv::{PersistentResourceAppExtensions, PkvStore};
use egui::{Color32, Margin, PointerButton, Pos2};
use egui::{
Button, Color32, Layout, Margin, PointerButton, Pos2, Rect, TextEdit, Theme, Ui,
scroll_area::ScrollSource,
};
use openxr::Path;
use serde::{Deserialize, Serialize};
@@ -46,7 +49,7 @@ use crate::{
keyboard::VirtualKeyboard,
otdipcplugin::{OtdIpcPlugin, PenButtons, PenDelta, PenPosition},
},
egui_pages::{Overview, overview},
egui_pages::*,
vrcontrollerplugin::{
LeftController, LeftControllerActions, RightController, RightControllerActions,
},
@@ -101,6 +104,9 @@ impl Default for KneeboardPosition {
}
}
#[derive(Resource, Serialize, Deserialize, Default)]
pub struct KneeboardNotepad(String);
pub struct APadPlugin;
impl Plugin for APadPlugin {
fn build(&self, app: &mut App) {
@@ -109,10 +115,12 @@ impl Plugin for APadPlugin {
.add_plugins(MaterialPlugin::<MyCustomMaterial>::default());
app.insert_resource(PkvStore::new("Avii", "Kneeboard"))
.init_persistent_resource::<KneeboardPosition>();
.init_persistent_resource::<KneeboardPosition>()
.init_persistent_resource::<KneeboardNotepad>();
app.insert_resource(TabletSize(Vec2::new(210.0, 279.0)));
app.insert_resource(TabletResolutionScale(2.25));
// app.insert_resource(TabletResolutionScale(2.25));
app.insert_resource(TabletResolutionScale(2.5));
app.insert_resource(PointerImage(None));
app.insert_resource(Name("".to_string()));
app.insert_resource(KeyboardVisible(false));
@@ -127,9 +135,11 @@ impl Plugin for APadPlugin {
position_kneeboard,
move_kneeboard,
sync_camera_with_kneeboard,
),
)
.chain(),
)
.add_systems(Update, pointer.in_set(EguiInputSet::InitReading))
.add_systems(Update, update_pointer.in_set(EguiInputSet::WriteEguiEvents))
.add_systems(Update, render_pointer)
.add_systems(WorldspaceContextPass, update);
}
}
@@ -158,29 +168,16 @@ fn setup_pointer(
pointer.0 = Some(image);
}
fn pointer(
fn update_pointer(
tablet_size: Res<TabletSize>,
tablet_res: Res<TabletResolutionScale>,
ent: Single<Entity, With<bevy_egui::EguiContext>>,
mesh_material: Single<&MeshMaterial3d<MyCustomMaterial>, With<Kneeboard>>,
mut pen_buttons: MessageReader<PenButtons>,
mut pen_delta: MessageReader<PenDelta>,
mut pen_position: MessageReader<PenPosition>,
mut input_writer: MessageWriter<EguiInputEvent>,
mut materials: ResMut<Assets<MyCustomMaterial>>,
mut images: ResMut<Assets<Image>>,
mut pointer: ResMut<PointerImage>,
mut pen_button_pressed: ResMut<WasPenButtonPressed>,
) {
let Some(ref mut pointer) = pointer.0 else {
return;
};
let Some(image) = images.get_mut(&*pointer) else {
return;
};
image.clear(&[0u8; 4]);
for pos in pen_position.read() {
let x = pos.x * tablet_size.x * **tablet_res;
let y = pos.y * tablet_size.y * **tablet_res;
@@ -206,6 +203,7 @@ fn pointer(
continue;
}
// this is making me drop inputs or something
if **pen_button_pressed != button.tip() {
input_writer.write(EguiInputEvent {
context: *ent,
@@ -219,7 +217,31 @@ fn pointer(
**pen_button_pressed = button.tip();
}
}
}
}
fn render_pointer(
tablet_size: Res<TabletSize>,
tablet_res: Res<TabletResolutionScale>,
mesh_material: Single<&MeshMaterial3d<MyCustomMaterial>, With<Kneeboard>>,
mut pen_position: MessageReader<PenPosition>,
mut materials: ResMut<Assets<MyCustomMaterial>>,
mut images: ResMut<Assets<Image>>,
mut pointer: ResMut<PointerImage>,
) {
let Some(ref mut pointer) = pointer.0 else {
return;
};
let Some(image) = images.get_mut(&*pointer) else {
return;
};
image.clear(&[0u8; 4]);
for pos in pen_position.read() {
let x = pos.x * tablet_size.x * **tablet_res;
let y = pos.y * tablet_size.y * **tablet_res;
draw_pointer(image, x, y);
if let Some(material) = materials.get_mut(mesh_material.0.id()) {
@@ -354,44 +376,109 @@ fn update(
mut input: Single<&mut bevy_egui::EguiInput>,
mut keyboard: Single<&mut Keyboard>,
mut notepad: ResMut<KneeboardNotepad>,
mo: Res<Overview>,
sr: Res<Sitrep>,
pr: Res<PilotRoster>,
pe: Res<PackageElements>,
ta: Res<ThreatAnalysis>,
sp: Res<Steerpoints>,
cl: Res<Commladder>,
or: Res<Ordnance>,
wt: Res<Weather>,
su: Res<Support>,
ro: Res<RulesOfEngagement>,
ep: Res<Emergency>,
) {
let bgcolor = egui::containers::Frame {
fill: egui::Color32::from_rgb(43, 44, 47),
inner_margin: Margin {
left: 15,
right: 15,
top: 15,
bottom: 15,
},
ctx.get_mut().options_mut(|opt| {
opt.input_options.max_click_dist = 24.0;
opt.input_options.max_click_duration = 1.0;
});
let margins = egui::containers::Frame {
inner_margin: Margin::same(15),
..Default::default()
};
let focus = keyboard.is_active(ctx.get_mut());
let height = if focus { 200.0 } else { 0.0 };
egui::containers::CentralPanel::default()
.frame(bgcolor)
.show(ctx.get_mut(), |ui| {
egui::containers::TopBottomPanel::bottom("bottom_panel")
.resizable(false)
.height_range(egui::Rangef::new(0., height))
.show_inside(ui, |ui| {
ui.vertical_centered(|ui| {
keyboard.show(ui);
});
egui::containers::CentralPanel::default().show(ctx.get_mut(), |ui| {
egui::containers::TopBottomPanel::bottom("bottom_panel")
.resizable(false)
.height_range(egui::Rangef::new(0., height))
.show_inside(ui, |ui| {
ui.with_layout(Layout::top_down_justified(egui::Align::Center), |ui| {
keyboard.show(ui);
});
egui::ScrollArea::vertical().show(ui, |ui| {
overview(ui, mo);
// ..
});
ui.with_layout(Layout::top_down_justified(egui::Align::LEFT), |ui| {
let rect = ui
.add(TextEdit::multiline(&mut notepad.0).margin(Margin::same(8)))
.rect;
global_theme_preference_switch(ui, &rect);
});
egui::containers::CentralPanel::default()
.frame(margins)
.show_inside(ui, |ui| {
egui::ScrollArea::vertical()
// .scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::AlwaysHidden)
.scroll_source(ScrollSource::MOUSE_WHEEL | ScrollSource::SCROLL_BAR)
.show(ui, |ui| {
overview(ui, &mo);
ui.add(egui::Separator::default().grow(8.0));
sitrep(ui, &sr);
ui.add(egui::Separator::default().grow(8.0));
pilot_roster(ui, &pr);
ui.add(egui::Separator::default().grow(8.0));
package_elements(ui, &pe);
ui.add(egui::Separator::default().grow(8.0));
threat_analysis(ui, &ta);
ui.add(egui::Separator::default().grow(8.0));
steerpoints(ui, &sp);
ui.add(egui::Separator::default().grow(8.0));
commladder(ui, &cl);
ui.add(egui::Separator::default().grow(8.0));
ordnance(ui, &or, &mo);
ui.add(egui::Separator::default().grow(8.0));
weather(ui, &wt);
ui.add(egui::Separator::default().grow(8.0));
support(ui, &su);
ui.add(egui::Separator::default().grow(8.0));
rulesofengagement(ui, &ro);
ui.add(egui::Separator::default().grow(8.0));
emergency(ui, &ep);
});
});
});
keyboard.bump_events(ctx.get_mut(), &mut input.0);
}
pub fn global_theme_preference_switch(ui: &mut Ui, rect: &egui::Rect) {
let theme = ui.ctx().theme();
let icon = if theme == Theme::Dark { "" } else { "🌙" };
let new_theme = if theme == Theme::Dark {
Theme::Light
} else {
Theme::Dark
};
let size = 16.;
let min = egui::pos2(rect.max.x - size, rect.min.y - 2.);
let max = egui::pos2(rect.max.x, size - 2.);
let new_rect = Rect::from_min_max(min, max);
if ui.put(new_rect, Button::new(icon).frame(false)).clicked() {
ui.ctx().set_theme(new_theme);
}
}
fn sync_camera_with_kneeboard(
kneeboard: Query<&Transform, With<Kneeboard>>,
mut cameras: Query<&mut Transform, (With<MainCamera>, Without<Kneeboard>)>,
@@ -482,8 +569,6 @@ fn move_kneeboard(
if let Ok(trigger_state) = left.squeeze_click.state(&session, Path::NULL)
&& trigger_state.current_state
{
dbg!("squeeze triggered");
let Ok(transform) = left_transform.single() else {
return;
};