aboutsummaryrefslogtreecommitdiff
path: root/src/gui/tool_sidebar.rs
blob: af6af743a028755f5c365a5514aa263b4b369dae (plain) (blame)
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
//! The sidebar showing all tools available to the user. This toolbar handles changing the active tool
//! based on the mouse input and (TODO!) keyboard inputs.
// TODO: Currently, the keyboard shortcuts for tools are handled by the editor, but a lot speaks for
// them being handled by the ToolSidebar instead.

use crate::input::Input;
use crate::math::Rect;
use crate::tool::ToolType;
use crate::Editor;
use raylib::core::texture::Texture2D;
use raylib::rgui::RaylibDrawGui;
use raylib::{RaylibHandle, RaylibThread};
use std::mem;

/// The file containing textures for all buttons describing the tools.
pub const BUTTON_FILE: &str = "assets/button/tool_buttons.png";

/// Sidebar that renders and handles input for the tool activation buttons.
pub struct ToolSidebar {
    button_texture: Texture2D,
    bindings_id: usize,
    panel_rect: Rect<u16>,
}

impl ToolSidebar {
    /// Create a new tool sidebar. There should be only one sidebar per program instance.
    pub fn new(rl: &mut RaylibHandle, rlt: &RaylibThread, input: &mut Input) -> Self {
        let button_texture = rl
            .load_texture(rlt, BUTTON_FILE)
            .expect("Could not read file containing tool icons.");

        let panel_rect = Self::panel_rect(rl.get_screen_height() as u16);
        let bindings_id = input.add_local_handler(panel_rect.clone());

        Self {
            button_texture,
            bindings_id,
            panel_rect,
        }
    }

    fn panel_rect(screen_height: u16) -> Rect<u16> {
        /* The width is currently hardcoded as 104, which is
         * 64 (button-size) + 20 left gap + 20 right gap
         */
        Rect::new(0, 0, 104, screen_height)
    }

    /// Update the state of the tool sidebar. Due to raylib limitations, this is not where the tools
    /// are selected for the editor, which happens in draw.
    pub fn update(&mut self, screen_height: u16, input: &mut Input) {
        let new_panel_rect = Self::panel_rect(screen_height);
        if new_panel_rect != self.panel_rect {
            self.panel_rect = new_panel_rect;
            input.set_binding_rect(self.bindings_id, self.panel_rect);
        }
    }

    /// Draw the tool buttons and encasing panel. Because of the way raylib works, this also handles
    /// clicking on tool buttons, which may be changed in the future, should a different gui be
    /// chosen.
    pub fn draw(&self, rld: &mut impl RaylibDrawGui, editor: &mut Editor) {
        rld.gui_panel(Rect::new(
            self.panel_rect.x as f32,
            self.panel_rect.y as f32,
            self.panel_rect.w as f32,
            self.panel_rect.h as f32,
        ));

        // TODO: Update to new input system. Create buttons that integrate.
        let mut active = editor.active();
        for i in 0..ToolType::NumTools as usize {
            let is_current_active = active as usize == i;
            if rld.gui_image_button_ex(
                Rect::new(20., i as f32 * 100. + 20., 64., 64.),
                None,
                &self.button_texture,
                Rect::new(
                    is_current_active as u8 as f32 * 64.,
                    i as f32 * 64.,
                    64.,
                    64.,
                ),
            ) {
                active = unsafe { mem::transmute(i as u8) };
            }
        }

        editor.set_active(active);
    }
}