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
121
122
123
124
125
126
127
128
129
130
131
132
133
use std::{ffi::c_void, marker::PhantomData, mem};

use crate::{
    core::{CoreStateImplementation, CoreWindowRef},
    state::CoreStateData,
    util::PhantomUnsend,
    DrawingContext, RectRegion, WWindInitState, WWindState,
};

pub type OnClose<UserData> = dyn FnMut(&mut WWindState<UserData>, &mut Window<UserData>) + 'static;
pub type OnRedraw<UserData> =
    dyn FnMut(&mut WWindState<UserData>, &mut Window<UserData>, RectRegion) + 'static;
pub type OnKeydown<UserData> =
    dyn FnMut(&mut WWindState<UserData>, &mut Window<UserData>, u32) + 'static;

pub struct WindowData {
    pub on_close: Option<[usize; 2]>,
    pub redraw: Option<[usize; 2]>,
    pub keydown: Option<[usize; 2]>,
}

impl WindowData {
    pub fn new(_width: u16, _height: u16) -> Self {
        Self {
            on_close: None,
            redraw: None,
            keydown: None,
        }
    }
}

#[repr(C)]
pub struct Window<'a, UserData = ()> {
    window_ref: CoreWindowRef,
    data: *mut CoreStateData,
    _unsend: PhantomUnsend,
    _phantom_data: PhantomData<(&'a (), UserData)>,
}

impl<'a, UserData> Window<'a, UserData> {
    pub(crate) unsafe fn with_data<V>(self) -> Window<'a, V> {
        mem::transmute(self)
    }

    pub fn schedule_window_destruction(&mut self) {
        let window_to_schedule = self.window_ref;
        let windows_to_destroy = &mut self.get_core_data_mut().windows_to_destroy;

        if !windows_to_destroy.contains(&window_to_schedule) {
            windows_to_destroy.push(window_to_schedule);
        }
    }

    pub fn on_window_close<F: FnMut(&mut WWindState<UserData>, &mut Window<UserData>) + 'static>(
        &mut self,
        closure: F,
    ) {
        let window_ref = self.window_ref;

        if let Some(window_data) = self.get_core_data_mut().windows.get_mut(&window_ref) {
            if let Some(old_binding) = window_data.on_close {
                drop(unsafe { mem::transmute::<[usize; 2], Box<OnClose<UserData>>>(old_binding) })
            }

            window_data.on_close =
                Some(unsafe { mem::transmute(Box::new(closure) as Box<OnClose<UserData>>) });
        }
    }

    pub fn on_redraw<
        F: FnMut(&mut WWindState<UserData>, &mut Window<UserData>, RectRegion) + 'static,
    >(
        &mut self,
        closure: F,
    ) {
        let window_ref = self.window_ref;

        if let Some(window_data) = self.get_core_data_mut().windows.get_mut(&window_ref) {
            if let Some(old_binding) = window_data.redraw {
                drop(unsafe { mem::transmute::<[usize; 2], Box<OnRedraw<UserData>>>(old_binding) })
            }

            window_data.redraw =
                Some(unsafe { mem::transmute(Box::new(closure) as Box<OnRedraw<UserData>>) });
        }
    }

    pub fn on_keydown<F: FnMut(&mut WWindState<UserData>, &mut Window<UserData>, u32) + 'static>(
        &mut self,
        closure: F,
    ) {
        let window_ref = self.window_ref;

        if let Some(window_data) = self.get_core_data_mut().windows.get_mut(&window_ref) {
            if let Some(old_binding) = window_data.keydown {
                drop(unsafe { mem::transmute::<[usize; 2], Box<OnKeydown<UserData>>>(old_binding) })
            }

            window_data.keydown =
                Some(unsafe { mem::transmute(Box::new(closure) as Box<OnKeydown<UserData>>) });
        }
    }
    pub fn get_drawing_context(&mut self) -> DrawingContext<'_> {
        let window_ref = self.window_ref;

        let context = unsafe { self.get_core_data_mut().core_state.get_context(window_ref) };

        DrawingContext::from_parts(context, self.data)
    }

    pub fn get_size(&self) -> (u16, u16) {
        let window_ref = self.window_ref;

        self.get_core_data().core_state.get_size(window_ref)
    }
}

impl<UserData> Window<'_, UserData> {
    pub(crate) fn from_parts(window_ref: CoreWindowRef, data: *mut CoreStateData) -> Self {
        Self {
            window_ref,
            data,
            _unsend: Default::default(),
            _phantom_data: PhantomData,
        }
    }
    pub(crate) fn get_core_data_mut(&mut self) -> &mut CoreStateData {
        unsafe { &mut *self.data }
    }
    pub(crate) fn get_core_data(&self) -> &CoreStateData {
        unsafe { &*self.data }
    }
}