rustapi/editor_tools/
tile_picker.rs1use 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}