makepad_widgets/
rotated_image.rs1use crate::{image_cache::*, makepad_draw::*, widget::*};
2use crate::makepad_derive_widget::*;
3
4live_design! {
5 link widgets
6 use link::shaders::*;
7
8 pub RotatedImageBase = {{RotatedImage}} {}
9 pub RotatedImage = <RotatedImageBase> {
10 width: Fit
11 height: Fit
12
13 draw_bg: {
14 texture image: texture2d
15
16 instance rotation: 0.0
17 instance opacity: 1.0
18 instance scale: 1.0
19
20 fn rotation_vertex_expansion(rotation: float, w: float, h: float) -> vec2 {
21 let horizontal_expansion = (abs(cos(rotation)) * w + abs(sin(rotation)) * h) / w - 1.0;
22 let vertical_expansion = (abs(sin(rotation)) * w + abs(cos(rotation)) * h) / h - 1.0;
23
24 return vec2(horizontal_expansion, vertical_expansion);
25 }
26
27 fn rotate_2d_from_center(coord: vec2, a: float, size: vec2) -> vec2 {
28 let cos_a = cos(-a);
29 let sin_a = sin(-a);
30
31 let centered_coord = coord - vec2(0.5, 0.5);
32
33 let denorm_coord = vec2(centered_coord.x, centered_coord.y * size.y / size.x);
35 let demorm_rotated = vec2(denorm_coord.x * cos_a - denorm_coord.y * sin_a, denorm_coord.x * sin_a + denorm_coord.y * cos_a);
36
37 let rotated = vec2(demorm_rotated.x, demorm_rotated.y * size.x / size.y);
39
40 return rotated + vec2(0.5, 0.5);
41 }
42
43 fn get_color(self) -> vec4 {
44 let rot_padding = rotation_vertex_expansion(self.rotation, self.rect_size.x, self.rect_size.y) / 2.0;
45
46 let current_pos = self.pos.xy - rot_padding;
48 let original_pos = rotate_2d_from_center(current_pos, self.rotation, self.rect_size);
49
50 let scaled_pos = original_pos / self.scale;
52
53 let color = sample2d(self.image, scaled_pos).xyzw;
55
56 let faded_color = color * vec4(1.0, 1.0, 1.0, self.opacity);
57 return faded_color;
58 }
59
60 fn pixel(self) -> vec4 {
61 let rot_expansion = rotation_vertex_expansion(self.rotation, self.rect_size.x, self.rect_size.y);
62
63 let sdf = Sdf2d::viewport(self.pos * self.rect_size);
70
71 let translation_offset = vec2(self.rect_size.x * rot_expansion.x / 2.0, self.rect_size.y * self.scale * rot_expansion.y / 2.0);
72 sdf.translate(translation_offset.x, translation_offset.y);
73
74 let center = self.rect_size * 0.5;
75 sdf.rotate(self.rotation, center.x, center.y);
76
77 let scaled_size = self.rect_size * self.scale;
78 sdf.box(0.0, 0.0, scaled_size.x, scaled_size.y, 1);
79
80 sdf.fill_premul(Pal::premul(self.get_color()));
81 return sdf.result
82 }
83
84 fn vertex(self) -> vec4 {
85 let rot_expansion = rotation_vertex_expansion(self.rotation, self.rect_size.x, self.rect_size.y);
86 let adjusted_pos = vec2(
87 self.rect_pos.x - self.rect_size.x * rot_expansion.x / 2.0,
88 self.rect_pos.y - self.rect_size.y * rot_expansion.y / 2.0
89 );
90
91 let expanded_size = vec2(self.rect_size.x * (self.scale + rot_expansion.x), self.rect_size.y * (self.scale + rot_expansion.y));
92 let clipped: vec2 = clamp(
93 self.geom_pos * expanded_size + adjusted_pos,
94 self.draw_clip.xy,
95 self.draw_clip.zw
96 );
97
98 self.pos = (clipped - adjusted_pos) / self.rect_size;
99 return self.camera_projection * (self.camera_view * (
100 self.view_transform * vec4(clipped.x, clipped.y, self.draw_depth + self.draw_zbias, 1.)
101 ));
102 }
103
104 shape: Solid,
105 fill: Image
106 }
107 }
108
109}
110
111#[derive(Live, Widget)]
112pub struct RotatedImage {
113 #[walk] walk: Walk,
114 #[layout] layout: Layout,
115 #[redraw] #[live] draw_bg: DrawColor,
116
117 #[live] source: LiveDependency,
118 #[rust(Texture::new(cx))] texture: Option<Texture>,
119 #[live] scale: f64,
120}
121
122impl ImageCacheImpl for RotatedImage {
123 fn get_texture(&self, _id:usize) -> &Option<Texture> {
124 &self.texture
125 }
126
127 fn set_texture(&mut self, texture: Option<Texture>, _id:usize) {
128 self.texture = texture;
129 }
130}
131
132impl LiveHook for RotatedImage {
133
134 fn after_apply(&mut self, cx: &mut Cx, _applyl: &mut Apply, _index: usize, _nodes: &[LiveNode]) {
135 self.lazy_create_image_cache(cx);
136 let source = self.source.clone();
137 if source.as_str().len()>0{
138 let _ = self.load_image_dep_by_path(cx, source.as_str(), 0);
139 }
140 }
141}
142
143impl Widget for RotatedImage {
144 fn draw_walk(&mut self, cx: &mut Cx2d, _scope:&mut Scope, walk: Walk) -> DrawStep {
145 self.draw_walk_rotated_image(cx, walk)
146 }
147}
148
149impl RotatedImage {
150 pub fn draw_walk_rotated_image(&mut self, cx: &mut Cx2d, walk: Walk) -> DrawStep {
151 if let Some(image_texture) = &self.texture {
152 self.draw_bg.draw_vars.set_texture(0, image_texture);
153 }
154 self.draw_bg.draw_walk(cx, walk);
155
156 DrawStep::done()
157 }
158}