use std::any::Any;
use std::fmt::Debug;
use std::hash::{BuildHasher, Hash, Hasher};
use std::ops::Deref;
use enum_dispatch::enum_dispatch;
use crate::{GizmoDrawData, GizmoResult, config::PreparedGizmoConfig, gizmo::Ray};
pub(crate) use arcball::ArcballSubGizmo;
pub(crate) use rotation::RotationSubGizmo;
pub(crate) use scale::ScaleSubGizmo;
pub(crate) use translation::TranslationSubGizmo;
pub(crate) mod arcball;
pub(crate) mod common;
pub(crate) mod rotation;
pub(crate) mod scale;
pub(crate) mod translation;
#[derive(Clone, Debug)]
#[enum_dispatch(SubGizmoControl)]
pub(crate) enum SubGizmo {
Rotate(RotationSubGizmo),
Translate(TranslationSubGizmo),
Scale(ScaleSubGizmo),
Arcball(ArcballSubGizmo),
}
#[enum_dispatch]
pub(crate) trait SubGizmoControl {
fn id(&self) -> u64;
fn update_config(&mut self, config: PreparedGizmoConfig);
fn set_focused(&mut self, focused: bool);
fn set_active(&mut self, active: bool);
fn is_focused(&self) -> bool;
fn is_active(&self) -> bool;
fn pick(&mut self, ray: Ray) -> Option<f64>;
fn update(&mut self, ray: Ray) -> Option<GizmoResult>;
fn draw(&self) -> GizmoDrawData;
fn pick_preview(&self, ray: Ray) -> bool;
}
pub(crate) trait SubGizmoKind: 'static {
type Params: Debug + Copy + Hash;
type State: Debug + Copy + Clone + Send + Sync + Default + 'static;
type PickPreview: Picked + 'static;
fn pick(subgizmo: &mut SubGizmoConfig<Self>, ray: Ray) -> Option<f64>
where
Self: Sized;
fn update(subgizmo: &mut SubGizmoConfig<Self>, ray: Ray) -> Option<GizmoResult>
where
Self: Sized;
fn draw(subgizmo: &SubGizmoConfig<Self>) -> GizmoDrawData
where
Self: Sized;
fn pick_preview(subgizmo: &SubGizmoConfig<Self>, ray: Ray) -> Self::PickPreview
where
Self: Sized;
}
pub trait Picked {
fn picked(&self) -> bool;
}
#[derive(Clone, Debug)]
pub(crate) struct SubGizmoConfig<T: SubGizmoKind> {
id: u64,
params: T::Params,
pub(crate) config: PreparedGizmoConfig,
pub(crate) focused: bool,
pub(crate) active: bool,
pub(crate) state: T::State,
}
impl<T: SubGizmoKind> Deref for SubGizmoConfig<T> {
type Target = T::Params;
fn deref(&self) -> &Self::Target {
&self.params
}
}
impl<T> SubGizmoConfig<T>
where
T: SubGizmoKind,
{
pub(crate) fn new(config: PreparedGizmoConfig, params: T::Params) -> Self {
let mut hasher = ahash::RandomState::with_seeds(1, 2, 3, 4).build_hasher();
params.type_id().hash(&mut hasher);
params.hash(&mut hasher);
let id = hasher.finish();
Self {
id,
params,
config,
focused: false,
active: false,
state: Default::default(),
}
}
}
impl<T> SubGizmoControl for SubGizmoConfig<T>
where
T: SubGizmoKind,
{
fn id(&self) -> u64 {
self.id
}
fn update_config(&mut self, config: PreparedGizmoConfig) {
self.config = config;
}
fn set_focused(&mut self, focused: bool) {
self.focused = focused;
}
fn set_active(&mut self, active: bool) {
self.active = active;
}
fn is_focused(&self) -> bool {
self.focused
}
fn is_active(&self) -> bool {
self.active
}
fn pick(&mut self, ray: Ray) -> Option<f64> {
T::pick(self, ray)
}
fn update(&mut self, ray: Ray) -> Option<GizmoResult> {
T::update(self, ray)
}
fn draw(&self) -> GizmoDrawData {
T::draw(self)
}
fn pick_preview(&self, ray: Ray) -> bool {
T::pick_preview(self, ray).picked()
}
}