forestiles/src/ui.rs
2025-01-23 19:42:39 +01:00

119 lines
4.5 KiB
Rust

use mevy::*;
use bevy::{asset::embedded_asset, input::mouse::MouseWheel, math::{NormedVectorSpace, VectorSpace}, picking::{focus::HoverMap, pointer::PointerId}, prelude::*, utils::{dbg, HashMap}, window::PrimaryWindow};
use crate::map::{self, MapMarker};
pub struct Plugin;
impl bevy::prelude::Plugin for Plugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, setup)
.add_systems(Update, zoom_with_scroll);
embedded_asset!(app, "../assets/ui/tree.png");
}
}
#[derive(Component, Debug)]
struct PointersDragging(HashMap<PointerId, Vec2>);
#[derive(Component)]
pub struct MapUIComponent;
fn setup(
mut world: Commands,
asset_server: Res<AssetServer>
) {
spawn!{
Node {width: 100%, height: 100%, display: Display::Flex, flex_direction: FlexDirection::Column, !};
PickingBehavior {
should_block_lower: false,
is_hoverable: true
};
.observe(move |trigger: Trigger<Pointer<DragStart>>, mut ptrs: Query<&mut PointersDragging>| {
if trigger.button == PointerButton::Primary {
if let Ok(mut ptrs) = ptrs.get_mut(trigger.target) {
ptrs.0.insert(trigger.pointer_id, trigger.pointer_location.position);
}
}
});
.observe(move |trigger: Trigger<Pointer<DragEnd>>, mut ptrs: Query<&mut PointersDragging>| {
if trigger.button == PointerButton::Primary {
ptrs.single_mut().0.remove(&trigger.pointer_id);
}
});
.observe(|
trigger: Trigger<Pointer<Drag>>,
mut ptrs: Query<&mut PointersDragging>,
mut cam: Query<&mut Transform, With<Camera2d>>,
| {
if trigger.button == PointerButton::Primary {
let mut ptrs = ptrs.single_mut();
if !ptrs.0.contains_key(&trigger.pointer_id) {
return
}
let mut cam = cam.single_mut();
let old_midpoint = ptrs.0.values().fold(Vec2::ZERO, |acc, pos| acc + (pos/ptrs.0.len() as f32));
let old_d_to_midpoint = ptrs.0.values().fold(0., |acc, pos| acc + (old_midpoint-pos).norm());
ptrs.0.insert(trigger.pointer_id, trigger.pointer_location.position);
let new_midpoint = ptrs.0.values().fold(Vec2::ZERO, |acc, pos| acc + (pos/ptrs.0.len() as f32));
let new_d_to_midpoint = ptrs.0.values().fold(0., |acc, pos| acc + (new_midpoint-pos).norm());
// move camera
cam.translation.x -= (new_midpoint.x - old_midpoint.x)*cam.scale.x;
cam.translation.y += (new_midpoint.y - old_midpoint.y)*cam.scale.y;
if ptrs.0.len() > 1 {
cam.scale *= old_d_to_midpoint/new_d_to_midpoint;
}
}
}
);
[map][
Node{
flex_grow: 1.,
!};
PointersDragging(HashMap::new());
MapUIComponent;
PickingBehavior {
should_block_lower: false,
is_hoverable: true
};
]
[
Node{
width: 100%,
height: 10vh,
align_self: AlignSelf::FlexEnd,
!};
Button;
BorderColor(#F00);
BackgroundColor(#77767b);
[
ImageNode::new(asset_server.load("embedded://forestiles/../assets/ui/tree.png"));
Node {
height: 80%,
margin: [>1vh],
!};
]
]
}
// Spawn all ui elements as children of this one
}
fn zoom_with_scroll(
mut cam: Query<&mut Transform, With<Camera2d>>,
mut ev_scroll: EventReader<MouseWheel>,
hover_map: Res<HoverMap>,
window: Query<&Window, With<PrimaryWindow>>,
map_ui_id: Query<Entity, With<MapUIComponent>>
) {
let map_ui_id = map_ui_id.single();
if hover_map.get(&PointerId::Mouse).and_then(|hovered_ids| hovered_ids.get(&map_ui_id)).is_some() {
let window = window.single();
let mut cam = cam.single_mut();
for ev in ev_scroll.read() {
let scale = (cam.scale.x-(ev.y*0.1/window.width().min(window.height()))).clamp(0.0001, 2./window.width().min(window.height()));
cam.scale = Vec3::new(scale, scale, scale);
}
}
}