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
use conrod_core::{widget, Position, Sizeable, Ui, UiCell, Widget, WidgetCommon};
use vek::*;

#[derive(Clone, WidgetCommon)]
pub struct Ingame<W> {
    #[conrod(common_builder)]
    common: widget::CommonBuilder,
    widget: W,
    prim_num: usize,
    pos: Vec3<f32>,
}

pub trait Ingameable: Widget + Sized {
    fn prim_count(&self) -> usize;
    // Note this is not responsible for the 3d positioning
    // Only call this directly if using IngameAnchor
    fn set_ingame(self, id: widget::Id, ui: &mut UiCell) -> Self::Event {
        self
            // should pass focus to the window if these are clicked
            // (they are not displayed where conrod thinks they are)
            .graphics_for(ui.window)
            .set(id, ui)
    }
    fn position_ingame(self, pos: Vec3<f32>) -> Ingame<Self> { Ingame::new(pos, self) }
}

pub trait PrimitiveMarker {}
impl PrimitiveMarker for widget::Line {}
impl PrimitiveMarker for widget::Image {}
impl<I> PrimitiveMarker for widget::PointPath<I> {}
impl PrimitiveMarker for widget::Circle {}
impl<S> PrimitiveMarker for widget::Oval<S> {}
impl<I> PrimitiveMarker for widget::Polygon<I> {}
impl PrimitiveMarker for widget::Rectangle {}
impl<S, I> PrimitiveMarker for widget::Triangles<S, I> {}
impl<'a> PrimitiveMarker for widget::Text<'a> {}

impl<P> Ingameable for P
where
    P: Widget + PrimitiveMarker,
{
    fn prim_count(&self) -> usize { 1 }
}

// All ingame widgets are now fixed scale
#[derive(Copy, Clone, PartialEq)]
pub struct IngameParameters {
    // Number of primitive widgets to position in the game at the specified position
    // Note this could be more than the number of widgets in the widgets field since widgets can
    // contain widgets
    pub num: usize,
    pub pos: Vec3<f32>,
    pub dims: Vec2<f32>,
}

pub struct State {
    id: widget::Id,
    pub parameters: IngameParameters,
}

pub type Style = ();

impl<W: Ingameable> Ingame<W> {
    pub fn new(pos: Vec3<f32>, widget: W) -> Self {
        Self {
            common: widget::CommonBuilder::default(),
            prim_num: widget.prim_count(),
            pos,
            widget,
        }
    }
}

impl<W: Ingameable> Widget for Ingame<W> {
    type Event = W::Event;
    type State = State;
    type Style = Style;

    fn init_state(&self, mut id_gen: widget::id::Generator) -> Self::State {
        State {
            id: id_gen.next(),
            parameters: IngameParameters {
                num: self.prim_num,
                pos: self.pos,
                dims: Vec2::zero(),
            },
        }
    }

    fn style(&self) -> Self::Style {}

    fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
        let widget::UpdateArgs { state, ui, .. } = args;
        let Ingame {
            widget,
            prim_num,
            pos,
            ..
        } = self;

        let parameters = IngameParameters {
            num: prim_num,
            pos,
            dims: Vec2::<f64>::from(widget.get_wh(ui).unwrap_or([1.0, 1.0])).map(|e| e as f32),
        };

        // Update parameters if it has changed
        if state.parameters != parameters {
            state.update(|s| {
                s.parameters = parameters;
            });
        }

        widget.set_ingame(state.id, ui)
    }

    fn default_x_position(&self, _: &Ui) -> Position { Position::Absolute(0.0) }

    fn default_y_position(&self, _: &Ui) -> Position { Position::Absolute(0.0) }
}