mirror of
https://github.com/slint-ui/slint.git
synced 2025-11-01 12:24:16 +00:00
Use Property<LogicalLength> instead of Property<Coord>
This removes the special code for the generated property getters and ensures type safety in the run-time library for property value setting. In the Rust generated code we continue to do arithmetic on the scalar values, that means we immediately extract the scalar, do arithmetic and rely on the compiler to only allow compatible units. Danger zone alert: In the interpreter Value::Number can now be converted to LogicalLength as-is.
This commit is contained in:
parent
d505ac4809
commit
c16253d29f
33 changed files with 496 additions and 380 deletions
|
|
@ -205,6 +205,7 @@ fn gen_corelib(
|
|||
"Coord",
|
||||
"LogicalRect",
|
||||
"LogicalPoint",
|
||||
"LogicalLength",
|
||||
]
|
||||
.iter()
|
||||
.chain(public_exported_types.iter())
|
||||
|
|
@ -470,6 +471,7 @@ namespace slint {
|
|||
struct Rect;
|
||||
using LogicalRect = Rect;
|
||||
using LogicalPoint = Point2D<float>;
|
||||
using LogicalLength = float;
|
||||
}
|
||||
}",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@ pub mod re_exports {
|
|||
};
|
||||
pub use i_slint_core::items::*;
|
||||
pub use i_slint_core::layout::*;
|
||||
pub use i_slint_core::lengths::LogicalLength;
|
||||
pub use i_slint_core::model::*;
|
||||
pub use i_slint_core::properties::{set_state_binding, Property, PropertyTracker, StateInfo};
|
||||
pub use i_slint_core::slice::Slice;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ use crate::qt_window::QPainterPtr;
|
|||
use const_field_offset::FieldOffsets;
|
||||
use core::pin::Pin;
|
||||
use cpp::cpp;
|
||||
use i_slint_core::graphics::euclid;
|
||||
use i_slint_core::graphics::Color;
|
||||
use i_slint_core::input::{
|
||||
FocusEvent, InputEventFilterResult, InputEventResult, KeyEvent, KeyEventResult, MouseEvent,
|
||||
|
|
@ -29,7 +28,7 @@ use i_slint_core::input::{
|
|||
use i_slint_core::item_rendering::{CachedRenderingData, ItemRenderer};
|
||||
use i_slint_core::items::{Item, ItemConsts, ItemRc, ItemVTable, RenderingResult, VoidArg};
|
||||
use i_slint_core::layout::{LayoutInfo, Orientation};
|
||||
use i_slint_core::lengths::LogicalRect;
|
||||
use i_slint_core::lengths::{LogicalLength, LogicalPoint, LogicalRect, LogicalSize};
|
||||
#[cfg(feature = "rtti")]
|
||||
use i_slint_core::rtti::*;
|
||||
use i_slint_core::window::{WindowAdapter, WindowAdapterRc, WindowInner};
|
||||
|
|
@ -45,8 +44,8 @@ type ItemRendererRef<'a> = &'a mut dyn ItemRenderer;
|
|||
/// and return Default::default in case the size is too small
|
||||
macro_rules! get_size {
|
||||
($self:ident) => {{
|
||||
let width = $self.width();
|
||||
let height = $self.height();
|
||||
let width = $self.width().get();
|
||||
let height = $self.height().get();
|
||||
if width < 1. || height < 1. {
|
||||
return Default::default();
|
||||
};
|
||||
|
|
@ -85,8 +84,8 @@ macro_rules! fn_render {
|
|||
backend.draw_cached_pixmap(
|
||||
item_rc,
|
||||
&|callback| {
|
||||
let width = self.width() * $dpr;
|
||||
let height = self.height() * $dpr;
|
||||
let width = self.width().get() * $dpr;
|
||||
let height = self.height().get() * $dpr;
|
||||
if width < 1. || height < 1. {
|
||||
return Default::default();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -104,10 +104,10 @@ type ActualStandardButtonKind = Option<StandardButtonKind>;
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct NativeButton {
|
||||
pub x: Property<f32>,
|
||||
pub y: Property<f32>,
|
||||
pub width: Property<f32>,
|
||||
pub height: Property<f32>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub text: Property<SharedString>,
|
||||
pub icon: Property<i_slint_core::graphics::Image>,
|
||||
pub pressed: Property<bool>,
|
||||
|
|
@ -191,7 +191,10 @@ impl Item for NativeButton {
|
|||
fn init(self: Pin<&Self>, _window_adapter: &Rc<dyn WindowAdapter>) {}
|
||||
|
||||
fn geometry(self: Pin<&Self>) -> LogicalRect {
|
||||
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
||||
LogicalRect::new(
|
||||
LogicalPoint::from_lengths(self.x(), self.y()),
|
||||
LogicalSize::from_lengths(self.width(), self.height()),
|
||||
)
|
||||
}
|
||||
|
||||
fn layout_info(
|
||||
|
|
@ -263,7 +266,12 @@ impl Item for NativeButton {
|
|||
MouseEvent::Wheel { .. } => return InputEventResult::EventIgnored,
|
||||
});
|
||||
if let MouseEvent::Released { position, .. } = event {
|
||||
if euclid::rect(0., 0., self.width(), self.height()).contains(position) {
|
||||
if LogicalRect::new(
|
||||
LogicalPoint::default(),
|
||||
LogicalSize::from_lengths(self.width(), self.height()),
|
||||
)
|
||||
.contains(position)
|
||||
{
|
||||
self.activate();
|
||||
}
|
||||
InputEventResult::EventAccepted
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ use super::*;
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct NativeCheckBox {
|
||||
pub x: Property<f32>,
|
||||
pub y: Property<f32>,
|
||||
pub width: Property<f32>,
|
||||
pub height: Property<f32>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub enabled: Property<bool>,
|
||||
pub has_focus: Property<bool>,
|
||||
pub toggled: Callback<VoidArg>,
|
||||
|
|
@ -25,7 +25,10 @@ impl Item for NativeCheckBox {
|
|||
fn init(self: Pin<&Self>, _window_adapter: &Rc<dyn WindowAdapter>) {}
|
||||
|
||||
fn geometry(self: Pin<&Self>) -> LogicalRect {
|
||||
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
||||
LogicalRect::new(
|
||||
LogicalPoint::from_lengths(self.x(), self.y()),
|
||||
LogicalSize::from_lengths(self.width(), self.height()),
|
||||
)
|
||||
}
|
||||
|
||||
fn layout_info(
|
||||
|
|
@ -74,7 +77,12 @@ impl Item for NativeCheckBox {
|
|||
return InputEventResult::EventIgnored;
|
||||
}
|
||||
if let MouseEvent::Released { position, .. } = event {
|
||||
if euclid::rect(0., 0., self.width(), self.height()).contains(position) {
|
||||
if LogicalRect::new(
|
||||
LogicalPoint::default(),
|
||||
LogicalSize::from_lengths(self.width(), self.height()),
|
||||
)
|
||||
.contains(position)
|
||||
{
|
||||
Self::FIELD_OFFSETS.checked.apply_pin(self).set(!self.checked());
|
||||
Self::FIELD_OFFSETS.toggled.apply_pin(self).call(&())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ use super::*;
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct NativeComboBox {
|
||||
pub x: Property<f32>,
|
||||
pub y: Property<f32>,
|
||||
pub width: Property<f32>,
|
||||
pub height: Property<f32>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub enabled: Property<bool>,
|
||||
pub pressed: Property<bool>,
|
||||
pub is_open: Property<bool>,
|
||||
|
|
@ -25,7 +25,10 @@ impl Item for NativeComboBox {
|
|||
fn init(self: Pin<&Self>, _window_adapter: &Rc<dyn WindowAdapter>) {}
|
||||
|
||||
fn geometry(self: Pin<&Self>) -> LogicalRect {
|
||||
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
||||
LogicalRect::new(
|
||||
LogicalPoint::from_lengths(self.x(), self.y()),
|
||||
LogicalSize::from_lengths(self.width(), self.height()),
|
||||
)
|
||||
}
|
||||
|
||||
fn layout_info(
|
||||
|
|
@ -165,10 +168,10 @@ fn slint_get_NativeComboBoxVTable() -> NativeComboBoxVTable for NativeComboBox
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct NativeComboBoxPopup {
|
||||
pub x: Property<f32>,
|
||||
pub y: Property<f32>,
|
||||
pub width: Property<f32>,
|
||||
pub height: Property<f32>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
}
|
||||
|
||||
|
|
@ -176,7 +179,10 @@ impl Item for NativeComboBoxPopup {
|
|||
fn init(self: Pin<&Self>, _window_adapter: &Rc<dyn WindowAdapter>) {}
|
||||
|
||||
fn geometry(self: Pin<&Self>) -> LogicalRect {
|
||||
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
||||
LogicalRect::new(
|
||||
LogicalPoint::from_lengths(self.x(), self.y()),
|
||||
LogicalSize::from_lengths(self.width(), self.height()),
|
||||
)
|
||||
}
|
||||
|
||||
fn layout_info(
|
||||
|
|
|
|||
|
|
@ -9,17 +9,17 @@ use super::*;
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct NativeGroupBox {
|
||||
pub x: Property<f32>,
|
||||
pub y: Property<f32>,
|
||||
pub width: Property<f32>,
|
||||
pub height: Property<f32>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub enabled: Property<bool>,
|
||||
pub title: Property<SharedString>,
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
pub native_padding_left: Property<f32>,
|
||||
pub native_padding_right: Property<f32>,
|
||||
pub native_padding_top: Property<f32>,
|
||||
pub native_padding_bottom: Property<f32>,
|
||||
pub native_padding_left: Property<LogicalLength>,
|
||||
pub native_padding_right: Property<LogicalLength>,
|
||||
pub native_padding_top: Property<LogicalLength>,
|
||||
pub native_padding_bottom: Property<LogicalLength>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
|
@ -108,7 +108,7 @@ impl Item for NativeGroupBox {
|
|||
move || {
|
||||
let margins =
|
||||
GroupBoxData::FIELD_OFFSETS.paddings.apply_pin(shared_data.as_ref()).get();
|
||||
margins.left as _
|
||||
LogicalLength::new(margins.left as _)
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ impl Item for NativeGroupBox {
|
|||
move || {
|
||||
let margins =
|
||||
GroupBoxData::FIELD_OFFSETS.paddings.apply_pin(shared_data.as_ref()).get();
|
||||
margins.right as _
|
||||
LogicalLength::new(margins.right as _)
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ impl Item for NativeGroupBox {
|
|||
move || {
|
||||
let margins =
|
||||
GroupBoxData::FIELD_OFFSETS.paddings.apply_pin(shared_data.as_ref()).get();
|
||||
margins.top as _
|
||||
LogicalLength::new(margins.top as _)
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -134,13 +134,16 @@ impl Item for NativeGroupBox {
|
|||
move || {
|
||||
let margins =
|
||||
GroupBoxData::FIELD_OFFSETS.paddings.apply_pin(shared_data.as_ref()).get();
|
||||
margins.bottom as _
|
||||
LogicalLength::new(margins.bottom as _)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn geometry(self: Pin<&Self>) -> LogicalRect {
|
||||
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
||||
LogicalRect::new(
|
||||
LogicalPoint::from_lengths(self.x(), self.y()),
|
||||
LogicalSize::from_lengths(self.width(), self.height()),
|
||||
)
|
||||
}
|
||||
|
||||
fn layout_info(
|
||||
|
|
|
|||
|
|
@ -10,15 +10,15 @@ use super::*;
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct NativeLineEdit {
|
||||
pub x: Property<f32>,
|
||||
pub y: Property<f32>,
|
||||
pub width: Property<f32>,
|
||||
pub height: Property<f32>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
pub native_padding_left: Property<f32>,
|
||||
pub native_padding_right: Property<f32>,
|
||||
pub native_padding_top: Property<f32>,
|
||||
pub native_padding_bottom: Property<f32>,
|
||||
pub native_padding_left: Property<LogicalLength>,
|
||||
pub native_padding_right: Property<LogicalLength>,
|
||||
pub native_padding_top: Property<LogicalLength>,
|
||||
pub native_padding_bottom: Property<LogicalLength>,
|
||||
pub has_focus: Property<bool>,
|
||||
pub enabled: Property<bool>,
|
||||
pub input_type: Property<InputType>,
|
||||
|
|
@ -53,24 +53,27 @@ impl Item for NativeLineEdit {
|
|||
|
||||
self.native_padding_left.set_binding({
|
||||
let paddings = paddings.clone();
|
||||
move || paddings.as_ref().get().left as _
|
||||
move || LogicalLength::new(paddings.as_ref().get().left as _)
|
||||
});
|
||||
self.native_padding_right.set_binding({
|
||||
let paddings = paddings.clone();
|
||||
move || paddings.as_ref().get().right as _
|
||||
move || LogicalLength::new(paddings.as_ref().get().right as _)
|
||||
});
|
||||
self.native_padding_top.set_binding({
|
||||
let paddings = paddings.clone();
|
||||
move || paddings.as_ref().get().top as _
|
||||
move || LogicalLength::new(paddings.as_ref().get().top as _)
|
||||
});
|
||||
self.native_padding_bottom.set_binding({
|
||||
let paddings = paddings;
|
||||
move || paddings.as_ref().get().bottom as _
|
||||
move || LogicalLength::new(paddings.as_ref().get().bottom as _)
|
||||
});
|
||||
}
|
||||
|
||||
fn geometry(self: Pin<&Self>) -> LogicalRect {
|
||||
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
||||
LogicalRect::new(
|
||||
LogicalPoint::from_lengths(self.x(), self.y()),
|
||||
LogicalSize::from_lengths(self.width(), self.height()),
|
||||
)
|
||||
}
|
||||
|
||||
fn layout_info(
|
||||
|
|
@ -82,7 +85,8 @@ impl Item for NativeLineEdit {
|
|||
min: match orientation {
|
||||
Orientation::Horizontal => self.native_padding_left() + self.native_padding_right(),
|
||||
Orientation::Vertical => self.native_padding_top() + self.native_padding_bottom(),
|
||||
},
|
||||
}
|
||||
.get(),
|
||||
stretch: if orientation == Orientation::Horizontal { 1. } else { 0. },
|
||||
..LayoutInfo::default()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ use super::*;
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct NativeStandardListViewItem {
|
||||
pub x: Property<f32>,
|
||||
pub y: Property<f32>,
|
||||
pub width: Property<f32>,
|
||||
pub height: Property<f32>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub item: Property<i_slint_core::model::StandardListViewItem>,
|
||||
pub index: Property<i32>,
|
||||
pub is_selected: Property<bool>,
|
||||
|
|
@ -24,7 +24,10 @@ impl Item for NativeStandardListViewItem {
|
|||
fn init(self: Pin<&Self>, _window_adapter: &Rc<dyn WindowAdapter>) {}
|
||||
|
||||
fn geometry(self: Pin<&Self>) -> LogicalRect {
|
||||
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
||||
LogicalRect::new(
|
||||
LogicalPoint::from_lengths(self.x(), self.y()),
|
||||
LogicalSize::from_lengths(self.width(), self.height()),
|
||||
)
|
||||
}
|
||||
|
||||
fn layout_info(
|
||||
|
|
|
|||
|
|
@ -9,21 +9,21 @@ use super::*;
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct NativeScrollView {
|
||||
pub x: Property<f32>,
|
||||
pub y: Property<f32>,
|
||||
pub width: Property<f32>,
|
||||
pub height: Property<f32>,
|
||||
pub horizontal_max: Property<f32>,
|
||||
pub horizontal_page_size: Property<f32>,
|
||||
pub horizontal_value: Property<f32>,
|
||||
pub vertical_max: Property<f32>,
|
||||
pub vertical_page_size: Property<f32>,
|
||||
pub vertical_value: Property<f32>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub horizontal_max: Property<LogicalLength>,
|
||||
pub horizontal_page_size: Property<LogicalLength>,
|
||||
pub horizontal_value: Property<LogicalLength>,
|
||||
pub vertical_max: Property<LogicalLength>,
|
||||
pub vertical_page_size: Property<LogicalLength>,
|
||||
pub vertical_value: Property<LogicalLength>,
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
pub native_padding_left: Property<f32>,
|
||||
pub native_padding_right: Property<f32>,
|
||||
pub native_padding_top: Property<f32>,
|
||||
pub native_padding_bottom: Property<f32>,
|
||||
pub native_padding_left: Property<LogicalLength>,
|
||||
pub native_padding_right: Property<LogicalLength>,
|
||||
pub native_padding_top: Property<LogicalLength>,
|
||||
pub native_padding_bottom: Property<LogicalLength>,
|
||||
pub enabled: Property<bool>,
|
||||
pub has_focus: Property<bool>,
|
||||
data: Property<NativeSliderData>,
|
||||
|
|
@ -65,24 +65,27 @@ impl Item for NativeScrollView {
|
|||
|
||||
self.native_padding_left.set_binding({
|
||||
let paddings = paddings.clone();
|
||||
move || paddings.as_ref().get().left as _
|
||||
move || LogicalLength::new(paddings.as_ref().get().left as _)
|
||||
});
|
||||
self.native_padding_right.set_binding({
|
||||
let paddings = paddings.clone();
|
||||
move || paddings.as_ref().get().right as _
|
||||
move || LogicalLength::new(paddings.as_ref().get().right as _)
|
||||
});
|
||||
self.native_padding_top.set_binding({
|
||||
let paddings = paddings.clone();
|
||||
move || paddings.as_ref().get().top as _
|
||||
move || LogicalLength::new(paddings.as_ref().get().top as _)
|
||||
});
|
||||
self.native_padding_bottom.set_binding({
|
||||
let paddings = paddings;
|
||||
move || paddings.as_ref().get().bottom as _
|
||||
move || LogicalLength::new(paddings.as_ref().get().bottom as _)
|
||||
});
|
||||
}
|
||||
|
||||
fn geometry(self: Pin<&Self>) -> LogicalRect {
|
||||
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
||||
LogicalRect::new(
|
||||
LogicalPoint::from_lengths(self.x(), self.y()),
|
||||
LogicalSize::from_lengths(self.width(), self.height()),
|
||||
)
|
||||
}
|
||||
|
||||
fn layout_info(
|
||||
|
|
@ -94,7 +97,8 @@ impl Item for NativeScrollView {
|
|||
min: match orientation {
|
||||
Orientation::Horizontal => self.native_padding_left() + self.native_padding_right(),
|
||||
Orientation::Vertical => self.native_padding_top() + self.native_padding_bottom(),
|
||||
},
|
||||
}
|
||||
.get(),
|
||||
stretch: 1.,
|
||||
..LayoutInfo::default()
|
||||
}
|
||||
|
|
@ -119,19 +123,19 @@ impl Item for NativeScrollView {
|
|||
let mut data = self.data();
|
||||
let active_controls = data.active_controls;
|
||||
let pressed = data.pressed;
|
||||
let left = self.native_padding_left();
|
||||
let right = self.native_padding_right();
|
||||
let top = self.native_padding_top();
|
||||
let bottom = self.native_padding_bottom();
|
||||
let left = self.native_padding_left().get();
|
||||
let right = self.native_padding_right().get();
|
||||
let top = self.native_padding_top().get();
|
||||
let bottom = self.native_padding_bottom().get();
|
||||
|
||||
let mut handle_scrollbar = |horizontal: bool,
|
||||
pos: qttypes::QPoint,
|
||||
size: qttypes::QSize,
|
||||
value_prop: Pin<&Property<f32>>,
|
||||
value_prop: Pin<&Property<LogicalLength>>,
|
||||
page_size: i32,
|
||||
max: i32| {
|
||||
let pressed: bool = data.pressed != 0;
|
||||
let value: i32 = value_prop.get() as i32;
|
||||
let value: i32 = value_prop.get().get() as i32;
|
||||
let new_control = cpp!(unsafe [
|
||||
pos as "QPoint",
|
||||
value as "int",
|
||||
|
|
@ -195,7 +199,7 @@ impl Item for NativeScrollView {
|
|||
return -value;
|
||||
}
|
||||
});
|
||||
value_prop.set(-(new_val.min(max).max(0) as f32));
|
||||
value_prop.set(LogicalLength::new(-(new_val.min(max).max(0) as f32)));
|
||||
InputEventResult::EventIgnored
|
||||
}
|
||||
MouseEvent::Moved { .. } => {
|
||||
|
|
@ -204,7 +208,7 @@ impl Item for NativeScrollView {
|
|||
let new_val = data.pressed_val
|
||||
+ ((pos as f32) - data.pressed_x) * (max + (page_size as f32))
|
||||
/ size as f32;
|
||||
value_prop.set(-new_val.min(max).max(0.));
|
||||
value_prop.set(LogicalLength::new(-new_val.min(max).max(0.)));
|
||||
InputEventResult::GrabMouse
|
||||
} else {
|
||||
InputEventResult::EventAccepted
|
||||
|
|
@ -233,8 +237,8 @@ impl Item for NativeScrollView {
|
|||
height: (size.height as f32 - (bottom + top)) as _,
|
||||
},
|
||||
Self::FIELD_OFFSETS.vertical_value.apply_pin(self),
|
||||
self.vertical_page_size() as i32,
|
||||
self.vertical_max() as i32,
|
||||
self.vertical_page_size().get() as i32,
|
||||
self.vertical_max().get() as i32,
|
||||
)
|
||||
} else if pressed == 1 || pos.y > (size.height as f32 - bottom) {
|
||||
handle_scrollbar(
|
||||
|
|
@ -248,8 +252,8 @@ impl Item for NativeScrollView {
|
|||
height: (bottom - top) as _,
|
||||
},
|
||||
Self::FIELD_OFFSETS.horizontal_value.apply_pin(self),
|
||||
self.horizontal_page_size() as i32,
|
||||
self.horizontal_max() as i32,
|
||||
self.horizontal_page_size().get() as i32,
|
||||
self.horizontal_max().get() as i32,
|
||||
)
|
||||
} else {
|
||||
Default::default()
|
||||
|
|
@ -278,10 +282,10 @@ impl Item for NativeScrollView {
|
|||
|
||||
let data = this.data();
|
||||
let margins = qttypes::QMargins {
|
||||
left: this.native_padding_left() as _,
|
||||
top: this.native_padding_top() as _,
|
||||
right: this.native_padding_right() as _,
|
||||
bottom: this.native_padding_bottom() as _,
|
||||
left: this.native_padding_left().get() as _,
|
||||
top: this.native_padding_top().get() as _,
|
||||
right: this.native_padding_right().get() as _,
|
||||
bottom: this.native_padding_bottom().get() as _,
|
||||
};
|
||||
let enabled: bool = this.enabled();
|
||||
let has_focus: bool = this.has_focus();
|
||||
|
|
@ -399,9 +403,9 @@ impl Item for NativeScrollView {
|
|||
width: scrollbars_width as _,
|
||||
height: ((size.height as f32 / dpr) - if frame_around_contents { scrollbars_height } else { (margins.bottom + margins.top) as f32 }) as _,
|
||||
},
|
||||
this.vertical_value() as i32,
|
||||
this.vertical_page_size() as i32,
|
||||
this.vertical_max() as i32,
|
||||
this.vertical_value().get() as i32,
|
||||
this.vertical_page_size().get() as i32,
|
||||
this.vertical_max().get() as i32,
|
||||
data.active_controls,
|
||||
data.pressed == 2,
|
||||
initial_state
|
||||
|
|
@ -414,9 +418,9 @@ impl Item for NativeScrollView {
|
|||
width: ((size.width as f32 / dpr) - if frame_around_contents { scrollbars_width } else { (margins.left + margins.right) as _ }) as _,
|
||||
height: (scrollbars_height) as _,
|
||||
},
|
||||
this.horizontal_value() as i32,
|
||||
this.horizontal_page_size() as i32,
|
||||
this.horizontal_max() as i32,
|
||||
this.horizontal_value().get() as i32,
|
||||
this.horizontal_page_size().get() as i32,
|
||||
this.horizontal_max().get() as i32,
|
||||
data.active_controls,
|
||||
data.pressed == 1,
|
||||
initial_state
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ type FloatArg = (f32,);
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct NativeSlider {
|
||||
pub x: Property<f32>,
|
||||
pub y: Property<f32>,
|
||||
pub width: Property<f32>,
|
||||
pub height: Property<f32>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub enabled: Property<bool>,
|
||||
pub value: Property<f32>,
|
||||
pub minimum: Property<f32>,
|
||||
|
|
@ -60,7 +60,10 @@ impl Item for NativeSlider {
|
|||
fn init(self: Pin<&Self>, _window_adapter: &Rc<dyn WindowAdapter>) {}
|
||||
|
||||
fn geometry(self: Pin<&Self>) -> LogicalRect {
|
||||
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
||||
LogicalRect::new(
|
||||
LogicalPoint::from_lengths(self.x(), self.y()),
|
||||
LogicalSize::from_lengths(self.width(), self.height()),
|
||||
)
|
||||
}
|
||||
|
||||
fn layout_info(
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@ struct NativeSpinBoxData {
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct NativeSpinBox {
|
||||
pub x: Property<f32>,
|
||||
pub y: Property<f32>,
|
||||
pub width: Property<f32>,
|
||||
pub height: Property<f32>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub enabled: Property<bool>,
|
||||
pub has_focus: Property<bool>,
|
||||
pub value: Property<i32>,
|
||||
|
|
@ -57,7 +57,10 @@ impl Item for NativeSpinBox {
|
|||
fn init(self: Pin<&Self>, _window_adapter: &Rc<dyn WindowAdapter>) {}
|
||||
|
||||
fn geometry(self: Pin<&Self>) -> LogicalRect {
|
||||
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
||||
LogicalRect::new(
|
||||
LogicalPoint::from_lengths(self.x(), self.y()),
|
||||
LogicalSize::from_lengths(self.width(), self.height()),
|
||||
)
|
||||
}
|
||||
|
||||
fn layout_info(
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@ struct StyleChangeListener : QWidget {
|
|||
#[pin]
|
||||
#[pin_drop]
|
||||
pub struct NativeStyleMetrics {
|
||||
pub layout_spacing: Property<f32>,
|
||||
pub layout_padding: Property<f32>,
|
||||
pub text_cursor_width: Property<f32>,
|
||||
pub layout_spacing: Property<LogicalLength>,
|
||||
pub layout_padding: Property<LogicalLength>,
|
||||
pub text_cursor_width: Property<LogicalLength>,
|
||||
pub window_background: Property<Color>,
|
||||
pub default_text_color: Property<Color>,
|
||||
pub textedit_background: Property<Color>,
|
||||
|
|
@ -104,15 +104,15 @@ impl NativeStyleMetrics {
|
|||
spacing = qApp->style()->layoutSpacing(QSizePolicy::DefaultType, QSizePolicy::DefaultType, Qt::Horizontal);
|
||||
return spacing;
|
||||
});
|
||||
self.layout_spacing.set(layout_spacing.max(0.0));
|
||||
self.layout_spacing.set(LogicalLength::new(layout_spacing.max(0.0)));
|
||||
let layout_padding = cpp!(unsafe [] -> f32 as "float" {
|
||||
return qApp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
|
||||
});
|
||||
self.layout_padding.set(layout_padding.max(0.0));
|
||||
self.layout_padding.set(LogicalLength::new(layout_padding.max(0.0)));
|
||||
let text_cursor_width = cpp!(unsafe [] -> f32 as "float" {
|
||||
return qApp->style()->pixelMetric(QStyle::PM_TextCursorWidth);
|
||||
});
|
||||
self.text_cursor_width.set(text_cursor_width.max(0.0));
|
||||
self.text_cursor_width.set(LogicalLength::new(text_cursor_width.max(0.0)));
|
||||
let window_background = cpp!(unsafe[] -> u32 as "QRgb" {
|
||||
return qApp->palette().color(QPalette::Window).rgba();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,27 +11,27 @@ use super::*;
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct NativeTabWidget {
|
||||
pub x: Property<f32>,
|
||||
pub y: Property<f32>,
|
||||
pub width: Property<f32>,
|
||||
pub height: Property<f32>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
pub content_min_height: Property<f32>,
|
||||
pub content_min_width: Property<f32>,
|
||||
pub tabbar_preferred_height: Property<f32>,
|
||||
pub tabbar_preferred_width: Property<f32>,
|
||||
pub content_min_height: Property<LogicalLength>,
|
||||
pub content_min_width: Property<LogicalLength>,
|
||||
pub tabbar_preferred_height: Property<LogicalLength>,
|
||||
pub tabbar_preferred_width: Property<LogicalLength>,
|
||||
pub current_index: Property<i32>,
|
||||
pub current_focused: Property<i32>,
|
||||
|
||||
// outputs
|
||||
pub content_x: Property<f32>,
|
||||
pub content_y: Property<f32>,
|
||||
pub content_height: Property<f32>,
|
||||
pub content_width: Property<f32>,
|
||||
pub tabbar_x: Property<f32>,
|
||||
pub tabbar_y: Property<f32>,
|
||||
pub tabbar_height: Property<f32>,
|
||||
pub tabbar_width: Property<f32>,
|
||||
pub content_x: Property<LogicalLength>,
|
||||
pub content_y: Property<LogicalLength>,
|
||||
pub content_height: Property<LogicalLength>,
|
||||
pub content_width: Property<LogicalLength>,
|
||||
pub tabbar_x: Property<LogicalLength>,
|
||||
pub tabbar_y: Property<LogicalLength>,
|
||||
pub tabbar_height: Property<LogicalLength>,
|
||||
pub tabbar_width: Property<LogicalLength>,
|
||||
}
|
||||
|
||||
impl Item for NativeTabWidget {
|
||||
|
|
@ -50,10 +50,10 @@ impl Item for NativeTabWidget {
|
|||
#[derive(FieldOffsets, Default)]
|
||||
#[pin]
|
||||
struct TabBarSharedData {
|
||||
width: Property<f32>,
|
||||
height: Property<f32>,
|
||||
tabbar_preferred_height: Property<f32>,
|
||||
tabbar_preferred_width: Property<f32>,
|
||||
width: Property<LogicalLength>,
|
||||
height: Property<LogicalLength>,
|
||||
tabbar_preferred_height: Property<LogicalLength>,
|
||||
tabbar_preferred_width: Property<LogicalLength>,
|
||||
horizontal_metrics: Property<TabWidgetMetrics>,
|
||||
vertical_metrics: Property<TabWidgetMetrics>,
|
||||
}
|
||||
|
|
@ -82,6 +82,7 @@ impl Item for NativeTabWidget {
|
|||
width: TabBarSharedData::FIELD_OFFSETS
|
||||
.width
|
||||
.apply_pin(shared_data.as_ref())
|
||||
.get()
|
||||
.get() as _,
|
||||
height: (std::i32::MAX / 2) as _,
|
||||
},
|
||||
|
|
@ -89,6 +90,7 @@ impl Item for NativeTabWidget {
|
|||
width: TabBarSharedData::FIELD_OFFSETS
|
||||
.tabbar_preferred_width
|
||||
.apply_pin(shared_data.as_ref())
|
||||
.get()
|
||||
.get() as _,
|
||||
height: (std::i32::MAX / 2) as _,
|
||||
},
|
||||
|
|
@ -99,6 +101,7 @@ impl Item for NativeTabWidget {
|
|||
height: TabBarSharedData::FIELD_OFFSETS
|
||||
.height
|
||||
.apply_pin(shared_data.as_ref())
|
||||
.get()
|
||||
.get() as _,
|
||||
},
|
||||
qttypes::QSizeF {
|
||||
|
|
@ -106,6 +109,7 @@ impl Item for NativeTabWidget {
|
|||
height: TabBarSharedData::FIELD_OFFSETS
|
||||
.tabbar_preferred_height
|
||||
.apply_pin(shared_data.as_ref())
|
||||
.get()
|
||||
.get() as _,
|
||||
},
|
||||
),
|
||||
|
|
@ -150,7 +154,7 @@ impl Item for NativeTabWidget {
|
|||
.$field1
|
||||
.apply_pin(shared_data.as_ref())
|
||||
.get();
|
||||
metrics.$field2 as f32
|
||||
LogicalLength::new(metrics.$field2 as f32)
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
@ -165,7 +169,10 @@ impl Item for NativeTabWidget {
|
|||
}
|
||||
|
||||
fn geometry(self: Pin<&Self>) -> LogicalRect {
|
||||
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
||||
LogicalRect::new(
|
||||
LogicalPoint::from_lengths(self.x(), self.y()),
|
||||
LogicalSize::from_lengths(self.width(), self.height()),
|
||||
)
|
||||
}
|
||||
|
||||
fn layout_info(
|
||||
|
|
@ -176,22 +183,22 @@ impl Item for NativeTabWidget {
|
|||
let (content_size, tabbar_size) = match orientation {
|
||||
Orientation::Horizontal => (
|
||||
qttypes::QSizeF {
|
||||
width: self.content_min_width() as _,
|
||||
width: self.content_min_width().get() as _,
|
||||
height: (std::i32::MAX / 2) as _,
|
||||
},
|
||||
qttypes::QSizeF {
|
||||
width: self.tabbar_preferred_width() as _,
|
||||
width: self.tabbar_preferred_width().get() as _,
|
||||
height: (std::i32::MAX / 2) as _,
|
||||
},
|
||||
),
|
||||
Orientation::Vertical => (
|
||||
qttypes::QSizeF {
|
||||
width: (std::i32::MAX / 2) as _,
|
||||
height: self.content_min_height() as _,
|
||||
height: self.content_min_height().get() as _,
|
||||
},
|
||||
qttypes::QSizeF {
|
||||
width: (std::i32::MAX / 2) as _,
|
||||
height: self.tabbar_preferred_height() as _,
|
||||
height: self.tabbar_preferred_height().get() as _,
|
||||
},
|
||||
),
|
||||
};
|
||||
|
|
@ -262,8 +269,8 @@ impl Item for NativeTabWidget {
|
|||
|
||||
fn_render! { this dpr size painter widget initial_state =>
|
||||
let tabbar_size = qttypes::QSizeF {
|
||||
width: this.tabbar_preferred_width() as _,
|
||||
height: this.tabbar_preferred_height() as _,
|
||||
width: this.tabbar_preferred_width().get() as _,
|
||||
height: this.tabbar_preferred_height().get() as _,
|
||||
};
|
||||
cpp!(unsafe [
|
||||
painter as "QPainterPtr*",
|
||||
|
|
@ -322,10 +329,10 @@ fn slint_get_NativeTabWidgetVTable() -> NativeTabWidgetVTable for NativeTabWidge
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct NativeTab {
|
||||
pub x: Property<f32>,
|
||||
pub y: Property<f32>,
|
||||
pub width: Property<f32>,
|
||||
pub height: Property<f32>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub title: Property<SharedString>,
|
||||
pub icon: Property<i_slint_core::graphics::Image>,
|
||||
pub enabled: Property<bool>,
|
||||
|
|
@ -341,7 +348,10 @@ impl Item for NativeTab {
|
|||
fn init(self: Pin<&Self>, _window_adapter: &Rc<dyn WindowAdapter>) {}
|
||||
|
||||
fn geometry(self: Pin<&Self>) -> LogicalRect {
|
||||
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
||||
LogicalRect::new(
|
||||
LogicalPoint::from_lengths(self.x(), self.y()),
|
||||
LogicalSize::from_lengths(self.width(), self.height()),
|
||||
)
|
||||
}
|
||||
|
||||
fn layout_info(
|
||||
|
|
|
|||
|
|
@ -496,10 +496,10 @@ macro_rules! get_geometry {
|
|||
type Ty = $ty;
|
||||
let width = Ty::FIELD_OFFSETS.width.apply_pin($obj).get();
|
||||
let height = Ty::FIELD_OFFSETS.height.apply_pin($obj).get();
|
||||
if width <= 0. || height <= 0. {
|
||||
if width <= LogicalLength::zero() || height <= LogicalLength::zero() {
|
||||
return Default::default();
|
||||
};
|
||||
qttypes::QRectF { x: 0., y: 0., width: width as _, height: height as _ }
|
||||
qttypes::QRectF { x: 0., y: 0., width: width.get() as _, height: height.get() as _ }
|
||||
}};
|
||||
}
|
||||
|
||||
|
|
@ -1139,15 +1139,15 @@ impl QtItemRenderer<'_> {
|
|||
source_property: Pin<&Property<Image>>,
|
||||
dest_rect: qttypes::QRectF,
|
||||
source_rect: Option<qttypes::QRectF>,
|
||||
target_width: std::pin::Pin<&Property<f32>>,
|
||||
target_height: std::pin::Pin<&Property<f32>>,
|
||||
target_width: std::pin::Pin<&Property<LogicalLength>>,
|
||||
target_height: std::pin::Pin<&Property<LogicalLength>>,
|
||||
image_fit: ImageFit,
|
||||
rendering: ImageRendering,
|
||||
colorize_property: Option<Pin<&Property<Brush>>>,
|
||||
) {
|
||||
// Caller ensured that zero/negative width/height resulted in an early return via get_geometry!.
|
||||
debug_assert!(target_width.get() > 0.);
|
||||
debug_assert!(target_height.get() > 0.);
|
||||
debug_assert!(target_width.get() > LogicalLength::zero());
|
||||
debug_assert!(target_height.get() > LogicalLength::zero());
|
||||
|
||||
let pixmap: qttypes::QPixmap = self.cache.get_or_update_cache_entry(item_rc, || {
|
||||
let source = source_property.get();
|
||||
|
|
@ -1155,7 +1155,8 @@ impl QtItemRenderer<'_> {
|
|||
let source: &ImageInner = (&source).into();
|
||||
|
||||
// Query target_width/height here again to ensure that changes will invalidate the item rendering cache.
|
||||
let t = euclid::size2(target_width.get(), target_height.get()).cast::<f64>();
|
||||
let t =
|
||||
euclid::size2(target_width.get().get(), target_height.get().get()).cast::<f64>();
|
||||
|
||||
let source_size = if source.is_svg() {
|
||||
let has_source_clipping = source_rect.map_or(false, |rect| {
|
||||
|
|
@ -1466,14 +1467,14 @@ impl WindowAdapterSealed for QtWindow {
|
|||
let root_item = component.as_ref().get_item_ref(0);
|
||||
if let Some(window_item) = ItemRef::downcast_pin::<WindowItem>(root_item) {
|
||||
if window_item.width() <= LogicalLength::zero() {
|
||||
window_item.width.set(
|
||||
window_item.width.set(LogicalLength::new(
|
||||
component.as_ref().layout_info(Orientation::Horizontal).preferred_bounded(),
|
||||
)
|
||||
))
|
||||
}
|
||||
if window_item.height() <= LogicalLength::zero() {
|
||||
window_item
|
||||
.height
|
||||
.set(component.as_ref().layout_info(Orientation::Vertical).preferred_bounded())
|
||||
window_item.height.set(LogicalLength::new(
|
||||
component.as_ref().layout_info(Orientation::Vertical).preferred_bounded(),
|
||||
))
|
||||
}
|
||||
|
||||
self.apply_window_properties(window_item);
|
||||
|
|
@ -1531,11 +1532,11 @@ impl WindowAdapterSealed for QtWindow {
|
|||
return widget_ptr->size();
|
||||
});
|
||||
if size.width == 0 {
|
||||
window_item.width.set(existing_size.width as _);
|
||||
window_item.width.set(LogicalLength::new(existing_size.width as _));
|
||||
size.width = existing_size.width;
|
||||
}
|
||||
if size.height == 0 {
|
||||
window_item.height.set(existing_size.height as _);
|
||||
window_item.height.set(LogicalLength::new(existing_size.height as _));
|
||||
size.height = existing_size.height;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -443,7 +443,7 @@ impl<Renderer: WinitCompatibleRenderer + 'static> WindowAdapterSealed for GLWind
|
|||
if let Some(window_item) = runtime_window.window_item() {
|
||||
// Setting the width to its preferred size before querying the vertical layout info
|
||||
// is important in case the height depends on the width
|
||||
window_item.width.set(layout_info_h.preferred_bounded());
|
||||
window_item.width.set(LogicalLength::new(layout_info_h.preferred_bounded()));
|
||||
}
|
||||
let layout_info_v = component.as_ref().layout_info(Orientation::Vertical);
|
||||
let s = winit::dpi::LogicalSize::new(
|
||||
|
|
|
|||
|
|
@ -1157,14 +1157,14 @@ impl<'a> GLItemRenderer<'a> {
|
|||
item_rc: &ItemRc,
|
||||
source_property: Pin<&Property<Image>>,
|
||||
source_clip_rect: IntRect,
|
||||
target_width: Pin<&Property<f32>>,
|
||||
target_height: Pin<&Property<f32>>,
|
||||
target_width: Pin<&Property<LogicalLength>>,
|
||||
target_height: Pin<&Property<LogicalLength>>,
|
||||
image_fit: ImageFit,
|
||||
colorize_property: Option<Pin<&Property<Brush>>>,
|
||||
image_rendering: ImageRendering,
|
||||
) {
|
||||
let target_w = LogicalLength::new(target_width.get()) * self.scale_factor;
|
||||
let target_h = LogicalLength::new(target_height.get()) * self.scale_factor;
|
||||
let target_w = target_width.get() * self.scale_factor;
|
||||
let target_h = target_height.get() * self.scale_factor;
|
||||
|
||||
if target_w.get() <= 0. || target_h.get() <= 0. {
|
||||
return;
|
||||
|
|
@ -1178,10 +1178,8 @@ impl<'a> GLItemRenderer<'a> {
|
|||
let target_size_for_scalable_source = image_inner.is_svg().then(|| {
|
||||
// get the scale factor as a property again, to ensure the cache is invalidated when the scale factor changes
|
||||
let scale_factor = ScaleFactor::new(self.window.scale_factor());
|
||||
let t = LogicalSize::from_lengths(
|
||||
LogicalLength::new(target_width.get()),
|
||||
LogicalLength::new(target_height.get()),
|
||||
) * scale_factor;
|
||||
let t = LogicalSize::from_lengths(target_width.get(), target_height.get())
|
||||
* scale_factor;
|
||||
|
||||
i_slint_core::graphics::fit_size(image_fit, t, image.size()).cast()
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use i_slint_core::graphics::{
|
|||
SharedImageBuffer,
|
||||
};
|
||||
use i_slint_core::items::ImageFit;
|
||||
use i_slint_core::lengths::{LogicalSize, ScaleFactor};
|
||||
use i_slint_core::lengths::{LogicalLength, LogicalSize, ScaleFactor};
|
||||
|
||||
struct SkiaCachedImage {
|
||||
image: skia_safe::Image,
|
||||
|
|
@ -29,8 +29,8 @@ impl OpaqueImage for SkiaCachedImage {
|
|||
|
||||
pub(crate) fn as_skia_image(
|
||||
image: Image,
|
||||
target_width: std::pin::Pin<&i_slint_core::Property<f32>>,
|
||||
target_height: std::pin::Pin<&i_slint_core::Property<f32>>,
|
||||
target_width: std::pin::Pin<&i_slint_core::Property<LogicalLength>>,
|
||||
target_height: std::pin::Pin<&i_slint_core::Property<LogicalLength>>,
|
||||
image_fit: ImageFit,
|
||||
scale_factor: ScaleFactor,
|
||||
) -> Option<skia_safe::Image> {
|
||||
|
|
@ -52,7 +52,7 @@ pub(crate) fn as_skia_image(
|
|||
ImageInner::Svg(svg) => {
|
||||
// Query target_width/height here again to ensure that changes will invalidate the item rendering cache.
|
||||
let target_size =
|
||||
LogicalSize::new(target_width.get(), target_height.get()) * scale_factor;
|
||||
LogicalSize::from_lengths(target_width.get(), target_height.get()) * scale_factor;
|
||||
let target_size = i_slint_core::graphics::fit_size(image_fit, target_size, svg.size());
|
||||
let pixels = match svg.render(target_size.cast()).ok()? {
|
||||
SharedImageBuffer::RGB8(_) => unreachable!(),
|
||||
|
|
|
|||
|
|
@ -140,8 +140,8 @@ impl<'a> SkiaRenderer<'a> {
|
|||
source_property: Pin<&Property<i_slint_core::graphics::Image>>,
|
||||
mut dest_rect: PhysicalRect,
|
||||
source_rect: Option<skia_safe::Rect>,
|
||||
target_width: std::pin::Pin<&Property<f32>>,
|
||||
target_height: std::pin::Pin<&Property<f32>>,
|
||||
target_width: std::pin::Pin<&Property<LogicalLength>>,
|
||||
target_height: std::pin::Pin<&Property<LogicalLength>>,
|
||||
image_fit: ImageFit,
|
||||
rendering: ImageRendering,
|
||||
colorize_property: Option<Pin<&Property<Brush>>>,
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ impl quote::ToTokens for crate::embedded_resources::PixelFormat {
|
|||
}
|
||||
}
|
||||
|
||||
fn rust_type(ty: &Type) -> Option<proc_macro2::TokenStream> {
|
||||
fn rust_primitive_type(ty: &Type) -> Option<proc_macro2::TokenStream> {
|
||||
match ty {
|
||||
Type::Int32 => Some(quote!(i32)),
|
||||
Type::Float32 => Some(quote!(f32)),
|
||||
|
|
@ -80,13 +80,13 @@ fn rust_type(ty: &Type) -> Option<proc_macro2::TokenStream> {
|
|||
Type::Bool => Some(quote!(bool)),
|
||||
Type::Image => Some(quote!(slint::private_unstable_api::re_exports::Image)),
|
||||
Type::Struct { fields, name: None, .. } => {
|
||||
let elem = fields.values().map(rust_type).collect::<Option<Vec<_>>>()?;
|
||||
let elem = fields.values().map(rust_primitive_type).collect::<Option<Vec<_>>>()?;
|
||||
// This will produce a tuple
|
||||
Some(quote!((#(#elem,)*)))
|
||||
}
|
||||
Type::Struct { name: Some(name), .. } => Some(struct_name_to_tokens(name)),
|
||||
Type::Array(o) => {
|
||||
let inner = rust_type(o)?;
|
||||
let inner = rust_primitive_type(o)?;
|
||||
Some(quote!(slint::private_unstable_api::re_exports::ModelRc<#inner>))
|
||||
}
|
||||
Type::Enumeration(e) => {
|
||||
|
|
@ -103,6 +103,31 @@ fn rust_type(ty: &Type) -> Option<proc_macro2::TokenStream> {
|
|||
}
|
||||
}
|
||||
|
||||
fn rust_property_type(ty: &Type) -> Option<proc_macro2::TokenStream> {
|
||||
match ty {
|
||||
Type::LogicalLength => Some(quote!(slint::private_unstable_api::re_exports::LogicalLength)),
|
||||
_ => rust_primitive_type(ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn primitive_property_value(ty: &Type, property_accessor: TokenStream) -> TokenStream {
|
||||
let value = quote!(#property_accessor.get());
|
||||
match ty {
|
||||
Type::LogicalLength => quote!(#value.get()),
|
||||
_ => value,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_primitive_property_value(ty: &Type, value_expression: TokenStream) -> TokenStream {
|
||||
match ty {
|
||||
Type::LogicalLength => {
|
||||
let rust_ty = rust_primitive_type(ty).unwrap_or(quote!(_));
|
||||
quote!(slint::private_unstable_api::re_exports::LogicalLength::new(#value_expression as #rust_ty))
|
||||
}
|
||||
_ => value_expression,
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate the rust code for the given component.
|
||||
pub fn generate(doc: &Document) -> TokenStream {
|
||||
if matches!(doc.root_component.root_element.borrow().base_type, Type::Invalid | Type::Void) {
|
||||
|
|
@ -380,7 +405,7 @@ fn generate_public_component(llr: &llr::PublicComponent) -> TokenStream {
|
|||
fn generate_struct(name: &str, fields: &BTreeMap<String, Type>) -> TokenStream {
|
||||
let component_id = struct_name_to_tokens(name);
|
||||
let (declared_property_vars, declared_property_types): (Vec<_>, Vec<_>) =
|
||||
fields.iter().map(|(name, ty)| (ident(name), rust_type(ty).unwrap())).unzip();
|
||||
fields.iter().map(|(name, ty)| (ident(name), rust_primitive_type(ty).unwrap())).unzip();
|
||||
|
||||
quote! {
|
||||
#[derive(Default, PartialEq, Debug, Clone)]
|
||||
|
|
@ -427,8 +452,11 @@ fn handle_property_init(
|
|||
} else {
|
||||
let tokens_for_expression =
|
||||
compile_expression(&binding_expression.expression.borrow(), ctx);
|
||||
|
||||
let tokens_for_expression = set_primitive_property_value(prop_type, tokens_for_expression);
|
||||
|
||||
init.push(if binding_expression.is_constant && !binding_expression.is_state_info {
|
||||
let t = rust_type(prop_type).unwrap_or(quote!(_));
|
||||
let t = rust_property_type(prop_type).unwrap_or(quote!(_));
|
||||
|
||||
// When there is a `return` statement, we must use a lambda expression in the generated code so that the
|
||||
// generated code can have an actual return in it. We only want to do that if necessary because otherwise
|
||||
|
|
@ -498,8 +526,10 @@ fn public_api(
|
|||
let prop = access_member(r, ctx);
|
||||
|
||||
if let Type::Callback { args, return_type } = ty {
|
||||
let callback_args = args.iter().map(|a| rust_type(a).unwrap()).collect::<Vec<_>>();
|
||||
let return_type = return_type.as_ref().map_or(quote!(()), |a| rust_type(a).unwrap());
|
||||
let callback_args =
|
||||
args.iter().map(|a| rust_primitive_type(a).unwrap()).collect::<Vec<_>>();
|
||||
let return_type =
|
||||
return_type.as_ref().map_or(quote!(()), |a| rust_primitive_type(a).unwrap());
|
||||
let args_name = (0..args.len()).map(|i| format_ident!("arg_{}", i)).collect::<Vec<_>>();
|
||||
let caller_ident = format_ident!("invoke_{}", prop_ident);
|
||||
property_and_callback_accessors.push(quote!(
|
||||
|
|
@ -523,18 +553,20 @@ fn public_api(
|
|||
}
|
||||
));
|
||||
} else {
|
||||
let rust_property_type = rust_type(ty).unwrap();
|
||||
let rust_property_type = rust_primitive_type(ty).unwrap();
|
||||
|
||||
let getter_ident = format_ident!("get_{}", prop_ident);
|
||||
let setter_ident = format_ident!("set_{}", prop_ident);
|
||||
|
||||
let prop_expression = primitive_property_value(ty, prop);
|
||||
|
||||
property_and_callback_accessors.push(quote!(
|
||||
#[allow(dead_code)]
|
||||
pub fn #getter_ident(&self) -> #rust_property_type {
|
||||
#[allow(unused_imports)]
|
||||
use slint::private_unstable_api::re_exports::*;
|
||||
let _self = #self_init;
|
||||
#prop.get()
|
||||
#prop_expression
|
||||
}
|
||||
));
|
||||
|
||||
|
|
@ -586,13 +618,15 @@ fn generate_sub_component(
|
|||
for property in component.properties.iter().filter(|p| p.use_count.get() > 0) {
|
||||
let prop_ident = ident(&property.name);
|
||||
if let Type::Callback { args, return_type } = &property.ty {
|
||||
let callback_args = args.iter().map(|a| rust_type(a).unwrap()).collect::<Vec<_>>();
|
||||
let return_type = return_type.as_ref().map_or(quote!(()), |a| rust_type(a).unwrap());
|
||||
let callback_args =
|
||||
args.iter().map(|a| rust_primitive_type(a).unwrap()).collect::<Vec<_>>();
|
||||
let return_type =
|
||||
return_type.as_ref().map_or(quote!(()), |a| rust_primitive_type(a).unwrap());
|
||||
declared_callbacks.push(prop_ident.clone());
|
||||
declared_callbacks_types.push(callback_args);
|
||||
declared_callbacks_ret.push(return_type);
|
||||
} else {
|
||||
let rust_property_type = rust_type(&property.ty).unwrap();
|
||||
let rust_property_type = rust_property_type(&property.ty).unwrap();
|
||||
declared_property_vars.push(prop_ident.clone());
|
||||
declared_property_types.push(rust_property_type.clone());
|
||||
}
|
||||
|
|
@ -980,13 +1014,15 @@ fn generate_global(global: &llr::GlobalComponent, root: &llr::PublicComponent) -
|
|||
for property in global.properties.iter().filter(|p| p.use_count.get() > 0) {
|
||||
let prop_ident = ident(&property.name);
|
||||
if let Type::Callback { args, return_type } = &property.ty {
|
||||
let callback_args = args.iter().map(|a| rust_type(a).unwrap()).collect::<Vec<_>>();
|
||||
let return_type = return_type.as_ref().map_or(quote!(()), |a| rust_type(a).unwrap());
|
||||
let callback_args =
|
||||
args.iter().map(|a| rust_primitive_type(a).unwrap()).collect::<Vec<_>>();
|
||||
let return_type =
|
||||
return_type.as_ref().map_or(quote!(()), |a| rust_primitive_type(a).unwrap());
|
||||
declared_callbacks.push(prop_ident.clone());
|
||||
declared_callbacks_types.push(callback_args);
|
||||
declared_callbacks_ret.push(return_type);
|
||||
} else {
|
||||
let rust_property_type = rust_type(&property.ty).unwrap();
|
||||
let rust_property_type = rust_property_type(&property.ty).unwrap();
|
||||
declared_property_vars.push(prop_ident.clone());
|
||||
declared_property_types.push(rust_property_type.clone());
|
||||
}
|
||||
|
|
@ -1340,8 +1376,8 @@ fn generate_repeated_component(
|
|||
quote! {
|
||||
fn listview_layout(
|
||||
self: core::pin::Pin<&Self>,
|
||||
offset_y: &mut slint::private_unstable_api::re_exports::Coord,
|
||||
viewport_width: core::pin::Pin<&slint::private_unstable_api::re_exports::Property<slint::private_unstable_api::re_exports::Coord>>,
|
||||
offset_y: &mut slint::private_unstable_api::re_exports::LogicalLength,
|
||||
viewport_width: core::pin::Pin<&slint::private_unstable_api::re_exports::Property<slint::private_unstable_api::re_exports::LogicalLength>>,
|
||||
) {
|
||||
use slint::private_unstable_api::re_exports::*;
|
||||
let _self = self;
|
||||
|
|
@ -1367,19 +1403,27 @@ fn generate_repeated_component(
|
|||
};
|
||||
|
||||
let data_type = if let Some(data_prop) = repeated.data_prop {
|
||||
rust_type(&repeated.sub_tree.root.properties[data_prop].ty).unwrap()
|
||||
rust_primitive_type(&repeated.sub_tree.root.properties[data_prop].ty).unwrap()
|
||||
} else {
|
||||
quote!(())
|
||||
};
|
||||
|
||||
let access_prop = |&property_index| {
|
||||
let access_prop = |property_index| {
|
||||
access_member(
|
||||
&llr::PropertyReference::Local { sub_component_path: vec![], property_index },
|
||||
&ctx,
|
||||
)
|
||||
};
|
||||
let index_prop = repeated.index_prop.iter().map(access_prop);
|
||||
let data_prop = repeated.data_prop.iter().map(access_prop);
|
||||
let index_prop = repeated.index_prop.into_iter().map(access_prop);
|
||||
let set_data_expr = repeated.data_prop.into_iter().map(|property_index| {
|
||||
let prop_type = ctx.property_ty(&llr::PropertyReference::Local {
|
||||
sub_component_path: vec![],
|
||||
property_index,
|
||||
});
|
||||
let data_prop = access_prop(property_index);
|
||||
let value_tokens = set_primitive_property_value(prop_type, quote!(_data));
|
||||
quote!(#data_prop.set(#value_tokens);)
|
||||
});
|
||||
|
||||
quote!(
|
||||
#component
|
||||
|
|
@ -1390,7 +1434,7 @@ fn generate_repeated_component(
|
|||
let self_rc = self.self_weak.get().unwrap().upgrade().unwrap();
|
||||
let _self = self_rc.as_pin_ref();
|
||||
#(#index_prop.set(_index as _);)*
|
||||
#(#data_prop.set(_data);)*
|
||||
#(#set_data_expr)*
|
||||
}
|
||||
#extra_fn
|
||||
}
|
||||
|
|
@ -1421,6 +1465,8 @@ fn property_set_value_tokens(
|
|||
ctx: &EvaluationContext,
|
||||
) -> TokenStream {
|
||||
let prop = access_member(property, ctx);
|
||||
let prop_type = ctx.property_ty(property);
|
||||
let value_tokens = set_primitive_property_value(prop_type, value_tokens);
|
||||
if let Some(animation) = ctx.current_sub_component.and_then(|c| c.animations.get(property)) {
|
||||
let animation_tokens = compile_expression(animation, ctx);
|
||||
return quote!(#prop.set_animated_value(#value_tokens as _, #animation_tokens));
|
||||
|
|
@ -1674,7 +1720,8 @@ fn compile_expression(expr: &Expression, ctx: &EvaluationContext) -> TokenStream
|
|||
}
|
||||
Expression::PropertyReference(nr) => {
|
||||
let access = access_member(nr, ctx);
|
||||
quote!(#access.get())
|
||||
let prop_type = ctx.property_ty(nr);
|
||||
primitive_property_value(prop_type, access)
|
||||
}
|
||||
Expression::BuiltinFunctionCall { function, arguments } => {
|
||||
compile_builtin_function_call(*function, arguments, ctx)
|
||||
|
|
@ -1853,7 +1900,7 @@ fn compile_expression(expr: &Expression, ctx: &EvaluationContext) -> TokenStream
|
|||
Expression::Array { values, element_ty, as_model } => {
|
||||
let val = values.iter().map(|e| compile_expression(e, ctx));
|
||||
if *as_model {
|
||||
let rust_element_ty = rust_type(element_ty).unwrap();
|
||||
let rust_element_ty = rust_primitive_type(element_ty).unwrap();
|
||||
quote!(slint::private_unstable_api::re_exports::ModelRc::new(
|
||||
slint::private_unstable_api::re_exports::VecModel::<#rust_element_ty>::from(
|
||||
slint::private_unstable_api::re_exports::vec![#(#val as _),*]
|
||||
|
|
@ -1879,7 +1926,7 @@ fn compile_expression(expr: &Expression, ctx: &EvaluationContext) -> TokenStream
|
|||
if t.as_unit_product().is_some() {
|
||||
// number needs to be converted to the right things because intermediate
|
||||
// result might be f64 and that's usually not what the type of the tuple is in the end
|
||||
let t = rust_type(t).unwrap();
|
||||
let t = rust_primitive_type(t).unwrap();
|
||||
quote!(as #t)
|
||||
} else {
|
||||
quote!()
|
||||
|
|
|
|||
|
|
@ -36,9 +36,6 @@ pub fn slint_element(input: TokenStream) -> TokenStream {
|
|||
let mut property_names = Vec::new();
|
||||
let mut property_visibility = Vec::new();
|
||||
let mut property_types = Vec::new();
|
||||
let mut logical_length_property_names = Vec::new();
|
||||
let mut logical_length_property_field_names = Vec::new();
|
||||
let mut logical_length_property_visibility = Vec::new();
|
||||
|
||||
for field in fields {
|
||||
if let Some(property_type) = property_type(&field.ty) {
|
||||
|
|
@ -49,21 +46,6 @@ pub fn slint_element(input: TokenStream) -> TokenStream {
|
|||
pub_prop_field_types.push(&field.ty);
|
||||
}
|
||||
|
||||
if let syn::Type::Path(syn::TypePath { path: syn::Path { segments, .. }, .. }) =
|
||||
&property_type
|
||||
{
|
||||
if let Some(syn::PathSegment { ident, arguments: syn::PathArguments::None }) =
|
||||
segments.first()
|
||||
{
|
||||
if *ident == "Coord" {
|
||||
logical_length_property_names.push(name);
|
||||
logical_length_property_field_names.push(name);
|
||||
logical_length_property_visibility.push(field.vis.clone());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property_names.push(name);
|
||||
property_visibility.push(field.vis.clone());
|
||||
property_types.push(property_type);
|
||||
|
|
@ -144,11 +126,6 @@ pub fn slint_element(input: TokenStream) -> TokenStream {
|
|||
Self::FIELD_OFFSETS.#property_names.apply_pin(self).get()
|
||||
}
|
||||
)*
|
||||
#(
|
||||
#logical_length_property_visibility fn #logical_length_property_names(self: core::pin::Pin<&Self>) -> LogicalLength {
|
||||
LogicalLength::new(Self::FIELD_OFFSETS.#logical_length_property_field_names.apply_pin(self).get())
|
||||
}
|
||||
)*
|
||||
}
|
||||
)
|
||||
.into()
|
||||
|
|
|
|||
|
|
@ -468,7 +468,10 @@ macro_rules! forward_rendering_call {
|
|||
let height = Ty::FIELD_OFFSETS.height.apply_pin(obj).get_untracked();
|
||||
let x = Ty::FIELD_OFFSETS.x.apply_pin(obj).get_untracked();
|
||||
let y = Ty::FIELD_OFFSETS.y.apply_pin(obj).get_untracked();
|
||||
LogicalRect::new(LogicalPoint::new(x, y), LogicalSize::new(width, height))
|
||||
LogicalRect::new(
|
||||
LogicalPoint::from_lengths(x, y),
|
||||
LogicalSize::from_lengths(width, height),
|
||||
)
|
||||
})
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -179,10 +179,10 @@ pub type ItemRef<'a> = vtable::VRef<'a, ItemVTable>;
|
|||
/// The implementation of the `Rectangle` element
|
||||
pub struct Rectangle {
|
||||
pub background: Property<Brush>,
|
||||
pub x: Property<Coord>,
|
||||
pub y: Property<Coord>,
|
||||
pub width: Property<Coord>,
|
||||
pub height: Property<Coord>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
}
|
||||
|
||||
|
|
@ -267,12 +267,12 @@ declare_item_vtable! {
|
|||
/// The implementation of the `BorderRectangle` element
|
||||
pub struct BorderRectangle {
|
||||
pub background: Property<Brush>,
|
||||
pub x: Property<Coord>,
|
||||
pub y: Property<Coord>,
|
||||
pub width: Property<Coord>,
|
||||
pub height: Property<Coord>,
|
||||
pub border_width: Property<Coord>,
|
||||
pub border_radius: Property<Coord>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub border_width: Property<LogicalLength>,
|
||||
pub border_radius: Property<LogicalLength>,
|
||||
pub border_color: Property<Brush>,
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
}
|
||||
|
|
@ -357,10 +357,10 @@ declare_item_vtable! {
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct TouchArea {
|
||||
pub x: Property<Coord>,
|
||||
pub y: Property<Coord>,
|
||||
pub width: Property<Coord>,
|
||||
pub height: Property<Coord>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub enabled: Property<bool>,
|
||||
/// FIXME: We should annotate this as an "output" property.
|
||||
pub pressed: Property<bool>,
|
||||
|
|
@ -368,11 +368,11 @@ pub struct TouchArea {
|
|||
/// FIXME: there should be just one property for the point instead of two.
|
||||
/// Could even be merged with pressed in a `Property<Option<Point>>` (of course, in the
|
||||
/// implementation item only, for the compiler it would stay separate properties)
|
||||
pub pressed_x: Property<Coord>,
|
||||
pub pressed_y: Property<Coord>,
|
||||
pub pressed_x: Property<LogicalLength>,
|
||||
pub pressed_y: Property<LogicalLength>,
|
||||
/// FIXME: should maybe be as parameter to the mouse event instead. Or at least just one property
|
||||
pub mouse_x: Property<Coord>,
|
||||
pub mouse_y: Property<Coord>,
|
||||
pub mouse_x: Property<LogicalLength>,
|
||||
pub mouse_y: Property<LogicalLength>,
|
||||
pub mouse_cursor: Property<MouseCursor>,
|
||||
pub clicked: Callback<VoidArg>,
|
||||
pub moved: Callback<VoidArg>,
|
||||
|
|
@ -411,8 +411,8 @@ impl Item for TouchArea {
|
|||
return InputEventFilterResult::ForwardAndIgnore;
|
||||
}
|
||||
if let Some(pos) = event.position() {
|
||||
Self::FIELD_OFFSETS.mouse_x.apply_pin(self).set(pos.x);
|
||||
Self::FIELD_OFFSETS.mouse_y.apply_pin(self).set(pos.y);
|
||||
Self::FIELD_OFFSETS.mouse_x.apply_pin(self).set(pos.x_length());
|
||||
Self::FIELD_OFFSETS.mouse_y.apply_pin(self).set(pos.y_length());
|
||||
}
|
||||
let hovering = !matches!(event, MouseEvent::Exit);
|
||||
Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(hovering);
|
||||
|
|
@ -454,8 +454,8 @@ impl Item for TouchArea {
|
|||
MouseEvent::Pressed { position, button } => {
|
||||
self.grabbed.set(true);
|
||||
if button == PointerEventButton::Left {
|
||||
Self::FIELD_OFFSETS.pressed_x.apply_pin(self).set(position.x);
|
||||
Self::FIELD_OFFSETS.pressed_y.apply_pin(self).set(position.y);
|
||||
Self::FIELD_OFFSETS.pressed_x.apply_pin(self).set(position.x_length());
|
||||
Self::FIELD_OFFSETS.pressed_y.apply_pin(self).set(position.y_length());
|
||||
Self::FIELD_OFFSETS.pressed.apply_pin(self).set(true);
|
||||
}
|
||||
Self::FIELD_OFFSETS
|
||||
|
|
@ -544,10 +544,10 @@ declare_item_vtable! {
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct FocusScope {
|
||||
pub x: Property<Coord>,
|
||||
pub y: Property<Coord>,
|
||||
pub width: Property<Coord>,
|
||||
pub height: Property<Coord>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub enabled: Property<bool>,
|
||||
pub has_focus: Property<bool>,
|
||||
pub key_pressed: Callback<KeyEventArg, EventResult>,
|
||||
|
|
@ -664,12 +664,12 @@ declare_item_vtable! {
|
|||
#[pin]
|
||||
/// The implementation of the `Clip` element
|
||||
pub struct Clip {
|
||||
pub x: Property<Coord>,
|
||||
pub y: Property<Coord>,
|
||||
pub width: Property<Coord>,
|
||||
pub height: Property<Coord>,
|
||||
pub border_radius: Property<Coord>,
|
||||
pub border_width: Property<Coord>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub border_radius: Property<LogicalLength>,
|
||||
pub border_width: Property<LogicalLength>,
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
pub clip: Property<bool>,
|
||||
}
|
||||
|
|
@ -762,10 +762,10 @@ declare_item_vtable! {
|
|||
/// The Opacity Item is not meant to be used directly by the .slint code, instead, the `opacity: xxx` or `visible: false` should be used
|
||||
pub struct Opacity {
|
||||
// FIXME: this element shouldn't need these geometry property
|
||||
pub x: Property<Coord>,
|
||||
pub y: Property<Coord>,
|
||||
pub width: Property<Coord>,
|
||||
pub height: Property<Coord>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub opacity: Property<f32>,
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
}
|
||||
|
|
@ -877,10 +877,10 @@ declare_item_vtable! {
|
|||
/// The Layer Item is not meant to be used directly by the .slint code, instead, the `layer: xxx` property should be used
|
||||
pub struct Layer {
|
||||
// FIXME: this element shouldn't need these geometry property
|
||||
pub x: Property<Coord>,
|
||||
pub y: Property<Coord>,
|
||||
pub width: Property<Coord>,
|
||||
pub height: Property<Coord>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub cache_rendering_hint: Property<bool>,
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
}
|
||||
|
|
@ -964,13 +964,13 @@ declare_item_vtable! {
|
|||
#[pin]
|
||||
/// The implementation of the `Rotate` element
|
||||
pub struct Rotate {
|
||||
pub x: Property<Coord>,
|
||||
pub y: Property<Coord>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub rotation_angle: Property<f32>,
|
||||
pub rotation_origin_x: Property<Coord>,
|
||||
pub rotation_origin_y: Property<Coord>,
|
||||
pub width: Property<Coord>,
|
||||
pub height: Property<Coord>,
|
||||
pub rotation_origin_x: Property<LogicalLength>,
|
||||
pub rotation_origin_y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
}
|
||||
|
||||
|
|
@ -1085,14 +1085,14 @@ impl Default for PropertyAnimation {
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct WindowItem {
|
||||
pub width: Property<Coord>,
|
||||
pub height: Property<Coord>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub background: Property<Brush>,
|
||||
pub title: Property<SharedString>,
|
||||
pub no_frame: Property<bool>,
|
||||
pub icon: Property<crate::graphics::Image>,
|
||||
pub default_font_family: Property<SharedString>,
|
||||
pub default_font_size: Property<Coord>,
|
||||
pub default_font_size: Property<LogicalLength>,
|
||||
pub default_font_weight: Property<i32>,
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
}
|
||||
|
|
@ -1204,16 +1204,16 @@ declare_item_vtable! {
|
|||
#[pin]
|
||||
pub struct BoxShadow {
|
||||
// Rectangle properties
|
||||
pub x: Property<Coord>,
|
||||
pub y: Property<Coord>,
|
||||
pub width: Property<Coord>,
|
||||
pub height: Property<Coord>,
|
||||
pub border_radius: Property<Coord>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub border_radius: Property<LogicalLength>,
|
||||
// Shadow specific properties
|
||||
pub offset_x: Property<Coord>,
|
||||
pub offset_y: Property<Coord>,
|
||||
pub offset_x: Property<LogicalLength>,
|
||||
pub offset_y: Property<LogicalLength>,
|
||||
pub color: Property<Color>,
|
||||
pub blur: Property<Coord>,
|
||||
pub blur: Property<LogicalLength>,
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,10 +45,10 @@ use num_traits::Float;
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct Flickable {
|
||||
pub x: Property<Coord>,
|
||||
pub y: Property<Coord>,
|
||||
pub width: Property<Coord>,
|
||||
pub height: Property<Coord>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub viewport: Rectangle,
|
||||
pub interactive: Property<bool>,
|
||||
data: FlickableDataBox,
|
||||
|
|
@ -212,7 +212,7 @@ impl FlickableData {
|
|||
MouseEvent::Pressed { position, button: PointerEventButton::Left } => {
|
||||
inner.pressed_pos = position;
|
||||
inner.pressed_time = Some(crate::animations::current_tick());
|
||||
inner.pressed_viewport_pos = LogicalPoint::new(
|
||||
inner.pressed_viewport_pos = LogicalPoint::from_lengths(
|
||||
(Flickable::FIELD_OFFSETS.viewport + Rectangle::FIELD_OFFSETS.x)
|
||||
.apply_pin(flick)
|
||||
.get(),
|
||||
|
|
@ -241,16 +241,16 @@ impl FlickableData {
|
|||
if crate::animations::current_tick() - pressed_time > DURATION_THRESHOLD {
|
||||
return false;
|
||||
}
|
||||
let can_move_horiz = LogicalLength::new(
|
||||
(Flickable::FIELD_OFFSETS.viewport + Rectangle::FIELD_OFFSETS.width)
|
||||
.apply_pin(flick)
|
||||
.get(),
|
||||
) > flick.width();
|
||||
let can_move_vert = LogicalLength::new(
|
||||
(Flickable::FIELD_OFFSETS.viewport + Rectangle::FIELD_OFFSETS.height)
|
||||
.apply_pin(flick)
|
||||
.get(),
|
||||
) > flick.height();
|
||||
let can_move_horiz = (Flickable::FIELD_OFFSETS.viewport
|
||||
+ Rectangle::FIELD_OFFSETS.width)
|
||||
.apply_pin(flick)
|
||||
.get()
|
||||
> flick.width();
|
||||
let can_move_vert = (Flickable::FIELD_OFFSETS.viewport
|
||||
+ Rectangle::FIELD_OFFSETS.height)
|
||||
.apply_pin(flick)
|
||||
.get()
|
||||
> flick.height();
|
||||
let diff = position - inner.pressed_pos;
|
||||
(can_move_horiz && diff.x.abs() > DISTANCE_THRESHOLD)
|
||||
|| (can_move_vert && diff.y.abs() > DISTANCE_THRESHOLD)
|
||||
|
|
@ -293,10 +293,10 @@ impl FlickableData {
|
|||
);
|
||||
(Flickable::FIELD_OFFSETS.viewport + Rectangle::FIELD_OFFSETS.x)
|
||||
.apply_pin(flick)
|
||||
.set(new_pos.x);
|
||||
.set(new_pos.x_length());
|
||||
(Flickable::FIELD_OFFSETS.viewport + Rectangle::FIELD_OFFSETS.y)
|
||||
.apply_pin(flick)
|
||||
.set(new_pos.y);
|
||||
.set(new_pos.y_length());
|
||||
InputEventResult::GrabMouse
|
||||
} else {
|
||||
inner.capture_events = false;
|
||||
|
|
@ -304,7 +304,7 @@ impl FlickableData {
|
|||
}
|
||||
}
|
||||
MouseEvent::Wheel { delta_x, delta_y, .. } => {
|
||||
let old_pos = LogicalPoint::new(
|
||||
let old_pos = LogicalPoint::from_lengths(
|
||||
(Flickable::FIELD_OFFSETS.viewport + Rectangle::FIELD_OFFSETS.x)
|
||||
.apply_pin(flick)
|
||||
.get(),
|
||||
|
|
@ -318,10 +318,10 @@ impl FlickableData {
|
|||
);
|
||||
(Flickable::FIELD_OFFSETS.viewport + Rectangle::FIELD_OFFSETS.x)
|
||||
.apply_pin(flick)
|
||||
.set(new_pos.x);
|
||||
.set(new_pos.x_length());
|
||||
(Flickable::FIELD_OFFSETS.viewport + Rectangle::FIELD_OFFSETS.y)
|
||||
.apply_pin(flick)
|
||||
.set(new_pos.y);
|
||||
.set(new_pos.y_length());
|
||||
InputEventResult::EventAccepted
|
||||
}
|
||||
}
|
||||
|
|
@ -348,10 +348,10 @@ impl FlickableData {
|
|||
};
|
||||
(Flickable::FIELD_OFFSETS.viewport + Rectangle::FIELD_OFFSETS.x)
|
||||
.apply_pin(flick)
|
||||
.set_animated_value(final_pos.x, anim.clone());
|
||||
.set_animated_value(final_pos.x_length(), anim.clone());
|
||||
(Flickable::FIELD_OFFSETS.viewport + Rectangle::FIELD_OFFSETS.y)
|
||||
.apply_pin(flick)
|
||||
.set_animated_value(final_pos.y, anim);
|
||||
.set_animated_value(final_pos.y_length(), anim);
|
||||
}
|
||||
}
|
||||
inner.capture_events = false; // FIXME: should only be set to false once the flick animation is over
|
||||
|
|
@ -363,14 +363,11 @@ impl FlickableData {
|
|||
fn ensure_in_bound(flick: Pin<&Flickable>, p: LogicalPoint) -> LogicalPoint {
|
||||
let w = flick.width();
|
||||
let h = flick.height();
|
||||
let vw = LogicalLength::new(
|
||||
(Flickable::FIELD_OFFSETS.viewport + Rectangle::FIELD_OFFSETS.width).apply_pin(flick).get(),
|
||||
);
|
||||
let vh = LogicalLength::new(
|
||||
(Flickable::FIELD_OFFSETS.viewport + Rectangle::FIELD_OFFSETS.height)
|
||||
.apply_pin(flick)
|
||||
.get(),
|
||||
);
|
||||
let vw =
|
||||
(Flickable::FIELD_OFFSETS.viewport + Rectangle::FIELD_OFFSETS.width).apply_pin(flick).get();
|
||||
let vh = (Flickable::FIELD_OFFSETS.viewport + Rectangle::FIELD_OFFSETS.height)
|
||||
.apply_pin(flick)
|
||||
.get();
|
||||
|
||||
let min = LogicalPoint::from_lengths(w - vw, h - vh);
|
||||
let max = LogicalPoint::default();
|
||||
|
|
|
|||
|
|
@ -31,10 +31,10 @@ use i_slint_core_macros::*;
|
|||
/// The implementation of the `Image` element
|
||||
pub struct ImageItem {
|
||||
pub source: Property<crate::graphics::Image>,
|
||||
pub x: Property<Coord>,
|
||||
pub y: Property<Coord>,
|
||||
pub width: Property<Coord>,
|
||||
pub height: Property<Coord>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub image_fit: Property<ImageFit>,
|
||||
pub image_rendering: Property<ImageRendering>,
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
|
|
@ -127,10 +127,10 @@ impl ItemConsts for ImageItem {
|
|||
/// The implementation of the `ClippedImage` element
|
||||
pub struct ClippedImage {
|
||||
pub source: Property<crate::graphics::Image>,
|
||||
pub x: Property<Coord>,
|
||||
pub y: Property<Coord>,
|
||||
pub width: Property<Coord>,
|
||||
pub height: Property<Coord>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub image_fit: Property<ImageFit>,
|
||||
pub image_rendering: Property<ImageRendering>,
|
||||
pub colorize: Property<Brush>,
|
||||
|
|
|
|||
|
|
@ -35,15 +35,15 @@ use i_slint_core_macros::*;
|
|||
#[derive(FieldOffsets, Default, SlintElement)]
|
||||
#[pin]
|
||||
pub struct Path {
|
||||
pub x: Property<Coord>,
|
||||
pub y: Property<Coord>,
|
||||
pub width: Property<Coord>,
|
||||
pub height: Property<Coord>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub elements: Property<PathData>,
|
||||
pub fill: Property<Brush>,
|
||||
pub fill_rule: Property<FillRule>,
|
||||
pub stroke: Property<Brush>,
|
||||
pub stroke_width: Property<Coord>,
|
||||
pub stroke_width: Property<LogicalLength>,
|
||||
pub viewbox_x: Property<f32>,
|
||||
pub viewbox_y: Property<f32>,
|
||||
pub viewbox_width: Property<f32>,
|
||||
|
|
|
|||
|
|
@ -41,18 +41,18 @@ use unicode_segmentation::UnicodeSegmentation;
|
|||
pub struct Text {
|
||||
pub text: Property<SharedString>,
|
||||
pub font_family: Property<SharedString>,
|
||||
pub font_size: Property<Coord>,
|
||||
pub font_size: Property<LogicalLength>,
|
||||
pub font_weight: Property<i32>,
|
||||
pub color: Property<Brush>,
|
||||
pub horizontal_alignment: Property<TextHorizontalAlignment>,
|
||||
pub vertical_alignment: Property<TextVerticalAlignment>,
|
||||
pub wrap: Property<TextWrap>,
|
||||
pub overflow: Property<TextOverflow>,
|
||||
pub letter_spacing: Property<Coord>,
|
||||
pub x: Property<Coord>,
|
||||
pub y: Property<Coord>,
|
||||
pub width: Property<Coord>,
|
||||
pub height: Property<Coord>,
|
||||
pub letter_spacing: Property<LogicalLength>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
}
|
||||
|
||||
|
|
@ -213,7 +213,7 @@ impl Text {
|
|||
pub struct TextInput {
|
||||
pub text: Property<SharedString>,
|
||||
pub font_family: Property<SharedString>,
|
||||
pub font_size: Property<Coord>,
|
||||
pub font_size: Property<LogicalLength>,
|
||||
pub font_weight: Property<i32>,
|
||||
pub color: Property<Brush>,
|
||||
pub selection_foreground_color: Property<Color>,
|
||||
|
|
@ -222,14 +222,14 @@ pub struct TextInput {
|
|||
pub vertical_alignment: Property<TextVerticalAlignment>,
|
||||
pub wrap: Property<TextWrap>,
|
||||
pub input_type: Property<InputType>,
|
||||
pub letter_spacing: Property<Coord>,
|
||||
pub x: Property<Coord>,
|
||||
pub y: Property<Coord>,
|
||||
pub width: Property<Coord>,
|
||||
pub height: Property<Coord>,
|
||||
pub letter_spacing: Property<LogicalLength>,
|
||||
pub x: Property<LogicalLength>,
|
||||
pub y: Property<LogicalLength>,
|
||||
pub width: Property<LogicalLength>,
|
||||
pub height: Property<LogicalLength>,
|
||||
pub cursor_position: Property<i32>, // byte offset,
|
||||
pub anchor_position: Property<i32>, // byte offset
|
||||
pub text_cursor_width: Property<Coord>,
|
||||
pub text_cursor_width: Property<LogicalLength>,
|
||||
pub cursor_visible: Property<bool>,
|
||||
pub has_focus: Property<bool>,
|
||||
pub enabled: Property<bool>,
|
||||
|
|
|
|||
|
|
@ -9,12 +9,14 @@ use crate::component::ComponentVTable;
|
|||
use crate::item_tree::TraversalOrder;
|
||||
use crate::items::ItemRef;
|
||||
use crate::layout::Orientation;
|
||||
use crate::lengths::{LogicalLength, RectLengths};
|
||||
use crate::{Coord, Property, SharedString, SharedVector};
|
||||
pub use adapters::{FilterModel, MapModel, SortModel};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use core::cell::{Cell, RefCell};
|
||||
use core::pin::Pin;
|
||||
use euclid::num::Zero;
|
||||
#[allow(unused)]
|
||||
use euclid::num::{Ceil, Floor};
|
||||
pub use model_peer::*;
|
||||
|
|
@ -608,8 +610,8 @@ pub trait RepeatedComponent:
|
|||
/// it should be updated to be to the y position of the next item.
|
||||
fn listview_layout(
|
||||
self: Pin<&Self>,
|
||||
_offset_y: &mut Coord,
|
||||
_viewport_width: Pin<&Property<Coord>>,
|
||||
_offset_y: &mut LogicalLength,
|
||||
_viewport_width: Pin<&Property<LogicalLength>>,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -636,12 +638,12 @@ struct RepeaterInner<C: RepeatedComponent> {
|
|||
/// The model row (index) of the first component in the `components` vector.
|
||||
offset: usize,
|
||||
/// The average visible item height.
|
||||
cached_item_height: Coord,
|
||||
cached_item_height: LogicalLength,
|
||||
/// The viewport_y last time the layout of the ListView was done
|
||||
previous_viewport_y: Coord,
|
||||
previous_viewport_y: LogicalLength,
|
||||
/// the position of the item in the row `offset` (which corresponds to `components[0]`).
|
||||
/// We will try to keep this constant when re-layouting items
|
||||
anchor_y: Coord,
|
||||
anchor_y: LogicalLength,
|
||||
}
|
||||
|
||||
impl<C: RepeatedComponent> Default for RepeaterInner<C> {
|
||||
|
|
@ -816,36 +818,36 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
|
|||
pub fn ensure_updated_listview(
|
||||
self: Pin<&Self>,
|
||||
init: impl Fn() -> ComponentRc<C>,
|
||||
viewport_width: Pin<&Property<Coord>>,
|
||||
viewport_height: Pin<&Property<Coord>>,
|
||||
viewport_y: Pin<&Property<Coord>>,
|
||||
listview_width: Coord,
|
||||
listview_height: Pin<&Property<Coord>>,
|
||||
viewport_width: Pin<&Property<LogicalLength>>,
|
||||
viewport_height: Pin<&Property<LogicalLength>>,
|
||||
viewport_y: Pin<&Property<LogicalLength>>,
|
||||
listview_width: LogicalLength,
|
||||
listview_height: Pin<&Property<LogicalLength>>,
|
||||
) {
|
||||
viewport_width.set(listview_width);
|
||||
let model = self.model();
|
||||
let row_count = model.row_count();
|
||||
if row_count == 0 {
|
||||
self.0.inner.borrow_mut().components.clear();
|
||||
viewport_height.set(0 as _);
|
||||
viewport_y.set(0 as _);
|
||||
viewport_height.set(LogicalLength::zero());
|
||||
viewport_y.set(LogicalLength::zero());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let listview_height = listview_height.get();
|
||||
let mut vp_y = viewport_y.get().min(0 as _);
|
||||
let mut vp_y = viewport_y.get().min(LogicalLength::zero());
|
||||
|
||||
// We need some sort of estimation of the element height
|
||||
let cached_item_height = self.data().inner.borrow_mut().cached_item_height;
|
||||
let element_height = if cached_item_height > 0 as Coord {
|
||||
let element_height = if cached_item_height > LogicalLength::zero() {
|
||||
cached_item_height
|
||||
} else {
|
||||
let total_height = Cell::new(0 as Coord);
|
||||
let total_height = Cell::new(LogicalLength::zero());
|
||||
let count = Cell::new(0);
|
||||
let get_height_visitor = |item: Pin<ItemRef>| {
|
||||
count.set(count.get() + 1);
|
||||
let height = item.as_ref().geometry().height();
|
||||
let height = item.as_ref().geometry().height_length();
|
||||
total_height.set(total_height.get() + height);
|
||||
};
|
||||
for c in self.data().inner.borrow().components.iter() {
|
||||
|
|
@ -879,14 +881,14 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
|
|||
let mut inner = data.inner.borrow_mut();
|
||||
let one_and_a_half_screen = listview_height * 3 as Coord / 2 as Coord;
|
||||
let first_item_y = inner.anchor_y;
|
||||
let last_item_bottom = first_item_y + inner.components.len() as Coord * element_height;
|
||||
let last_item_bottom = first_item_y + element_height * inner.components.len() as Coord;
|
||||
|
||||
let (mut new_offset, mut new_offset_y) = if first_item_y > -vp_y + one_and_a_half_screen
|
||||
|| last_item_bottom + element_height < -vp_y
|
||||
{
|
||||
// We are jumping more than 1.5 screens, consider this as a random seek.
|
||||
inner.components.clear();
|
||||
inner.offset = ((-vp_y / element_height).floor() as usize).min(row_count - 1);
|
||||
inner.offset = ((-vp_y / element_height).get().floor() as usize).min(row_count - 1);
|
||||
(inner.offset, -vp_y)
|
||||
} else if vp_y < inner.previous_viewport_y {
|
||||
// we scrolled down, try to find out the new offset.
|
||||
|
|
@ -902,7 +904,13 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
|
|||
c.0 = RepeatedComponentState::Clean;
|
||||
}
|
||||
let h =
|
||||
c.1.as_ref().unwrap().as_pin_ref().get_item_ref(0).as_ref().geometry().height();
|
||||
c.1.as_ref()
|
||||
.unwrap()
|
||||
.as_pin_ref()
|
||||
.get_item_ref(0)
|
||||
.as_ref()
|
||||
.geometry()
|
||||
.height_length();
|
||||
if it_y + h >= -vp_y || new_offset + 1 >= row_count {
|
||||
break;
|
||||
}
|
||||
|
|
@ -929,7 +937,7 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
|
|||
.get_item_ref(0)
|
||||
.as_ref()
|
||||
.geometry()
|
||||
.height();
|
||||
.height_length();
|
||||
}
|
||||
// If there is still a gap, fill it with new component before
|
||||
let mut new_components = Vec::new();
|
||||
|
|
@ -938,7 +946,7 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
|
|||
let new_component = init();
|
||||
new_component.update(new_offset, model.row_data(new_offset).unwrap());
|
||||
new_offset_y -=
|
||||
new_component.as_pin_ref().get_item_ref(0).as_ref().geometry().height();
|
||||
new_component.as_pin_ref().get_item_ref(0).as_ref().geometry().height_length();
|
||||
new_components.push(new_component);
|
||||
}
|
||||
if !new_components.is_empty() {
|
||||
|
|
@ -984,7 +992,7 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
|
|||
inner.components.push((RepeatedComponentState::Clean, Some(new_component)));
|
||||
idx += 1;
|
||||
}
|
||||
if y < -vp_y + listview_height && vp_y < 0 as Coord {
|
||||
if y < -vp_y + listview_height && vp_y < LogicalLength::zero() {
|
||||
assert!(idx >= row_count);
|
||||
// we reached the end of the model, and we still have room. scroll a bit up.
|
||||
vp_y = listview_height - y;
|
||||
|
|
@ -1003,7 +1011,7 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
|
|||
|
||||
// Now re-compute some coordinate such a way that the scrollbar are adjusted.
|
||||
inner.cached_item_height = (y - new_offset_y) / inner.components.len() as Coord;
|
||||
inner.anchor_y = inner.offset as Coord * inner.cached_item_height;
|
||||
inner.anchor_y = inner.cached_item_height * inner.offset as Coord;
|
||||
viewport_height.set(inner.cached_item_height * row_count as Coord);
|
||||
let new_viewport_y = -inner.anchor_y + vp_y + new_offset_y;
|
||||
viewport_y.set(new_viewport_y);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
use super::*;
|
||||
use crate::items::PropertyAnimation;
|
||||
use crate::{items::PropertyAnimation, lengths::LogicalLength};
|
||||
|
||||
enum AnimationState {
|
||||
Delaying,
|
||||
|
|
@ -200,6 +200,12 @@ impl InterpolatedPropertyValue for u8 {
|
|||
}
|
||||
}
|
||||
|
||||
impl InterpolatedPropertyValue for LogicalLength {
|
||||
fn interpolate(&self, target_value: &Self, t: f32) -> Self {
|
||||
LogicalLength::new(self.get().interpolate(&target_value.get(), t))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + InterpolatedPropertyValue + 'static> Property<T> {
|
||||
/// Change the value of this property, by animating (interpolating) from the current property's value
|
||||
/// to the specified parameter value. The animation is done according to the parameters described by
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ macro_rules! declare_ValueType_2 {
|
|||
crate::Brush,
|
||||
crate::graphics::Point,
|
||||
crate::items::PointerEvent,
|
||||
crate::lengths::LogicalLength,
|
||||
$(crate::items::$Name,)*
|
||||
];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use crate::input::{
|
|||
};
|
||||
use crate::item_tree::ItemRc;
|
||||
use crate::items::{ItemRef, MouseCursor};
|
||||
use crate::lengths::{LogicalLength, LogicalPoint, LogicalSize};
|
||||
use crate::lengths::{LogicalLength, LogicalPoint, LogicalSize, SizeLengths};
|
||||
use crate::properties::{Property, PropertyTracker};
|
||||
use crate::renderer::Renderer;
|
||||
use crate::Callback;
|
||||
|
|
@ -621,8 +621,8 @@ impl WindowInner {
|
|||
crate::items::WindowItem::FIELD_OFFSETS.width.apply_pin(window_item);
|
||||
let height_property =
|
||||
crate::items::WindowItem::FIELD_OFFSETS.height.apply_pin(window_item);
|
||||
width_property.set(size.width);
|
||||
height_property.set(size.height);
|
||||
width_property.set(size.width_length());
|
||||
height_property.set(size.height_length());
|
||||
};
|
||||
|
||||
let location = match self
|
||||
|
|
@ -690,8 +690,8 @@ impl WindowInner {
|
|||
let root_item = component.as_ref().get_item_ref(0);
|
||||
if let Some(window_item) = ItemRef::downcast_pin::<crate::items::WindowItem>(root_item)
|
||||
{
|
||||
window_item.width.set(size.width);
|
||||
window_item.height.set(size.height);
|
||||
window_item.width.set(size.width_length());
|
||||
window_item.height.set(size.height_length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -350,6 +350,23 @@ impl TryFrom<Value> for i_slint_core::Color {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<i_slint_core::lengths::LogicalLength> for Value {
|
||||
#[inline]
|
||||
fn from(l: i_slint_core::lengths::LogicalLength) -> Self {
|
||||
Value::Number(l.get() as _)
|
||||
}
|
||||
}
|
||||
impl TryFrom<Value> for i_slint_core::lengths::LogicalLength {
|
||||
type Error = Value;
|
||||
#[inline]
|
||||
fn try_from(v: Value) -> Result<i_slint_core::lengths::LogicalLength, Self::Error> {
|
||||
match v {
|
||||
Value::Number(n) => Ok(i_slint_core::lengths::LogicalLength::new(n as _)),
|
||||
_ => Err(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Normalize the identifier to use dashes
|
||||
pub(crate) fn normalize_identifier(ident: &str) -> Cow<'_, str> {
|
||||
if ident.contains('_') {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ use i_slint_core::item_tree::{
|
|||
};
|
||||
use i_slint_core::items::{AccessibleRole, Flickable, ItemRef, ItemVTable, PropertyAnimation};
|
||||
use i_slint_core::layout::{BoxLayoutCellData, LayoutInfo, Orientation};
|
||||
use i_slint_core::lengths::LogicalLength;
|
||||
use i_slint_core::model::RepeatedComponent;
|
||||
use i_slint_core::model::Repeater;
|
||||
use i_slint_core::properties::InterpolatedPropertyValue;
|
||||
|
|
@ -110,12 +111,16 @@ impl RepeatedComponent for ErasedComponentBox {
|
|||
s.component_type.set_property(s.borrow(), "model_data", data).unwrap();
|
||||
}
|
||||
|
||||
fn listview_layout(self: Pin<&Self>, offset_y: &mut f32, viewport_width: Pin<&Property<f32>>) {
|
||||
fn listview_layout(
|
||||
self: Pin<&Self>,
|
||||
offset_y: &mut LogicalLength,
|
||||
viewport_width: Pin<&Property<LogicalLength>>,
|
||||
) {
|
||||
generativity::make_guard!(guard);
|
||||
let s = self.unerase(guard);
|
||||
|
||||
s.component_type
|
||||
.set_property(s.borrow(), "y", Value::Number(*offset_y as f64))
|
||||
.set_property(s.borrow(), "y", Value::Number(offset_y.get() as f64))
|
||||
.expect("cannot set y");
|
||||
let h: f32 = s
|
||||
.component_type
|
||||
|
|
@ -129,6 +134,8 @@ impl RepeatedComponent for ErasedComponentBox {
|
|||
.expect("missing width")
|
||||
.try_into()
|
||||
.expect("width not the right type");
|
||||
let h = LogicalLength::new(h);
|
||||
let w = LogicalLength::new(w);
|
||||
*offset_y += h;
|
||||
let vp_w = viewport_width.get();
|
||||
if vp_w < w {
|
||||
|
|
@ -674,18 +681,18 @@ fn ensure_repeater_updated<'id>(
|
|||
.unwrap()
|
||||
.is_listview
|
||||
{
|
||||
let assume_property_f32 =
|
||||
|prop| unsafe { Pin::new_unchecked(&*(prop as *const Property<f32>)) };
|
||||
let get_prop = |nr: &NamedReference| -> f32 {
|
||||
let assume_property_logical_length =
|
||||
|prop| unsafe { Pin::new_unchecked(&*(prop as *const Property<LogicalLength>)) };
|
||||
let get_prop = |nr: &NamedReference| -> LogicalLength {
|
||||
eval::load_property(instance_ref, &nr.element(), nr.name()).unwrap().try_into().unwrap()
|
||||
};
|
||||
repeater.ensure_updated_listview(
|
||||
init,
|
||||
assume_property_f32(get_property_ptr(&lv.viewport_width, instance_ref)),
|
||||
assume_property_f32(get_property_ptr(&lv.viewport_height, instance_ref)),
|
||||
assume_property_f32(get_property_ptr(&lv.viewport_y, instance_ref)),
|
||||
assume_property_logical_length(get_property_ptr(&lv.viewport_width, instance_ref)),
|
||||
assume_property_logical_length(get_property_ptr(&lv.viewport_height, instance_ref)),
|
||||
assume_property_logical_length(get_property_ptr(&lv.viewport_y, instance_ref)),
|
||||
get_prop(&lv.listview_width),
|
||||
assume_property_f32(get_property_ptr(&lv.listview_height, instance_ref)),
|
||||
assume_property_logical_length(get_property_ptr(&lv.listview_height, instance_ref)),
|
||||
);
|
||||
} else {
|
||||
repeater.ensure_updated(init);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue