flo/standard_tools/
eraser.rs

1use super::ink::*;
2use super::super::menu::*;
3use super::super::tools::*;
4use super::super::model::*;
5
6use ui::*;
7use binding::*;
8use animation::*;
9
10use futures::*;
11use std::sync::*;
12
13///
14/// TODO: really, we should make the eraser subtract from existing paths rather
15/// than drawing over the top (this means when moving things around, any erasings
16/// stick around: also when something is entire erased it should be removed from
17/// the drawing).
18/// 
19/// We need to add path arithmetic at least before this is possible to do,
20/// however.
21/// 
22
23///
24/// The Eraser tool (Erasers control points of existing objects)
25/// 
26pub struct Eraser { 
27    ink: Ink
28}
29
30impl Eraser {
31    ///
32    /// Creates a new instance of the Eraser tool
33    /// 
34    pub fn new() -> Eraser {
35        Eraser {
36            ink: Ink::new()
37        }
38    }
39}
40
41impl<Anim: Animation+'static> Tool<Anim> for Eraser {
42    type ToolData   = InkData;
43    type Model      = InkModel;
44
45    fn tool_name(&self) -> String { "Eraser".to_string() }
46
47    fn image_name(&self) -> String { "eraser".to_string() }
48
49    fn create_model(&self, _flo_model: Arc<FloModel<Anim>>) -> InkModel {
50        let mut model = InkModel::new();
51
52        model.size.set(10.0);
53
54        model
55    }
56
57    fn create_menu_controller(&self, _flo_model: Arc<FloModel<Anim>>, tool_model: &InkModel) -> Option<Arc<Controller>> {
58        Some(Arc::new(EraserMenuController::new(&tool_model.size, &tool_model.opacity)))
59    }
60
61    fn actions_for_model(&self, flo_model: Arc<FloModel<Anim>>, tool_model: &InkModel) -> Box<Stream<Item=ToolAction<InkData>, Error=()>+Send> {
62        // Fetch the brush properties
63        let brush_properties    = tool_model.brush_properties.clone();
64        let selected_layer      = flo_model.timeline().selected_layer.clone();
65
66        // Create a computed binding that generates the data for the brush
67        let ink_data            = computed(move || {
68            InkData {
69                brush:              BrushDefinition::Ink(InkDefinition::default()),
70                brush_properties:   brush_properties.get(),
71                selected_layer:     selected_layer.get().unwrap_or(0)
72            }
73        });
74
75        // Turn the computed values into a stream and update the brush whenever the values change
76        Box::new(follow(ink_data).map(|ink_data| ToolAction::Data(ink_data)))
77    }
78
79    fn actions_for_input<'a>(&'a self, data: Option<Arc<InkData>>, input: Box<'a+Iterator<Item=ToolInput<InkData>>>) -> Box<'a+Iterator<Item=ToolAction<InkData>>> {
80        use self::ToolAction::*;
81        use self::BrushPreviewAction::*;
82
83        let ink: &Tool<Anim, ToolData=InkData, Model=InkModel> = &self.ink;
84
85        // As for the ink tool, except that we use the eraser drawing style
86        let actions = ink.actions_for_input(data, input)
87            .map(|action| {
88                match action {
89                    BrushPreview(BrushDefinition(brush, BrushDrawingStyle::Draw)) => BrushPreview(BrushDefinition(brush, BrushDrawingStyle::Erase)),
90                    
91                    other => other
92                }
93            });
94
95        Box::new(actions)
96    }
97}