1use std::time::Duration;
2
3use crate::theme::Style;
4use blockworx_doc::block_model::Asset;
5use blockworx_doc::id::BlockId;
6use blockworx_paint::{Canvas, Cursor, Event, Interaction};
7use std::sync::mpsc::{Receiver, TryRecvError};
8
9use crate::{
10 shape::ShapeId,
11 tools::{
12 names::ToolName,
13 new_image::spawn_image_dialog,
14 resize_block::ResizeBlock,
15 tool::{Action, ToolTrait},
16 },
17 widget::drawing::Drawing,
18};
19
20pub enum IconTool {
27 Idle,
29 Armed(BlockId),
32 Pending {
34 rx: Receiver<Option<Asset>>,
35 block: BlockId,
36 },
37}
38
39impl ToolTrait for IconTool {
40 fn name(&self) -> ToolName {
41 ToolName::Icon
42 }
43
44 fn widget<C: Canvas>(
45 &mut self,
46 data: &mut Drawing,
47 interaction: &Interaction,
48 painter: &mut Style<'_, C>,
49 ) -> Option<Action> {
50 crate::widget::display::widget(data, interaction, painter);
51 match self {
52 IconTool::Idle => {
53 painter.set_cursor(Cursor::PointingHand);
54 if let Some(Event::Clicked { pos }) = interaction.event
55 && let Some(ShapeId::Rect(rid)) = data.shape_at_pos(pos)
56 {
57 *self = IconTool::Pending {
58 rx: spawn_image_dialog(painter.waker()),
59 block: rid,
60 };
61 }
62 }
63 IconTool::Armed(block) => {
64 let block = *block;
65 *self = IconTool::Pending {
66 rx: spawn_image_dialog(painter.waker()),
67 block,
68 };
69 }
70 IconTool::Pending { rx, block } => {
71 let block = *block;
72 match rx.try_recv() {
73 Ok(picked) => {
74 let shape = match picked.as_ref().filter(|asset| {
79 crate::edit::lower::asset_within_limit(asset, "the picked icon")
80 }) {
81 Some(asset) => {
82 data.set_icon(block, asset);
83 ShapeId::Icon(block)
84 }
85 None => ShapeId::Rect(block),
86 };
87 *self = IconTool::Idle;
88 return Some(Action::SwitchTool(ResizeBlock::Selected { shape }.into()));
89 }
90 Err(TryRecvError::Empty) => {
91 painter.request_repaint_after(Duration::from_millis(100));
92 }
93 Err(TryRecvError::Disconnected) => *self = IconTool::Idle,
94 }
95 }
96 }
97 None
98 }
99}