feat: add popup positioning

This commit is contained in:
drendog 2025-10-31 23:47:35 +01:00
parent 18d1391dee
commit ec08429413
Signed by: dwenya
GPG key ID: 8DD77074645332D0
5 changed files with 77 additions and 15 deletions

View file

@ -5,7 +5,10 @@ pub mod rendering;
pub mod wayland;
pub use rendering::femtovg::popup_window::PopupWindow;
pub use rendering::slint_integration::platform::close_current_popup;
pub use rendering::slint_integration::platform::{
clear_popup_position_override, close_current_popup, get_popup_position_override,
set_popup_position_override,
};
pub mod platform {
pub use slint;

View file

@ -24,11 +24,41 @@ pub fn close_current_popup() {
});
}
pub fn set_popup_position_override(x: f32, y: f32) {
CURRENT_PLATFORM.with(|platform| {
if let Some(weak_platform) = platform.borrow().as_ref() {
if let Some(strong_platform) = weak_platform.upgrade() {
strong_platform.set_popup_position(x, y);
}
}
});
}
#[must_use]
pub fn get_popup_position_override() -> Option<(f32, f32)> {
CURRENT_PLATFORM.with(|platform| {
platform.borrow().as_ref()
.and_then(Weak::upgrade)
.and_then(|strong| strong.get_popup_position())
})
}
pub fn clear_popup_position_override() {
CURRENT_PLATFORM.with(|platform| {
if let Some(weak_platform) = platform.borrow().as_ref() {
if let Some(strong_platform) = weak_platform.upgrade() {
strong_platform.clear_popup_position();
}
}
});
}
pub struct CustomSlintPlatform {
main_window: Weak<FemtoVGWindow>,
popup_creator: RefCell<Option<Rc<PopupCreator>>>,
first_call: Cell<bool>,
last_popup: RefCell<Option<Weak<PopupWindow>>>,
popup_position: RefCell<Option<(f32, f32)>>,
}
impl CustomSlintPlatform {
@ -39,6 +69,7 @@ impl CustomSlintPlatform {
popup_creator: RefCell::new(None),
first_call: Cell::new(true),
last_popup: RefCell::new(None),
popup_position: RefCell::new(None),
});
CURRENT_PLATFORM.with(|current| {
@ -68,6 +99,19 @@ impl CustomSlintPlatform {
}
*self.last_popup.borrow_mut() = None;
}
pub fn set_popup_position(&self, x: f32, y: f32) {
*self.popup_position.borrow_mut() = Some((x, y));
}
#[must_use]
pub fn get_popup_position(&self) -> Option<(f32, f32)> {
*self.popup_position.borrow()
}
pub fn clear_popup_position(&self) {
*self.popup_position.borrow_mut() = None;
}
}
impl Platform for CustomSlintPlatform {

View file

@ -1,6 +1,9 @@
use crate::errors::{LayerShikaError, Result};
use crate::rendering::egl::context::EGLContext;
use crate::rendering::femtovg::popup_window::PopupWindow;
use crate::rendering::slint_integration::platform::{
clear_popup_position_override, get_popup_position_override,
};
use log::info;
use slab::Slab;
use slint::{platform::femtovg_renderer::FemtoVGRenderer, PhysicalSize, WindowSize};
@ -93,6 +96,15 @@ impl PopupManager {
}
})?;
let pointer_position = if let Some((x, y)) = get_popup_position_override() {
info!("Using explicit popup position: ({}, {})", x, y);
clear_popup_position_override();
slint::LogicalPosition::new(x, y)
} else {
log::error!("No popup position provided - using (0, 0) as fallback");
slint::LogicalPosition::new(0.0, 0.0)
};
let scale_factor = *self.current_scale_factor.borrow();
let output_size = *self.current_output_size.borrow();
info!(
@ -120,7 +132,7 @@ impl PopupManager {
fractional_scale_manager: self.context.fractional_scale_manager.as_ref(),
viewporter: self.context.viewporter.as_ref(),
queue_handle,
position: slint::LogicalPosition::new(0.0, 0.0),
position: pointer_position,
size: popup_size,
scale_factor,
});

View file

@ -108,23 +108,23 @@ impl PopupSurface {
.xdg_wm_base
.create_positioner(params.queue_handle, ());
let x = (params.position.x * params.scale_factor) as i32;
let y = (params.position.y * params.scale_factor) as i32;
let width = params.size.width as i32;
let height = params.size.height as i32;
let x = params.position.x as i32;
let y = params.position.y as i32;
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_sign_loss)]
#[allow(clippy::cast_precision_loss)]
let logical_width = (params.size.width as f32 / params.scale_factor) as i32;
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_sign_loss)]
#[allow(clippy::cast_precision_loss)]
let logical_height = (params.size.height as f32 / params.scale_factor) as i32;
positioner.set_anchor_rect(x, y, 1, 1);
positioner.set_size(width, height);
positioner.set_size(logical_width, logical_height);
positioner.set_anchor(Anchor::TopLeft);
positioner.set_gravity(Gravity::BottomRight);
positioner.set_constraint_adjustment(
ConstraintAdjustment::SlideX
| ConstraintAdjustment::SlideY
| ConstraintAdjustment::FlipX
| ConstraintAdjustment::FlipY
| ConstraintAdjustment::ResizeX
| ConstraintAdjustment::ResizeY,
);
positioner.set_constraint_adjustment(ConstraintAdjustment::None);
positioner
}

View file

@ -11,6 +11,9 @@ pub use builder::LayerShika;
pub use layer_shika_adapters::PopupWindow;
pub use layer_shika_adapters::close_current_popup;
pub use layer_shika_adapters::platform::{calloop, slint, slint_interpreter};
pub use layer_shika_adapters::{
clear_popup_position_override, get_popup_position_override, set_popup_position_override,
};
pub use layer_shika_domain::value_objects::anchor::AnchorEdges;
pub type Result<T> = StdResult<T, Error>;