iced: Allow rendering at a higher native scale than it's output

This commit is contained in:
Victoria Brekenfeld 2025-02-14 18:34:12 +01:00 committed by Victoria Brekenfeld
parent f72d2b91f3
commit 24b5742554

View file

@ -152,6 +152,7 @@ impl<P: Program> IcedProgram for ProgramWrapper<P> {
pub(crate) struct IcedElementInternal<P: Program + Send + 'static> { pub(crate) struct IcedElementInternal<P: Program + Send + 'static> {
// draw buffer // draw buffer
additional_scale: f64,
outputs: HashSet<Output>, outputs: HashSet<Output>,
buffers: HashMap<OrderedFloat<f64>, (MemoryRenderBuffer, Option<(Vec<Layer>, Color)>)>, buffers: HashMap<OrderedFloat<f64>, (MemoryRenderBuffer, Option<(Vec<Layer>, Color)>)>,
pending_update: Option<Instant>, pending_update: Option<Instant>,
@ -204,6 +205,7 @@ impl<P: Program + Send + Clone + 'static> Clone for IcedElementInternal<P> {
); );
IcedElementInternal { IcedElementInternal {
additional_scale: self.additional_scale,
outputs: self.outputs.clone(), outputs: self.outputs.clone(),
buffers: self.buffers.clone(), buffers: self.buffers.clone(),
pending_update: self.pending_update.clone(), pending_update: self.pending_update.clone(),
@ -226,10 +228,17 @@ impl<P: Program + Send + Clone + 'static> Clone for IcedElementInternal<P> {
impl<P: Program + Send + 'static> fmt::Debug for IcedElementInternal<P> { impl<P: Program + Send + 'static> fmt::Debug for IcedElementInternal<P> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IcedElementInternal") f.debug_struct("IcedElementInternal")
.field("additional_scale", &self.additional_scale)
.field(
"outputs",
&self.outputs.iter().map(|o| o.name()).collect::<Vec<_>>(),
)
.field("buffers", &"...") .field("buffers", &"...")
.field("size", &self.size) .field("size", &self.size)
.field("pending_update", &self.pending_update) .field("pending_update", &self.pending_update)
.field("last_seat", &self.last_seat)
.field("cursor_pos", &self.cursor_pos) .field("cursor_pos", &self.cursor_pos)
.field("touch_map", &self.touch_map)
.field("theme", &"...") .field("theme", &"...")
.field("renderer", &"...") .field("renderer", &"...")
.field("state", &"...") .field("state", &"...")
@ -281,6 +290,7 @@ impl<P: Program + Send + 'static> IcedElement<P> {
.ok(); .ok();
let mut internal = IcedElementInternal { let mut internal = IcedElementInternal {
additional_scale: 1.0,
outputs: HashSet::new(), outputs: HashSet::new(),
buffers: HashMap::new(), buffers: HashMap::new(),
pending_update: None, pending_update: None,
@ -352,6 +362,19 @@ impl<P: Program + Send + 'static> IcedElement<P> {
} }
} }
pub fn set_additional_scale(&self, scale: f64) {
{
let mut internal = self.0.lock().unwrap();
let internal_ref = &mut *internal;
if internal_ref.additional_scale == scale {
return;
}
internal_ref.additional_scale = scale;
}
self.refresh();
}
pub fn force_update(&self) { pub fn force_update(&self) {
self.0.lock().unwrap().update(true); self.0.lock().unwrap().update(true);
} }
@ -370,7 +393,12 @@ impl<P: Program + Send + 'static> IcedElement<P> {
} }
pub fn current_size(&self) -> Size<i32, Logical> { pub fn current_size(&self) -> Size<i32, Logical> {
self.0.lock().unwrap().size let internal = self.0.lock().unwrap();
internal
.size
.to_f64()
.upscale(internal.additional_scale)
.to_i32_round()
} }
pub fn queue_message(&self, msg: P::Message) { pub fn queue_message(&self, msg: P::Message) {
@ -405,6 +433,7 @@ impl<P: Program + Send + 'static> IcedElementInternal<P> {
.map(|p| IcedPoint::new(p.x as f32, p.y as f32)) .map(|p| IcedPoint::new(p.x as f32, p.y as f32))
.map(Cursor::Available) .map(Cursor::Available)
.unwrap_or(Cursor::Unavailable); .unwrap_or(Cursor::Unavailable);
let actions = self let actions = self
.state .state
.update( .update(
@ -446,12 +475,13 @@ impl<P: Program + Send + 'static> PointerTarget<crate::state::State> for IcedEle
internal internal
.state .state
.queue_event(Event::Mouse(MouseEvent::CursorEntered)); .queue_event(Event::Mouse(MouseEvent::CursorEntered));
let position = IcedPoint::new(event.location.x as f32, event.location.y as f32); let event_location = event.location.downscale(internal.additional_scale);
let position = IcedPoint::new(event_location.x as f32, event_location.y as f32);
internal internal
.state .state
.queue_event(Event::Mouse(MouseEvent::CursorMoved { position })); .queue_event(Event::Mouse(MouseEvent::CursorMoved { position }));
// TODO: Update iced widgets to handle touch using event position, not cursor_pos // TODO: Update iced widgets to handle touch using event position, not cursor_pos
internal.cursor_pos = Some(event.location); internal.cursor_pos = Some(event_location);
*internal.last_seat.lock().unwrap() = Some((seat.clone(), event.serial)); *internal.last_seat.lock().unwrap() = Some((seat.clone(), event.serial));
let _ = internal.update(true); let _ = internal.update(true);
} }
@ -463,11 +493,12 @@ impl<P: Program + Send + 'static> PointerTarget<crate::state::State> for IcedEle
event: &MotionEvent, event: &MotionEvent,
) { ) {
let mut internal = self.0.lock().unwrap(); let mut internal = self.0.lock().unwrap();
let position = IcedPoint::new(event.location.x as f32, event.location.y as f32); let event_location = event.location.downscale(internal.additional_scale);
let position = IcedPoint::new(event_location.x as f32, event_location.y as f32);
internal internal
.state .state
.queue_event(Event::Mouse(MouseEvent::CursorMoved { position })); .queue_event(Event::Mouse(MouseEvent::CursorMoved { position }));
internal.cursor_pos = Some(event.location); internal.cursor_pos = Some(event_location);
*internal.last_seat.lock().unwrap() = Some((seat.clone(), event.serial)); *internal.last_seat.lock().unwrap() = Some((seat.clone(), event.serial));
let _ = internal.update(true); let _ = internal.update(true);
} }
@ -610,12 +641,13 @@ impl<P: Program + Send + 'static> TouchTarget<crate::state::State> for IcedEleme
) { ) {
let mut internal = self.0.lock().unwrap(); let mut internal = self.0.lock().unwrap();
let id = Finger(i32::from(event.slot) as u64); let id = Finger(i32::from(event.slot) as u64);
let position = IcedPoint::new(event.location.x as f32, event.location.y as f32); let event_location = event.location.downscale(internal.additional_scale);
let position = IcedPoint::new(event_location.x as f32, event_location.y as f32);
internal internal
.state .state
.queue_event(Event::Touch(TouchEvent::FingerPressed { id, position })); .queue_event(Event::Touch(TouchEvent::FingerPressed { id, position }));
internal.touch_map.insert(id, position); internal.touch_map.insert(id, position);
internal.cursor_pos = Some(event.location); internal.cursor_pos = Some(event_location);
*internal.last_seat.lock().unwrap() = Some((seat.clone(), seq)); *internal.last_seat.lock().unwrap() = Some((seat.clone(), seq));
let _ = internal.update(true); let _ = internal.update(true);
} }
@ -647,13 +679,14 @@ impl<P: Program + Send + 'static> TouchTarget<crate::state::State> for IcedEleme
) { ) {
let mut internal = self.0.lock().unwrap(); let mut internal = self.0.lock().unwrap();
let id = Finger(i32::from(event.slot) as u64); let id = Finger(i32::from(event.slot) as u64);
let position = IcedPoint::new(event.location.x as f32, event.location.y as f32); let event_location = event.location.downscale(internal.additional_scale);
let position = IcedPoint::new(event_location.x as f32, event_location.y as f32);
*internal.last_seat.lock().unwrap() = Some((seat.clone(), seq)); *internal.last_seat.lock().unwrap() = Some((seat.clone(), seq));
internal internal
.state .state
.queue_event(Event::Touch(TouchEvent::FingerMoved { id, position })); .queue_event(Event::Touch(TouchEvent::FingerMoved { id, position }));
internal.touch_map.insert(id, position); internal.touch_map.insert(id, position);
internal.cursor_pos = Some(event.location); internal.cursor_pos = Some(event_location);
let _ = internal.update(true); let _ = internal.update(true);
} }
@ -767,7 +800,14 @@ impl<P: Program + Send + 'static> IsAlive for IcedElement<P> {
impl<P: Program + Send + 'static> SpaceElement for IcedElement<P> { impl<P: Program + Send + 'static> SpaceElement for IcedElement<P> {
fn bbox(&self) -> Rectangle<i32, Logical> { fn bbox(&self) -> Rectangle<i32, Logical> {
Rectangle::from_size(self.0.lock().unwrap().size) let internal = self.0.lock().unwrap();
Rectangle::from_size(
internal
.size
.to_f64()
.upscale(internal.additional_scale)
.to_i32_round(),
)
} }
fn is_in_input_region(&self, _point: &Point<f64, Logical>) -> bool { fn is_in_input_region(&self, _point: &Point<f64, Logical>) -> bool {
@ -786,7 +826,7 @@ impl<P: Program + Send + 'static> SpaceElement for IcedElement<P> {
fn output_enter(&self, output: &Output, _overlap: Rectangle<i32, Logical>) { fn output_enter(&self, output: &Output, _overlap: Rectangle<i32, Logical>) {
let mut internal = self.0.lock().unwrap(); let mut internal = self.0.lock().unwrap();
let scale = output.current_scale().fractional_scale(); let scale = output.current_scale().fractional_scale() * internal.additional_scale;
let internal_size = internal.size; let internal_size = internal.size;
internal.buffers.entry(OrderedFloat(scale)).or_insert({ internal.buffers.entry(OrderedFloat(scale)).or_insert({
@ -820,15 +860,16 @@ impl<P: Program + Send + 'static> SpaceElement for IcedElement<P> {
// makes partial borrows easier // makes partial borrows easier
let internal_ref = &mut *internal; let internal_ref = &mut *internal;
internal_ref.buffers.retain(|scale, _| { internal_ref.buffers.retain(|scale, _| {
internal_ref internal_ref.outputs.iter().any(|o| {
.outputs o.current_scale().fractional_scale() * internal_ref.additional_scale == **scale
.iter() })
.any(|o| o.current_scale().fractional_scale() == **scale)
}); });
for scale in internal_ref for scale in internal_ref
.outputs .outputs
.iter() .iter()
.map(|o| OrderedFloat(o.current_scale().fractional_scale())) .map(|o| {
OrderedFloat(o.current_scale().fractional_scale() * internal_ref.additional_scale)
})
.filter(|scale| !internal_ref.buffers.contains_key(scale)) .filter(|scale| !internal_ref.buffers.contains_key(scale))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_iter() .into_iter()
@ -868,7 +909,7 @@ where
&self, &self,
renderer: &mut R, renderer: &mut R,
location: Point<i32, Physical>, location: Point<i32, Physical>,
scale: Scale<f64>, mut scale: Scale<f64>,
alpha: f32, alpha: f32,
) -> Vec<C> { ) -> Vec<C> {
let mut internal = self.0.lock().unwrap(); let mut internal = self.0.lock().unwrap();
@ -886,6 +927,8 @@ where
internal_ref.pending_update = None; internal_ref.pending_update = None;
} }
let _ = internal_ref.update(force); let _ = internal_ref.update(force);
scale = scale * internal_ref.additional_scale;
if let Some((buffer, ref mut old_layers)) = if let Some((buffer, ref mut old_layers)) =
internal_ref.buffers.get_mut(&OrderedFloat(scale.x)) internal_ref.buffers.get_mut(&OrderedFloat(scale.x))
{ {
@ -988,7 +1031,13 @@ where
.to_logical(1., Transform::Normal) .to_logical(1., Transform::Normal)
.to_i32_round(), .to_i32_round(),
)), )),
Some(internal_ref.size), Some(
internal_ref
.size
.to_f64()
.upscale(internal_ref.additional_scale)
.to_i32_round(),
),
Kind::Unspecified, Kind::Unspecified,
) { ) {
return vec![C::from(buffer)]; return vec![C::from(buffer)];