ferroui_xaml_interactions_custom/writeable_bitmap/
writeable_bitmap_behavior.rs1use crate::{IWriteableBitmapRenderer, WriteableBitmapRef};
4use ferroui_base::media::imaging::WriteableBitmap;
5use ferroui_base::platform::{AlphaFormat, PixelFormat};
6use ferroui_base::{
7 ferro_class, ferro_class_info, ferro_properties, instantiate, DirectProperty, FerroObjectImpl, FerroProperty,
8 PixelSize, Ref, StaticType, StyledElementImpl, StyledProperty, Vector,
9};
10use ferroui_controls::Image;
11use ferroui_xaml_interactivity::{StyledElementBehaviorImpl, StyledElementBehaviorOfT};
12use std::cell::RefCell;
13use std::rc::Rc;
14
15#[repr(C)]
17pub struct WriteableBitmapBehavior {
18 base: StyledElementBehaviorOfT,
19 bitmap: RefCell<Option<WriteableBitmapRef>>,
20}
21
22ferro_class!(WriteableBitmapBehavior: StyledElementBehaviorOfT);
23ferro_class_info!(WriteableBitmapBehavior { new: WriteableBitmapBehavior::new });
24ferroui_base::ferro_impl_classes!(WriteableBitmapBehavior: FerroObjectImpl, StyledElementImpl);
25
26ferro_properties! {
27 impl WriteableBitmapBehavior {
28 pub fn pixel_width_property() -> StyledProperty<i32> {
30 FerroProperty::register::<WriteableBitmapBehavior, _>("PixelWidth", 256)
31 }
32
33 pub fn pixel_height_property() -> StyledProperty<i32> {
35 FerroProperty::register::<WriteableBitmapBehavior, _>("PixelHeight", 256)
36 }
37
38 pub fn renderer_property() -> StyledProperty<Option<Rc<dyn IWriteableBitmapRenderer>>> {
40 FerroProperty::register::<WriteableBitmapBehavior, _>("Renderer", None)
41 }
42
43 pub fn bitmap_property() -> DirectProperty<WriteableBitmapBehavior, Option<WriteableBitmapRef>> {
45 FerroProperty::register_direct::<WriteableBitmapBehavior, _>("Bitmap", |behavior| behavior.bitmap(), None, None)
46 }
47 }
48}
49
50ferroui_base::ferro_overrides! {
51 impl StyledElementBehaviorImpl for WriteableBitmapBehavior {
52 fn on_attached_to_visual_tree(this: &Self) {
53 let bitmap = WriteableBitmapRef::new(WriteableBitmap::new(
54 PixelSize::new(this.pixel_width(), this.pixel_height()),
55 Vector::new(96.0, 96.0),
56 Some(PixelFormat::BGRA8888),
57 Some(AlphaFormat::Unpremul),
58 ));
59 this.set_bitmap(Some(bitmap.clone()));
60
61 if let Some(associated_object) = this.associated_object_as::<Image>() {
62 associated_object.set_source(Some(bitmap.as_image()));
63 }
64
65 if let Some(renderer) = this.renderer() {
66 renderer.render(&bitmap);
67 }
68 }
69
70 fn on_detached_from_visual_tree(this: &Self) {
71 if let Some(associated_object) = this.associated_object_as::<Image>() {
72 associated_object.set_source(None);
73 }
74
75 if let Some(bitmap) = this.bitmap() {
76 bitmap.dispose();
77 }
78 this.set_bitmap(None);
79 }
80 }
81}
82
83impl WriteableBitmapBehavior {
84 pub fn construct() -> Self {
86 Self { base: StyledElementBehaviorOfT::construct(<Image as StaticType>::TYPE), bitmap: RefCell::new(None) }
87 }
88
89 pub fn new() -> Ref<Self> {
91 instantiate(Self::construct())
92 }
93
94 pub fn pixel_width(&self) -> i32 {
96 self.get_value(Self::pixel_width_property())
97 }
98
99 pub fn set_pixel_width(&self, value: i32) {
100 self.set_value(Self::pixel_width_property(), value)
101 }
102
103 pub fn pixel_height(&self) -> i32 {
105 self.get_value(Self::pixel_height_property())
106 }
107
108 pub fn set_pixel_height(&self, value: i32) {
109 self.set_value(Self::pixel_height_property(), value)
110 }
111
112 pub fn renderer(&self) -> Option<Rc<dyn IWriteableBitmapRenderer>> {
115 self.get_value(Self::renderer_property())
116 }
117
118 pub fn set_renderer(&self, value: Option<Rc<dyn IWriteableBitmapRenderer>>) {
119 self.set_value(Self::renderer_property(), value)
120 }
121
122 pub fn bitmap(&self) -> Option<WriteableBitmapRef> {
124 self.bitmap.borrow().clone()
125 }
126
127 fn set_bitmap(&self, value: Option<WriteableBitmapRef>) {
128 self.set_and_raise(Self::bitmap_property(), &self.bitmap, value);
129 }
130
131 pub fn render(&self) {
133 let (Some(bitmap), Some(renderer)) = (self.bitmap(), self.renderer()) else {
134 return;
135 };
136
137 renderer.render(&bitmap);
138 if let Some(associated_object) = self.associated_object_as::<Image>() {
139 associated_object.invalidate_visual();
140 }
141 }
142}