Skip to main content

rustapi/editor_tools/
tile_picker.rs

1use crate::editor::{PALETTE, RUSTERIX, UNDOMANAGER};
2use crate::prelude::*;
3
4pub struct TilePickerTool {
5    id: TheId,
6}
7
8impl EditorTool for TilePickerTool {
9    fn new() -> Self
10    where
11        Self: Sized,
12    {
13        Self {
14            id: TheId::named_with_id("Tile Picker Tool", Uuid::new_v4()),
15        }
16    }
17
18    fn id(&self) -> TheId {
19        self.id.clone()
20    }
21
22    fn info(&self) -> String {
23        "Picker Tool (P). Click to sample a pixel color, then select it in the palette or add it if missing.".to_string()
24    }
25
26    fn icon_name(&self) -> String {
27        "eyedropper-sample".to_string()
28    }
29
30    fn rgba_view_mode(&self) -> Option<TheRGBAViewMode> {
31        Some(TheRGBAViewMode::TileEditor)
32    }
33
34    fn accel(&self) -> Option<char> {
35        Some('P')
36    }
37
38    fn handle_event(
39        &mut self,
40        event: &TheEvent,
41        ui: &mut TheUI,
42        ctx: &mut TheContext,
43        project: &mut Project,
44        server_ctx: &mut ServerContext,
45    ) -> bool {
46        if let TheEvent::TileEditorClicked(id, coord) = event
47            && id.name == "Tile Editor Dock RGBA Layout View"
48        {
49            return self.pick_from(*coord, ui, ctx, project, server_ctx);
50        }
51        false
52    }
53}
54
55impl TilePickerTool {
56    fn pick_from(
57        &mut self,
58        pos: Vec2<i32>,
59        ui: &mut TheUI,
60        ctx: &mut TheContext,
61        project: &mut Project,
62        server_ctx: &mut ServerContext,
63    ) -> bool {
64        if let Some(editor) = ui.get_rgba_layout("Tile Editor Dock RGBA Layout")
65            && let Some(rgba_view) = editor.rgba_view_mut().as_rgba_view()
66            && rgba_view.has_paste_preview()
67        {
68            return false;
69        }
70
71        let editing_ctx = server_ctx.editing_ctx;
72        let Some(texture) = project.get_editing_texture(&editing_ctx) else {
73            return false;
74        };
75
76        let width = texture.width as i32;
77        let height = texture.height as i32;
78        if pos.x < 0 || pos.y < 0 || pos.x >= width || pos.y >= height {
79            return false;
80        }
81
82        let sampled = texture.get_pixel(pos.x as u32, pos.y as u32);
83        let sampled_color = TheColor::from(sampled);
84
85        let prev_palette = project.palette.clone();
86
87        let mut selected_index = project
88            .palette
89            .colors
90            .iter()
91            .position(|entry| entry.as_ref() == Some(&sampled_color));
92
93        if selected_index.is_none() {
94            project.palette.add_unique_color(sampled_color.clone());
95            selected_index = project
96                .palette
97                .colors
98                .iter()
99                .position(|entry| entry.as_ref() == Some(&sampled_color));
100        }
101
102        if let Some(index) = selected_index {
103            project.palette.current_index = index as u16;
104        }
105
106        if project.palette != prev_palette {
107            let undo = ProjectUndoAtom::PaletteEdit(prev_palette, project.palette.clone());
108            UNDOMANAGER.write().unwrap().add_undo(undo, ctx);
109        }
110
111        apply_palette(ui, ctx, server_ctx, project);
112
113        if let Some(palette_picker) = ui.get_palette_picker("Palette Picker") {
114            palette_picker.set_palette(project.palette.clone());
115            palette_picker.set_index(project.palette.current_index as usize);
116        }
117        if let Some(widget) = ui.get_widget("Palette Color Picker") {
118            widget.set_value(TheValue::ColorObject(sampled_color.clone()));
119        }
120        if let Some(widget) = ui.get_widget("Palette Hex Edit") {
121            widget.set_value(TheValue::Text(sampled_color.to_hex()));
122        }
123
124        *PALETTE.write().unwrap() = project.palette.clone();
125        RUSTERIX.write().unwrap().assets.palette = project.palette.clone();
126
127        true
128    }
129}