1#![allow(unsafe_code)]
6#![warn(missing_docs)]
7extern crate alloc;
13use crate::Coord;
14use crate::SharedString;
15use crate::api::PlatformError;
16use crate::lengths::LogicalLength;
17use alloc::boxed::Box;
18
19pub use euclid;
20pub type Rect = euclid::default::Rect<Coord>;
22pub type IntRect = euclid::default::Rect<i32>;
24pub type Point = euclid::default::Point2D<Coord>;
26pub type Size = euclid::default::Size2D<Coord>;
28pub type IntSize = euclid::default::Size2D<u32>;
30pub type Transform = euclid::default::Transform2D<Coord>;
32
33pub(crate) mod color;
34pub use color::*;
35
36#[cfg(feature = "shared-fontique")]
37use i_slint_common::sharedfontique::{self, fontique};
38#[cfg(feature = "path")]
39mod path;
40#[cfg(feature = "path")]
41pub use path::*;
42
43mod brush;
44pub use brush::*;
45
46pub(crate) mod image;
47pub use self::image::*;
48
49pub(crate) mod bitmapfont;
50pub use self::bitmapfont::*;
51
52pub mod rendering_metrics_collector;
53
54#[cfg(feature = "box-shadow-cache")]
55pub mod boxshadowcache;
56
57pub mod border_radius;
58pub use border_radius::*;
59
60#[cfg(feature = "wgpu-29")]
61pub mod wgpu_29;
62#[cfg(feature = "wgpu-30")]
63pub mod wgpu_30;
64
65pub fn adjust_rect_and_border_for_inner_drawing<U>(
70 rect: &mut euclid::Rect<f32, U>,
71 border_width: &mut euclid::Length<f32, U>,
72) {
73 use crate::lengths::RectLengths;
74 *border_width = border_width.min(rect.width_length() / 2.);
76 rect.origin += euclid::Size2D::from_lengths(*border_width / 2., *border_width / 2.);
78 rect.size -= euclid::Size2D::from_lengths(*border_width, *border_width);
79}
80
81pub struct CachedGraphicsData<T> {
86 pub data: T,
88 pub dependency_tracker: Option<core::pin::Pin<Box<crate::properties::PropertyTracker>>>,
91}
92
93impl<T> CachedGraphicsData<T> {
94 pub fn new(update_fn: impl FnOnce() -> T) -> Self {
97 let dependency_tracker = Box::pin(crate::properties::PropertyTracker::default());
98 let data = dependency_tracker.as_ref().evaluate(update_fn);
99 Self { data, dependency_tracker: Some(dependency_tracker) }
100 }
101}
102
103#[derive(Debug, Clone, PartialEq, Default)]
107pub struct FontRequest {
108 pub family: Option<SharedString>,
111 pub weight: Option<i32>,
113 pub pixel_size: Option<LogicalLength>,
115 pub letter_spacing: Option<LogicalLength>,
118 pub line_height_factor: Option<f32>,
121 pub italic: bool,
123}
124
125impl FontRequest {
126 pub fn line_height_for_natural_height(&self, natural_line_height: f32) -> Option<f32> {
129 self.line_height_factor.map(|factor| natural_line_height * factor)
130 }
131}
132
133#[cfg(feature = "shared-fontique")]
134impl FontRequest {
135 pub fn query_fontique(
137 &self,
138 collection: &mut fontique::Collection,
139 source_cache: &mut fontique::SourceCache,
140 ) -> Option<fontique::QueryFont> {
141 let mut query = collection.query(source_cache);
142 query.set_families(
143 self.family
144 .as_ref()
145 .map(|family| fontique::QueryFamily::from(family.as_str()))
146 .into_iter()
147 .chain(
148 sharedfontique::FALLBACK_FAMILIES
149 .into_iter()
150 .map(fontique::QueryFamily::Generic),
151 ),
152 );
153
154 query.set_attributes(fontique::Attributes {
155 weight: self
156 .weight
157 .as_ref()
158 .map(|&weight| fontique::FontWeight::new(weight as f32))
159 .unwrap_or_default(),
160 style: if self.italic {
161 fontique::FontStyle::Italic
162 } else {
163 fontique::FontStyle::Normal
164 },
165 ..Default::default()
166 });
167
168 let mut font = None;
169
170 query.matches_with(|queried_font| {
171 font = Some(queried_font.clone());
172 fontique::QueryStatus::Stop
173 });
174
175 font
176 }
177}
178
179#[derive(Debug, Clone, PartialEq)]
182pub enum RequestedOpenGLVersion {
183 OpenGL(Option<(u8, u8)>),
185 OpenGLES(Option<(u8, u8)>),
187}
188
189#[derive(Debug, Clone)]
192#[allow(clippy::large_enum_variant)]
193pub enum RequestedGraphicsAPI {
194 OpenGL(RequestedOpenGLVersion),
196 Metal,
198 Vulkan,
200 Direct3D,
202 #[cfg(feature = "unstable-wgpu-29")]
203 WGPU29(wgpu_29::api::WGPUConfiguration),
205 #[cfg(feature = "unstable-wgpu-30")]
206 WGPU30(wgpu_30::api::WGPUConfiguration),
208}
209
210impl TryFrom<&RequestedGraphicsAPI> for RequestedOpenGLVersion {
211 type Error = PlatformError;
212
213 fn try_from(requested_graphics_api: &RequestedGraphicsAPI) -> Result<Self, Self::Error> {
214 match requested_graphics_api {
215 RequestedGraphicsAPI::OpenGL(requested_open_glversion) => {
216 Ok(requested_open_glversion.clone())
217 }
218 RequestedGraphicsAPI::Metal => {
219 Err("Metal rendering is not supported with an OpenGL renderer".into())
220 }
221 RequestedGraphicsAPI::Vulkan => {
222 Err("Vulkan rendering is not supported with an OpenGL renderer".into())
223 }
224 RequestedGraphicsAPI::Direct3D => {
225 Err("Direct3D rendering is not supported with an OpenGL renderer".into())
226 }
227 #[cfg(feature = "unstable-wgpu-29")]
228 RequestedGraphicsAPI::WGPU29(..) => {
229 Err("WGPU 29.x rendering is not supported with an OpenGL renderer".into())
230 }
231 #[cfg(feature = "unstable-wgpu-30")]
232 RequestedGraphicsAPI::WGPU30(..) => {
233 Err("WGPU 30.x rendering is not supported with an OpenGL renderer".into())
234 }
235 }
236 }
237}
238
239impl From<RequestedOpenGLVersion> for RequestedGraphicsAPI {
240 fn from(version: RequestedOpenGLVersion) -> Self {
241 Self::OpenGL(version)
242 }
243}
244
245#[cfg(feature = "unstable-wgpu-29")]
248pub fn create_graphics_api_wgpu_29(
249 instance: wgpu_29::wgpu::Instance,
250 device: wgpu_29::wgpu::Device,
251 queue: wgpu_29::wgpu::Queue,
252) -> crate::api::GraphicsAPI<'static> {
253 crate::api::GraphicsAPI::WGPU29 { instance, device, queue }
254}
255
256#[cfg(feature = "unstable-wgpu-30")]
259pub fn create_graphics_api_wgpu_30(
260 instance: wgpu_30::wgpu::Instance,
261 device: wgpu_30::wgpu::Device,
262 queue: wgpu_30::wgpu::Queue,
263) -> crate::api::GraphicsAPI<'static> {
264 crate::api::GraphicsAPI::WGPU30 { instance, device, queue }
265}
266
267#[cfg(feature = "ffi")]
269pub mod ffi {
270 #![allow(unsafe_code)]
271
272 #[cfg(cbindgen)]
274 #[repr(C)]
275 struct Rect {
276 x: f32,
277 y: f32,
278 width: f32,
279 height: f32,
280 }
281
282 #[cfg(cbindgen)]
284 #[repr(C)]
285 struct IntRect {
286 x: i32,
287 y: i32,
288 width: i32,
289 height: i32,
290 }
291
292 #[cfg(cbindgen)]
294 #[repr(C)]
295 struct Point {
296 x: f32,
297 y: f32,
298 }
299
300 #[cfg(cbindgen)]
302 #[repr(C)]
303 struct Box2D<T, U> {
304 min: euclid::Point2D<T>,
305 max: euclid::Point2D<T>,
306 _unit: std::marker::PhantomData<U>,
307 }
308
309 #[cfg(feature = "std")]
310 pub use super::path::ffi::*;
311
312 pub fn physical_size_from_api(
316 size: crate::api::PhysicalSize,
317 ) -> crate::graphics::euclid::default::Size2D<u32> {
318 size.to_euclid()
319 }
320
321 pub fn physical_position_from_api(
325 position: crate::api::PhysicalPosition,
326 ) -> crate::graphics::euclid::default::Point2D<i32> {
327 position.to_euclid()
328 }
329
330 pub fn physical_position_to_api(
333 position: crate::graphics::euclid::default::Point2D<i32>,
334 ) -> crate::api::PhysicalPosition {
335 crate::api::PhysicalPosition::from_euclid(position)
336 }
337}