backend.rs 8.35 KB
Newer Older
1
use std::cell::{Cell, RefCell};
Florian Blasius's avatar
Florian Blasius committed
2
use std::collections::BTreeMap;
3
use std::rc::Rc;
Florian Blasius's avatar
Florian Blasius committed
4

Michael Aaron Murphy's avatar
Fix CI  
Michael Aaron Murphy committed
5
use orbclient::{self, Color, Mode, Renderer as OrbRenderer, Window as OrbWindow};
Florian Blasius's avatar
Florian Blasius committed
6

Florian Blasius's avatar
Florian Blasius committed
7
use dces::prelude::{Entity, World};
8
use orbgl::prelude::{CairoRenderEngine, FramebufferSurface};
9
use orbgl_api::Canvas;
10

Florian Blasius's avatar
Florian Blasius committed
11
use crate::application::Tree;
12
use crate::backend::{
13
    Backend, BackendRunner, EventContext, InitContext, LayoutContext, RenderContext, StateContext,
14
};
Florian Blasius's avatar
Florian Blasius committed
15
use crate::event::{
16
    EventQueue, Key, KeyDownEvent, KeyUpEvent, MouseButton, MouseDownEvent, MouseUpEvent,
17
    SystemEvent, WindowEvent,
18
};
19 20
use crate::properties::Bounds;
use crate::structs::{Point, Position, Size};
Florian Blasius's avatar
Florian Blasius committed
21
use crate::theme::Theme;
22
use crate::widgets::MessageBox;
Florian Blasius's avatar
Florian Blasius committed
23

24
/// Implementation of the OrbClient based backend.
Florian Blasius's avatar
Florian Blasius committed
25 26
pub struct OrbitalBackend {
    inner: OrbWindow,
27
    theme: Theme,
28
    mouse_buttons: (bool, bool, bool),
29
    mouse_position: Point,
30
    event_queue: RefCell<EventQueue>,
Florian Blasius's avatar
Florian Blasius committed
31
    messages: RefCell<BTreeMap<Entity, Vec<MessageBox>>>,
Florian Blasius's avatar
Florian Blasius committed
32
    canvas: Canvas,
Florian Blasius's avatar
Florian Blasius committed
33 34
}

35
impl OrbitalBackend {
36
    pub fn new(theme: Theme, inner: OrbWindow) -> OrbitalBackend {
Florian Blasius's avatar
Florian Blasius committed
37
        let mut inner = inner;
38

Florian Blasius's avatar
Florian Blasius committed
39 40 41 42 43 44 45 46 47 48
        let surface = FramebufferSurface::new(
            inner.width(),
            inner.height(),
            inner.data_mut().as_mut_ptr() as *mut u8,
        );

        let render_engine = CairoRenderEngine::new(surface.clone());

        let canvas = Canvas::new(render_engine.clone());

49
        OrbitalBackend {
50
            inner,
51
            theme,
52
            mouse_buttons: (false, false, false),
53
            mouse_position: Point::default(),
54
            event_queue: RefCell::new(EventQueue::default()),
Florian Blasius's avatar
Florian Blasius committed
55
            messages: RefCell::new(BTreeMap::new()),
Florian Blasius's avatar
Florian Blasius committed
56
            canvas,
Florian Blasius's avatar
Florian Blasius committed
57 58
        }
    }
59 60 61 62 63 64
}

impl OrbRenderer for OrbitalBackend {
    fn width(&self) -> u32 {
        self.inner.width()
    }
Florian Blasius's avatar
Florian Blasius committed
65

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
    fn height(&self) -> u32 {
        self.inner.height()
    }

    fn data(&self) -> &[Color] {
        self.inner.data()
    }

    fn data_mut(&mut self) -> &mut [Color] {
        self.inner.data_mut()
    }

    fn sync(&mut self) -> bool {
        self.inner.sync()
    }

    fn mode(&self) -> &Cell<Mode> {
        &self.inner.mode()
    }

    fn char(&mut self, x: i32, y: i32, c: char, color: Color) {
Florian Blasius's avatar
Florian Blasius committed
87 88 89 90 91
        // if let Some(ref font) = self.font {
        //     let mut buf = [0; 4];
        //     font.render(&c.encode_utf8(&mut buf), 16.0)
        //         .draw(&mut self.inner, x, y, color)
        // } else {
92
        self.inner.char(x, y, c, color);
Florian Blasius's avatar
Florian Blasius committed
93
        // }
94 95 96 97 98 99 100 101 102 103
    }
}

impl Drop for OrbitalBackend {
    fn drop(&mut self) {
        self.inner.sync();
    }
}

