use std::cell::RefCell;
use std::rc::Rc;
use crate::model::{Pointer, Saber, SaberVisibility, Window};
use crate::scene::{SceneInput, ScenePose};
use crate::ui::UIEvent;
const ACTIVE: f32 = 0.15;
pub struct UISubr {
inner: RefCell<Inner>,
}
struct Inner {
prev_click_l: Option<bool>,
prev_click_r: Option<bool>,
active_saber: ActiveSaber,
active_info_opt: Option<ActiveInfo>,
}
enum ActiveSaber {
Left,
Right,
}
struct ActiveInfo {
window: Rc<Window>,
last_move: Option<(f32, f32)>,
}
impl UISubr {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
inner: RefCell::new(Inner {
prev_click_l: None,
prev_click_r: None,
active_saber: ActiveSaber::Right,
active_info_opt: None,
})
}
}
pub fn reset(&self) {
let mut inner = self.inner.borrow_mut();
inner.prev_click_l = None;
inner.prev_click_r = None;
inner.active_info_opt = None;
}
pub fn update<'a, T: Iterator<Item = &'a Rc<Window>>>(&self, saber_l: &Saber, saber_r: &Saber, pointer: &Pointer, windows: T, scene_input: &SceneInput) {
let mut inner = self.inner.borrow_mut();
let pose_l_opt = &scene_input.pose_l_opt;
let pose_r_opt = &scene_input.pose_r_opt;
Self::update_saber(saber_l, pose_l_opt);
Self::update_saber(saber_r, pose_r_opt);
let click_l = Self::update_click(&mut inner.prev_click_l, pose_l_opt);
let click_r = Self::update_click(&mut inner.prev_click_r, pose_r_opt);
let active_saber = &mut inner.active_saber;
let mut click = false;
if click_l && click_r {
} else if click_l {
*active_saber = ActiveSaber::Left;
click = true;
} else if click_r {
*active_saber = ActiveSaber::Right;
click = true;
} else {
}
let pose_opt = match active_saber {
ActiveSaber::Left => pose_l_opt,
ActiveSaber::Right => pose_r_opt,
};
let mut pointer_visible = false;
if let Some(pose) = *pose_opt {
if pose.get_render() {
pointer_visible = true;
}
let mut pointer_scale = ACTIVE;
let mut have_window = false;
for window in windows {
if let Some((d, x, y)) = window.intersect(pose) {
let mut active_info = ActiveInfo {
window: Rc::clone(window),
last_move: None,
};
let event_opt = if !click {
active_info.last_move = Some((x, y));
if let Some(active_info) = &inner.active_info_opt && Rc::ptr_eq(&active_info.window, window) && let Some(last_move) = &active_info.last_move && *last_move == (x, y) {
None
} else {
Some(UIEvent::PointerMove(x, y))
}
} else {
Some(UIEvent::PointerPress(x, y))
};
inner.active_info_opt = Some(active_info);
if let Some(event) = event_opt {
window.handle_event(event);
}
pointer_scale = d;
have_window = true;
break;
}
}
if !have_window && let Some(active_info) = inner.active_info_opt.take() {
active_info.window.handle_event(UIEvent::PointerExit);
}
pointer.set_scale(pointer_scale);
pointer.set_pos(pose.get_pos());
pointer.set_rot(pose.get_rot());
} else if let Some(active_info) = inner.active_info_opt.take() {
active_info.window.handle_event(UIEvent::PointerExit);
}
pointer.set_visible(pointer_visible);
}
fn update_saber(saber: &Saber, pose_opt: &Option<&dyn ScenePose>) {
if let Some(pose) = pose_opt && pose.get_render() {
saber.set_visible(SaberVisibility::Handle);
saber.set_pos(pose.get_pos());
saber.set_rot(pose.get_rot());
} else {
saber.set_visible(SaberVisibility::Hidden);
}
}
fn update_click(prev_click: &mut Option<bool>, pose_opt: &Option<&dyn ScenePose>) -> bool {
let mut click_triggered = false;
*prev_click = if let Some(pose) = pose_opt {
let click = pose.get_click();
if prev_click.is_some() && !prev_click.unwrap() && click {
click_triggered = true;
}
Some(click)
} else {
None
};
click_triggered
}
}