veloren_voxygen/ui/ice/renderer/widget/
scrollable.rs1use super::super::{super::Rotation, IcedRenderer, Primitive, style};
2use common::util::srgba_to_linear;
3use iced::{Rectangle, mouse, scrollable};
4use style::scrollable::{Scroller, Track};
5
6const SCROLLBAR_MIN_HEIGHT: u16 = 6;
7
8impl scrollable::Renderer for IcedRenderer {
9 type Style = style::scrollable::Style;
10
11 fn scrollbar(
15 &self,
16 bounds: Rectangle,
17 content_bounds: Rectangle,
18 offset: u32,
19 scrollbar_width: u16,
20 scrollbar_margin: u16,
21 scroller_width: u16,
22 ) -> Option<scrollable::Scrollbar> {
23 if content_bounds.height > bounds.height {
24 let outer_width = (scrollbar_width.max(scroller_width) + 2 * scrollbar_margin) as f32;
26 let outer_bounds = Rectangle {
27 x: bounds.x + bounds.width - outer_width,
28 width: outer_width,
29 ..bounds
30 };
31
32 let scrollbar_bounds = Rectangle {
34 x: bounds.x + bounds.width - outer_width / 2.0 - (scrollbar_width / 2) as f32,
35 width: scrollbar_width as f32,
36 ..bounds
37 };
38
39 let visible_fraction = bounds.height / content_bounds.height;
41 let scroller_height =
42 (bounds.height * visible_fraction).max((2 * SCROLLBAR_MIN_HEIGHT) as f32);
43 let y_offset = offset as f32 * visible_fraction;
44
45 let scroller_bounds = Rectangle {
46 x: bounds.x + bounds.width - outer_width / 2.0 - (scrollbar_width / 2) as f32,
47 y: scrollbar_bounds.y + y_offset,
48 width: scroller_width as f32,
49 height: scroller_height,
50 };
51 Some(scrollable::Scrollbar {
52 outer_bounds,
53 bounds: scrollbar_bounds,
54 margin: scrollbar_margin,
55 scroller: scrollable::Scroller {
56 bounds: scroller_bounds,
57 },
58 })
59 } else {
60 None
61 }
62 }
63
64 fn draw(
65 &mut self,
66 state: &scrollable::State,
67 bounds: Rectangle,
68 _content_bounds: Rectangle,
69 is_mouse_over: bool,
70 is_mouse_over_scrollbar: bool,
71 scrollbar: Option<scrollable::Scrollbar>,
72 offset: u32,
73 style_sheet: &Self::Style,
74 (content, mouse_interaction): Self::Output,
75 ) -> Self::Output {
76 (
77 if let Some(scrollbar) = scrollbar {
78 let mut primitives = Vec::with_capacity(5);
79
80 primitives.push(Primitive::Clip {
82 bounds,
83 offset: (0, offset).into(),
84 content: Box::new(content),
85 });
86
87 let style = style_sheet;
88 let is_scrollbar_visible = style.track.is_some();
98
99 if is_mouse_over || state.is_scroller_grabbed() || is_scrollbar_visible {
100 let bounds = scrollbar.scroller.bounds;
101
102 match style.scroller {
103 Scroller::Color(color) => primitives.push(Primitive::Rectangle {
104 bounds,
105 linear_color: srgba_to_linear(color.map(|e| e as f32 / 255.0)),
106 }),
107 Scroller::Image { ends, mid, color } => {
108 let (img_w, img_h) = self.image_dims(ends);
110 let end_height = bounds.width * img_h as f32 / img_w as f32;
111
112 let (end_height, middle_height) =
115 if end_height * 2.0 + 1.0 <= bounds.height {
116 (end_height, bounds.height - end_height * 2.0)
117 } else {
118 let remaining_height = bounds.height - 1.0;
120 (remaining_height / 2.0, 1.0)
121 };
122
123 primitives.push(Primitive::Image {
125 handle: (ends, Rotation::None),
126 bounds: Rectangle {
127 height: end_height,
128 ..bounds
129 },
130 color,
131 source_rect: None,
132 });
133 primitives.push(Primitive::Image {
135 handle: (mid, Rotation::None),
136 bounds: Rectangle {
137 y: bounds.y + end_height,
138 height: middle_height,
139 ..bounds
140 },
141 color,
142 source_rect: None,
143 });
144 primitives.push(Primitive::Image {
146 handle: (ends, Rotation::Cw180),
147 bounds: Rectangle {
148 y: bounds.y + end_height + middle_height,
149 height: end_height,
150 ..bounds
151 },
152 color,
153 source_rect: None,
154 });
155 },
156 }
157 }
158
159 if let Some(track) = style.track {
160 primitives.push(match track {
161 Track::Color(color) => Primitive::Rectangle {
162 bounds: scrollbar.bounds,
163 linear_color: srgba_to_linear(color.map(|e| e as f32 / 255.0)),
164 },
165 Track::Image(handle, color) => Primitive::Image {
166 handle: (handle, Rotation::None),
167 bounds: scrollbar.bounds,
168 color,
169 source_rect: None,
170 },
171 });
172 }
173
174 Primitive::Group { primitives }
175 } else {
176 content
177 },
178 if is_mouse_over_scrollbar || state.is_scroller_grabbed() {
179 mouse::Interaction::Idle
180 } else {
181 mouse_interaction
182 },
183 )
184 }
185}