impl Backend for OrbitalBackend {
104
    fn drain_events(&mut self) {
105
        self.inner.sync();
106 107 108

        for event in self.inner.events() {
            match event.to_option() {
109
                orbclient::EventOption::Mouse(mouse) => {
110 111
                    self.mouse_position.x = mouse.x as f64;
                    self.mouse_position.y = mouse.y as f64;
112 113
                    // self.event_queue
                    //     .borrow_mut()
114
                    //     .register_event(MouseMoveEvent {
115 116
                    //         position: self.mouse_position,
                    //     });
117
                }
118 119 120 121 122 123 124 125 126 127 128
                orbclient::EventOption::Button(button) => {
                    if !button.left && !button.middle && !button.right {
                        let button = {
                            if self.mouse_buttons.0 {
                                MouseButton::Left
                            } else if self.mouse_buttons.1 {
                                MouseButton::Middle
                            } else {
                                MouseButton::Right
                            }
                        };
129 130 131 132 133 134 135
                        self.event_queue.borrow_mut().register_event(
                            MouseUpEvent {
                                button,
                                position: self.mouse_position,
                            },
                            0,
                        )
136
                    } else {
137
                        let button = {
138 139 140 141 142 143 144 145
                            if button.left {
                                MouseButton::Left
                            } else if button.middle {
                                MouseButton::Middle
                            } else {
                                MouseButton::Right
                            }
                        };
146 147
                        self.event_queue.borrow_mut().register_event(
                            MouseDownEvent {
Florian Blasius's avatar
Florian Blasius committed
148 149
                                button,
                                position: self.mouse_position,
150 151 152
                            },
                            0,
                        );
153 154 155
                    }

                    self.mouse_buttons = (button.left, button.middle, button.right);
156
                }
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
                orbclient::EventOption::Key(key_event) => {
                    let key = {
                        match key_event.scancode {
                            orbclient::K_BKSP => Key::Backspace,
                            orbclient::K_UP => Key::Up,
                            orbclient::K_DOWN => Key::Down,
                            orbclient::K_LEFT => Key::Left,
                            orbclient::K_RIGHT => Key::Right,
                            _ => match key_event.character {
                                '\n' => Key::Enter,
                                _ => Key::from(key_event.character),
                            },
                        }
                    };

                    if key_event.pressed {
                        self.event_queue
                            .borrow_mut()
Florian Blasius's avatar
Florian Blasius committed
175
                            .register_event(KeyUpEvent { key }, 0);
176
                    } else {
177
                        self.event_queue
178
                            .borrow_mut()
Florian Blasius's avatar
Florian Blasius committed
179
                            .register_event(KeyDownEvent { key }, 0);
180 181
                    }
                }
182
                orbclient::EventOption::Quit(_quit_event) => {
Florian Blasius's avatar
Florian Blasius committed
183 184
                    self.event_queue
                        .borrow_mut()
Florian Blasius's avatar
Florian Blasius committed
185
                        .register_event(SystemEvent::Quit, 0);
186 187 188 189
                }
                orbclient::EventOption::Resize(resize_event) => {
                    self.event_queue.borrow_mut().register_event(
                        WindowEvent::Resize {
190 191
                            width: resize_event.width as f64,
                            height: resize_event.height as f64,
192 193 194
                        },
                        0,
                    );
195
                }
196 197 198
                _ => {}
            }
        }
199
    }
Florian Blasius's avatar
Florian Blasius committed
200 201 202 203 204

    fn size(&self) -> (u32, u32) {
        (self.width(), self.height())
    }

205
    fn bounds(&mut self, bounds: &Bounds) {
206
        self.inner.set_pos(bounds.x() as i32, bounds.y() as i32);
Florian Blasius's avatar
Florian Blasius committed
207 208
        self.inner
            .set_size(bounds.width() as u32, bounds.height() as u32);
Florian Blasius's avatar
Florian Blasius committed
209
    }
210

211 212 213 214
    fn init_context(&mut self) -> InitContext<'_> {
        InitContext { theme: &self.theme }
    }

Florian Blasius's avatar
Florian Blasius committed
215
    fn render_context(&mut self) -> RenderContext<'_> {
216
        RenderContext {
Florian Blasius's avatar
Florian Blasius committed
217
            canvas: &mut self.canvas,
218
            renderer: &mut self.inner,
219
            theme: &self.theme,
Florian Blasius's avatar
Florian Blasius committed
220
            event_queue: &self.event_queue,
221 222 223
        }
    }

Florian Blasius's avatar
Florian Blasius committed
224
    fn layout_context(&mut self) -> LayoutContext<'_> {
225 226 227 228 229 230
        LayoutContext {
            window_size: self.size(),
            theme: &self.theme,
        }
    }

Florian Blasius's avatar
Florian Blasius committed
231
    fn event_context(&mut self) -> EventContext<'_> {
232
        EventContext {
233
            event_queue: &self.event_queue,
234 235
        }
    }
Florian Blasius's avatar
Florian Blasius committed
236

Florian Blasius's avatar
Florian Blasius committed
237
    fn state_context(&mut self) -> StateContext<'_> {
Florian Blasius's avatar
Florian Blasius committed
238 239 240 241 242
        StateContext {
            theme: &self.theme,
            event_queue: &self.event_queue,
            messages: &mut self.messages,
        }
Florian Blasius's avatar
Florian Blasius committed
243
    }
244 245
}

246
/// Implementation of the OrbClient based backend runner.
247 248 249 250 251 252 253 254 255
pub struct OrbitalBackendRunner {
    pub world: Option<World<Tree>>,
    pub backend: Rc<RefCell<OrbitalBackend>>,
}

impl BackendRunner for OrbitalBackendRunner {
    fn world(&mut self, world: World<Tree>) {
        self.world = Some(world);
    }
256
    fn run(&mut self, update: Rc<Cell<bool>>, running: Rc<Cell<bool>>) {
257
        loop {
258
            if !running.get() {
259
                break;
260
            }
261

stratact's avatar
stratact committed
262 263
            if let Some(world) = &mut self.world {
                world.run();
stratact's avatar
stratact committed
264
            }
Florian Blasius's avatar
Florian Blasius committed
265

stratact's avatar
stratact committed
266 267
            update.set(false);

Florian Blasius's avatar
Florian Blasius committed
268
            self.backend.borrow_mut().drain_events();
269 270
        }
    }
Florian Blasius's avatar
Florian Blasius committed
271
}