mirror of
https://codeberg.org/waydeer/layer-shika.git
synced 2025-11-03 19:04:23 +00:00
feat: add popup positioning mode
This commit is contained in:
parent
d646306a7a
commit
47487b7062
9 changed files with 251 additions and 122 deletions
|
|
@ -6,9 +6,7 @@ pub mod wayland;
|
||||||
|
|
||||||
pub use rendering::femtovg::popup_window::PopupWindow;
|
pub use rendering::femtovg::popup_window::PopupWindow;
|
||||||
pub use rendering::slint_integration::platform::{
|
pub use rendering::slint_integration::platform::{
|
||||||
clear_popup_position_override, close_current_popup, get_popup_position_override,
|
clear_popup_config, close_current_popup, get_popup_config, set_popup_config,
|
||||||
set_popup_position_override, clear_popup_size_override, get_popup_size_override,
|
|
||||||
set_popup_size_override,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod platform {
|
pub mod platform {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
|
||||||
use slint::{
|
use slint::{
|
||||||
PlatformError,
|
PlatformError,
|
||||||
platform::{Platform, WindowAdapter},
|
platform::{Platform, WindowAdapter},
|
||||||
|
|
@ -9,6 +10,7 @@ use crate::rendering::femtovg::main_window::FemtoVGWindow;
|
||||||
use crate::rendering::femtovg::popup_window::PopupWindow;
|
use crate::rendering::femtovg::popup_window::PopupWindow;
|
||||||
|
|
||||||
type PopupCreator = dyn Fn() -> Result<Rc<dyn WindowAdapter>, PlatformError>;
|
type PopupCreator = dyn Fn() -> Result<Rc<dyn WindowAdapter>, PlatformError>;
|
||||||
|
type PopupConfigData = (f32, f32, f32, f32, PopupPositioningMode);
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static CURRENT_PLATFORM: RefCell<Option<Weak<CustomSlintPlatform>>> = const { RefCell::new(None) };
|
static CURRENT_PLATFORM: RefCell<Option<Weak<CustomSlintPlatform>>> = const { RefCell::new(None) };
|
||||||
|
|
@ -24,61 +26,43 @@ pub fn close_current_popup() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_popup_position_override(x: f32, y: f32) {
|
pub fn set_popup_config(
|
||||||
|
reference_x: f32,
|
||||||
|
reference_y: f32,
|
||||||
|
width: f32,
|
||||||
|
height: f32,
|
||||||
|
positioning_mode: PopupPositioningMode,
|
||||||
|
) {
|
||||||
CURRENT_PLATFORM.with(|platform| {
|
CURRENT_PLATFORM.with(|platform| {
|
||||||
if let Some(weak_platform) = platform.borrow().as_ref() {
|
if let Some(weak_platform) = platform.borrow().as_ref() {
|
||||||
if let Some(strong_platform) = weak_platform.upgrade() {
|
if let Some(strong_platform) = weak_platform.upgrade() {
|
||||||
strong_platform.set_popup_position(x, y);
|
strong_platform.set_popup_config(
|
||||||
|
reference_x,
|
||||||
|
reference_y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
positioning_mode,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_popup_position_override() -> Option<(f32, f32)> {
|
pub fn get_popup_config() -> Option<PopupConfigData> {
|
||||||
CURRENT_PLATFORM.with(|platform| {
|
CURRENT_PLATFORM.with(|platform| {
|
||||||
platform
|
platform
|
||||||
.borrow()
|
.borrow()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(Weak::upgrade)
|
.and_then(Weak::upgrade)
|
||||||
.and_then(|strong| strong.get_popup_position())
|
.and_then(|strong| strong.get_popup_config())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_popup_position_override() {
|
pub fn clear_popup_config() {
|
||||||
CURRENT_PLATFORM.with(|platform| {
|
CURRENT_PLATFORM.with(|platform| {
|
||||||
if let Some(weak_platform) = platform.borrow().as_ref() {
|
if let Some(weak_platform) = platform.borrow().as_ref() {
|
||||||
if let Some(strong_platform) = weak_platform.upgrade() {
|
if let Some(strong_platform) = weak_platform.upgrade() {
|
||||||
strong_platform.clear_popup_position();
|
strong_platform.clear_popup_config();
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_popup_size_override(width: f32, height: 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_size(width, height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_popup_size_override() -> Option<(f32, f32)> {
|
|
||||||
CURRENT_PLATFORM.with(|platform| {
|
|
||||||
platform
|
|
||||||
.borrow()
|
|
||||||
.as_ref()
|
|
||||||
.and_then(Weak::upgrade)
|
|
||||||
.and_then(|strong| strong.get_popup_size())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear_popup_size_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_size();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -89,8 +73,7 @@ pub struct CustomSlintPlatform {
|
||||||
popup_creator: RefCell<Option<Rc<PopupCreator>>>,
|
popup_creator: RefCell<Option<Rc<PopupCreator>>>,
|
||||||
first_call: Cell<bool>,
|
first_call: Cell<bool>,
|
||||||
last_popup: RefCell<Option<Weak<PopupWindow>>>,
|
last_popup: RefCell<Option<Weak<PopupWindow>>>,
|
||||||
popup_position: RefCell<Option<(f32, f32)>>,
|
popup_config: RefCell<Option<PopupConfigData>>,
|
||||||
popup_size: RefCell<Option<(f32, f32)>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CustomSlintPlatform {
|
impl CustomSlintPlatform {
|
||||||
|
|
@ -101,8 +84,7 @@ impl CustomSlintPlatform {
|
||||||
popup_creator: RefCell::new(None),
|
popup_creator: RefCell::new(None),
|
||||||
first_call: Cell::new(true),
|
first_call: Cell::new(true),
|
||||||
last_popup: RefCell::new(None),
|
last_popup: RefCell::new(None),
|
||||||
popup_position: RefCell::new(None),
|
popup_config: RefCell::new(None),
|
||||||
popup_size: RefCell::new(None),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
CURRENT_PLATFORM.with(|current| {
|
CURRENT_PLATFORM.with(|current| {
|
||||||
|
|
@ -133,29 +115,25 @@ impl CustomSlintPlatform {
|
||||||
*self.last_popup.borrow_mut() = None;
|
*self.last_popup.borrow_mut() = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_popup_position(&self, x: f32, y: f32) {
|
pub fn set_popup_config(
|
||||||
*self.popup_position.borrow_mut() = Some((x, y));
|
&self,
|
||||||
|
reference_x: f32,
|
||||||
|
reference_y: f32,
|
||||||
|
width: f32,
|
||||||
|
height: f32,
|
||||||
|
positioning_mode: PopupPositioningMode,
|
||||||
|
) {
|
||||||
|
*self.popup_config.borrow_mut() =
|
||||||
|
Some((reference_x, reference_y, width, height, positioning_mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_popup_position(&self) -> Option<(f32, f32)> {
|
pub fn get_popup_config(&self) -> Option<PopupConfigData> {
|
||||||
*self.popup_position.borrow()
|
*self.popup_config.borrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_popup_position(&self) {
|
pub fn clear_popup_config(&self) {
|
||||||
*self.popup_position.borrow_mut() = None;
|
*self.popup_config.borrow_mut() = None;
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_popup_size(&self, width: f32, height: f32) {
|
|
||||||
*self.popup_size.borrow_mut() = Some((width, height));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_popup_size(&self) -> Option<(f32, f32)> {
|
|
||||||
*self.popup_size.borrow()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear_popup_size(&self) {
|
|
||||||
*self.popup_size.borrow_mut() = None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use crate::wayland::{
|
||||||
config::{LayerSurfaceParams, WaylandWindowConfig},
|
config::{LayerSurfaceParams, WaylandWindowConfig},
|
||||||
globals::context::GlobalContext,
|
globals::context::GlobalContext,
|
||||||
surfaces::layer_surface::{SurfaceCtx, SurfaceSetupParams},
|
surfaces::layer_surface::{SurfaceCtx, SurfaceSetupParams},
|
||||||
surfaces::popup_manager::{PopupContext, PopupManager},
|
surfaces::popup_manager::{CreatePopupParams, PopupContext, PopupManager},
|
||||||
surfaces::{
|
surfaces::{
|
||||||
surface_builder::WindowStateBuilder,
|
surface_builder::WindowStateBuilder,
|
||||||
surface_state::{SharedPointerSerial, WindowState},
|
surface_state::{SharedPointerSerial, WindowState},
|
||||||
|
|
@ -11,13 +11,15 @@ use crate::wayland::{
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{EventLoopError, LayerShikaError, RenderingError, Result},
|
errors::{EventLoopError, LayerShikaError, RenderingError, Result},
|
||||||
rendering::{
|
rendering::{
|
||||||
egl::context::EGLContext, femtovg::main_window::FemtoVGWindow,
|
egl::context::EGLContext,
|
||||||
slint_integration::platform::CustomSlintPlatform,
|
femtovg::main_window::FemtoVGWindow,
|
||||||
|
slint_integration::platform::{CustomSlintPlatform, clear_popup_config, get_popup_config},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use core::result::Result as CoreResult;
|
use core::result::Result as CoreResult;
|
||||||
use layer_shika_domain::errors::DomainError;
|
use layer_shika_domain::errors::DomainError;
|
||||||
use layer_shika_domain::ports::windowing::WindowingSystemPort;
|
use layer_shika_domain::ports::windowing::WindowingSystemPort;
|
||||||
|
use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use slint::{
|
use slint::{
|
||||||
LogicalPosition, PhysicalSize, PlatformError, WindowPosition,
|
LogicalPosition, PhysicalSize, PlatformError, WindowPosition,
|
||||||
|
|
@ -173,14 +175,45 @@ impl WaylandWindowingSystem {
|
||||||
let layer_surface = state.layer_surface();
|
let layer_surface = state.layer_surface();
|
||||||
let queue_handle = event_queue.handle();
|
let queue_handle = event_queue.handle();
|
||||||
let serial_holder = Rc::clone(shared_serial);
|
let serial_holder = Rc::clone(shared_serial);
|
||||||
|
let output_size = *state.output_size();
|
||||||
|
|
||||||
|
#[allow(clippy::cast_precision_loss)]
|
||||||
|
let default_width = output_size.width as f32;
|
||||||
|
#[allow(clippy::cast_precision_loss)]
|
||||||
|
let default_height = output_size.height as f32;
|
||||||
|
|
||||||
platform.set_popup_creator(move || {
|
platform.set_popup_creator(move || {
|
||||||
info!("Popup creator called! Creating popup window...");
|
info!("Popup creator called! Creating popup window...");
|
||||||
|
|
||||||
let serial = serial_holder.get();
|
let serial = serial_holder.get();
|
||||||
|
|
||||||
|
let (reference_x, reference_y, width, height, positioning_mode) = get_popup_config()
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
log::warn!("No popup config provided, using output size as defaults");
|
||||||
|
(
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
default_width,
|
||||||
|
default_height,
|
||||||
|
PopupPositioningMode::TopLeft,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
clear_popup_config();
|
||||||
|
|
||||||
let popup_window = popup_manager_clone
|
let popup_window = popup_manager_clone
|
||||||
.create_popup(&queue_handle, &layer_surface, serial)
|
.create_popup(
|
||||||
|
&queue_handle,
|
||||||
|
&layer_surface,
|
||||||
|
CreatePopupParams {
|
||||||
|
last_pointer_serial: serial,
|
||||||
|
reference_x,
|
||||||
|
reference_y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
positioning_mode,
|
||||||
|
},
|
||||||
|
)
|
||||||
.map_err(|e| PlatformError::Other(format!("Failed to create popup: {e}")))?;
|
.map_err(|e| PlatformError::Other(format!("Failed to create popup: {e}")))?;
|
||||||
|
|
||||||
if let Some(platform) = platform_weak.upgrade() {
|
if let Some(platform) = platform_weak.upgrade() {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
use crate::errors::{LayerShikaError, Result};
|
use crate::errors::{LayerShikaError, Result};
|
||||||
use crate::rendering::egl::context::EGLContext;
|
use crate::rendering::egl::context::EGLContext;
|
||||||
use crate::rendering::femtovg::popup_window::PopupWindow;
|
use crate::rendering::femtovg::popup_window::PopupWindow;
|
||||||
use crate::rendering::slint_integration::platform::{
|
use layer_shika_domain::value_objects::popup_config::PopupConfig;
|
||||||
clear_popup_position_override, get_popup_position_override,
|
use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
|
||||||
clear_popup_size_override, get_popup_size_override,
|
|
||||||
};
|
|
||||||
use log::info;
|
use log::info;
|
||||||
use slab::Slab;
|
use slab::Slab;
|
||||||
use slint::{platform::femtovg_renderer::FemtoVGRenderer, PhysicalSize, WindowSize};
|
use slint::{platform::femtovg_renderer::FemtoVGRenderer, PhysicalSize, WindowSize};
|
||||||
|
|
@ -23,6 +21,16 @@ use wayland_protocols::xdg::shell::client::xdg_wm_base::XdgWmBase;
|
||||||
use super::popup_surface::PopupSurface;
|
use super::popup_surface::PopupSurface;
|
||||||
use super::surface_state::WindowState;
|
use super::surface_state::WindowState;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct CreatePopupParams {
|
||||||
|
pub last_pointer_serial: u32,
|
||||||
|
pub reference_x: f32,
|
||||||
|
pub reference_y: f32,
|
||||||
|
pub width: f32,
|
||||||
|
pub height: f32,
|
||||||
|
pub positioning_mode: PopupPositioningMode,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PopupContext {
|
pub struct PopupContext {
|
||||||
compositor: WlCompositor,
|
compositor: WlCompositor,
|
||||||
xdg_wm_base: Option<XdgWmBase>,
|
xdg_wm_base: Option<XdgWmBase>,
|
||||||
|
|
@ -89,7 +97,7 @@ impl PopupManager {
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
queue_handle: &QueueHandle<WindowState>,
|
queue_handle: &QueueHandle<WindowState>,
|
||||||
parent_layer_surface: &ZwlrLayerSurfaceV1,
|
parent_layer_surface: &ZwlrLayerSurfaceV1,
|
||||||
last_pointer_serial: u32,
|
params: CreatePopupParams,
|
||||||
) -> Result<Rc<PopupWindow>> {
|
) -> Result<Rc<PopupWindow>> {
|
||||||
let xdg_wm_base = self.context.xdg_wm_base.as_ref().ok_or_else(|| {
|
let xdg_wm_base = self.context.xdg_wm_base.as_ref().ok_or_else(|| {
|
||||||
LayerShikaError::WindowConfiguration {
|
LayerShikaError::WindowConfiguration {
|
||||||
|
|
@ -97,41 +105,32 @@ 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 scale_factor = *self.current_scale_factor.borrow();
|
||||||
let output_size = *self.current_output_size.borrow();
|
|
||||||
info!(
|
info!(
|
||||||
"Creating popup window with scale factor {scale_factor} and output size {output_size:?}"
|
"Creating popup window with scale factor {scale_factor}, reference=({}, {}), size=({} x {}), mode={:?}",
|
||||||
|
params.reference_x,
|
||||||
|
params.reference_y,
|
||||||
|
params.width,
|
||||||
|
params.height,
|
||||||
|
params.positioning_mode
|
||||||
|
);
|
||||||
|
|
||||||
|
let popup_config = PopupConfig::new(
|
||||||
|
params.reference_x,
|
||||||
|
params.reference_y,
|
||||||
|
params.width,
|
||||||
|
params.height,
|
||||||
|
params.positioning_mode,
|
||||||
);
|
);
|
||||||
|
|
||||||
#[allow(clippy::cast_precision_loss)]
|
|
||||||
let logical_size = if let Some((width, height)) = get_popup_size_override() {
|
|
||||||
info!("Using explicit popup size: ({}, {})", width, height);
|
|
||||||
clear_popup_size_override();
|
|
||||||
slint::LogicalSize::new(width, height)
|
|
||||||
} else {
|
|
||||||
info!("No popup size override - using full output size");
|
|
||||||
slint::LogicalSize::new(
|
|
||||||
output_size.width as f32 / scale_factor,
|
|
||||||
output_size.height as f32 / scale_factor,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
#[allow(clippy::cast_sign_loss)]
|
#[allow(clippy::cast_sign_loss)]
|
||||||
let popup_size = PhysicalSize::new(
|
let popup_size = PhysicalSize::new(
|
||||||
(logical_size.width * scale_factor) as u32,
|
(params.width * scale_factor) as u32,
|
||||||
(logical_size.height * scale_factor) as u32,
|
(params.height * scale_factor) as u32,
|
||||||
);
|
);
|
||||||
|
|
||||||
info!("Popup logical size: {logical_size:?}, physical size: {popup_size:?}");
|
info!("Popup physical size: {popup_size:?}");
|
||||||
|
|
||||||
let popup_surface = PopupSurface::create(&super::popup_surface::PopupSurfaceParams {
|
let popup_surface = PopupSurface::create(&super::popup_surface::PopupSurfaceParams {
|
||||||
compositor: &self.context.compositor,
|
compositor: &self.context.compositor,
|
||||||
|
|
@ -140,12 +139,12 @@ impl PopupManager {
|
||||||
fractional_scale_manager: self.context.fractional_scale_manager.as_ref(),
|
fractional_scale_manager: self.context.fractional_scale_manager.as_ref(),
|
||||||
viewporter: self.context.viewporter.as_ref(),
|
viewporter: self.context.viewporter.as_ref(),
|
||||||
queue_handle,
|
queue_handle,
|
||||||
position: pointer_position,
|
popup_config,
|
||||||
size: popup_size,
|
physical_size: popup_size,
|
||||||
scale_factor,
|
scale_factor,
|
||||||
});
|
});
|
||||||
|
|
||||||
popup_surface.grab(&self.context.seat, last_pointer_serial);
|
popup_surface.grab(&self.context.seat, params.last_pointer_serial);
|
||||||
|
|
||||||
let context = EGLContext::builder()
|
let context = EGLContext::builder()
|
||||||
.with_display_id(self.context.display.id())
|
.with_display_id(self.context.display.id())
|
||||||
|
|
@ -158,7 +157,10 @@ impl PopupManager {
|
||||||
|
|
||||||
let popup_window = PopupWindow::new(renderer);
|
let popup_window = PopupWindow::new(renderer);
|
||||||
popup_window.set_scale_factor(scale_factor);
|
popup_window.set_scale_factor(scale_factor);
|
||||||
popup_window.set_size(WindowSize::Logical(logical_size));
|
popup_window.set_size(WindowSize::Logical(slint::LogicalSize::new(
|
||||||
|
params.width,
|
||||||
|
params.height,
|
||||||
|
)));
|
||||||
|
|
||||||
let key = self.popups.borrow_mut().insert(ActivePopup {
|
let key = self.popups.borrow_mut().insert(ActivePopup {
|
||||||
surface: popup_surface,
|
surface: popup_surface,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
use layer_shika_domain::value_objects::popup_config::PopupConfig;
|
||||||
use log::info;
|
use log::info;
|
||||||
use slint::{LogicalPosition, PhysicalSize};
|
use slint::PhysicalSize;
|
||||||
use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
|
use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use wayland_client::{
|
use wayland_client::{
|
||||||
|
|
@ -30,8 +31,8 @@ pub struct PopupSurfaceParams<'a> {
|
||||||
pub fractional_scale_manager: Option<&'a WpFractionalScaleManagerV1>,
|
pub fractional_scale_manager: Option<&'a WpFractionalScaleManagerV1>,
|
||||||
pub viewporter: Option<&'a WpViewporter>,
|
pub viewporter: Option<&'a WpViewporter>,
|
||||||
pub queue_handle: &'a QueueHandle<WindowState>,
|
pub queue_handle: &'a QueueHandle<WindowState>,
|
||||||
pub position: LogicalPosition,
|
pub popup_config: PopupConfig,
|
||||||
pub size: PhysicalSize,
|
pub physical_size: PhysicalSize,
|
||||||
pub scale_factor: f32,
|
pub scale_factor: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,14 +77,14 @@ impl PopupSurface {
|
||||||
#[allow(clippy::cast_precision_loss)]
|
#[allow(clippy::cast_precision_loss)]
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
if let Some(ref vp) = viewport {
|
if let Some(ref vp) = viewport {
|
||||||
let logical_width = (params.size.width as f32 / params.scale_factor) as i32;
|
let logical_width = (params.physical_size.width as f32 / params.scale_factor) as i32;
|
||||||
let logical_height = (params.size.height as f32 / params.scale_factor) as i32;
|
let logical_height = (params.physical_size.height as f32 / params.scale_factor) as i32;
|
||||||
info!(
|
info!(
|
||||||
"Setting viewport destination to logical size: {}x{} (physical: {}x{}, scale: {})",
|
"Setting viewport destination to logical size: {}x{} (physical: {}x{}, scale: {})",
|
||||||
logical_width,
|
logical_width,
|
||||||
logical_height,
|
logical_height,
|
||||||
params.size.width,
|
params.physical_size.width,
|
||||||
params.size.height,
|
params.physical_size.height,
|
||||||
params.scale_factor
|
params.scale_factor
|
||||||
);
|
);
|
||||||
vp.set_destination(logical_width, logical_height);
|
vp.set_destination(logical_width, logical_height);
|
||||||
|
|
@ -102,24 +103,29 @@ impl PopupSurface {
|
||||||
|
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
#[allow(clippy::cast_possible_wrap)]
|
#[allow(clippy::cast_possible_wrap)]
|
||||||
|
#[allow(clippy::cast_sign_loss)]
|
||||||
|
#[allow(clippy::cast_precision_loss)]
|
||||||
fn create_positioner(params: &PopupSurfaceParams<'_>) -> XdgPositioner {
|
fn create_positioner(params: &PopupSurfaceParams<'_>) -> XdgPositioner {
|
||||||
let positioner = params
|
let positioner = params
|
||||||
.xdg_wm_base
|
.xdg_wm_base
|
||||||
.create_positioner(params.queue_handle, ());
|
.create_positioner(params.queue_handle, ());
|
||||||
|
|
||||||
let x = params.position.x as i32;
|
let calculated_x = params.popup_config.calculated_top_left_x() as i32;
|
||||||
let y = params.position.y as i32;
|
let calculated_y = params.popup_config.calculated_top_left_y() as i32;
|
||||||
|
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
info!(
|
||||||
#[allow(clippy::cast_sign_loss)]
|
"Popup positioning: reference=({}, {}), mode={:?}, calculated_top_left=({}, {})",
|
||||||
#[allow(clippy::cast_precision_loss)]
|
params.popup_config.reference_x(),
|
||||||
let logical_width = (params.size.width as f32 / params.scale_factor) as i32;
|
params.popup_config.reference_y(),
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
params.popup_config.positioning_mode(),
|
||||||
#[allow(clippy::cast_sign_loss)]
|
calculated_x,
|
||||||
#[allow(clippy::cast_precision_loss)]
|
calculated_y
|
||||||
let logical_height = (params.size.height as f32 / params.scale_factor) as i32;
|
);
|
||||||
|
|
||||||
positioner.set_anchor_rect(x, y, 1, 1);
|
let logical_width = (params.physical_size.width as f32 / params.scale_factor) as i32;
|
||||||
|
let logical_height = (params.physical_size.height as f32 / params.scale_factor) as i32;
|
||||||
|
|
||||||
|
positioner.set_anchor_rect(calculated_x, calculated_y, 1, 1);
|
||||||
positioner.set_size(logical_width, logical_height);
|
positioner.set_size(logical_width, logical_height);
|
||||||
positioner.set_anchor(Anchor::TopLeft);
|
positioner.set_anchor(Anchor::TopLeft);
|
||||||
positioner.set_gravity(Gravity::BottomRight);
|
positioner.set_gravity(Gravity::BottomRight);
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,9 @@ pub use builder::LayerShika;
|
||||||
pub use layer_shika_adapters::PopupWindow;
|
pub use layer_shika_adapters::PopupWindow;
|
||||||
pub use layer_shika_adapters::close_current_popup;
|
pub use layer_shika_adapters::close_current_popup;
|
||||||
pub use layer_shika_adapters::platform::{calloop, slint, slint_interpreter};
|
pub use layer_shika_adapters::platform::{calloop, slint, slint_interpreter};
|
||||||
pub use layer_shika_adapters::{
|
pub use layer_shika_adapters::{clear_popup_config, get_popup_config, set_popup_config};
|
||||||
clear_popup_position_override, get_popup_position_override, set_popup_position_override,
|
|
||||||
clear_popup_size_override, get_popup_size_override, set_popup_size_override,
|
|
||||||
};
|
|
||||||
pub use layer_shika_domain::value_objects::anchor::AnchorEdges;
|
pub use layer_shika_domain::value_objects::anchor::AnchorEdges;
|
||||||
|
pub use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
|
||||||
|
|
||||||
pub type Result<T> = StdResult<T, Error>;
|
pub type Result<T> = StdResult<T, Error>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,5 @@ pub mod anchor;
|
||||||
pub mod dimensions;
|
pub mod dimensions;
|
||||||
pub mod layer;
|
pub mod layer;
|
||||||
pub mod margins;
|
pub mod margins;
|
||||||
|
pub mod popup_config;
|
||||||
|
pub mod popup_positioning_mode;
|
||||||
|
|
|
||||||
72
domain/src/value_objects/popup_config.rs
Normal file
72
domain/src/value_objects/popup_config.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
use super::popup_positioning_mode::PopupPositioningMode;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct PopupConfig {
|
||||||
|
reference_x: f32,
|
||||||
|
reference_y: f32,
|
||||||
|
width: f32,
|
||||||
|
height: f32,
|
||||||
|
positioning_mode: PopupPositioningMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PopupConfig {
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(
|
||||||
|
reference_x: f32,
|
||||||
|
reference_y: f32,
|
||||||
|
width: f32,
|
||||||
|
height: f32,
|
||||||
|
positioning_mode: PopupPositioningMode,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
reference_x,
|
||||||
|
reference_y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
positioning_mode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn reference_x(&self) -> f32 {
|
||||||
|
self.reference_x
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn reference_y(&self) -> f32 {
|
||||||
|
self.reference_y
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn width(&self) -> f32 {
|
||||||
|
self.width
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn height(&self) -> f32 {
|
||||||
|
self.height
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn positioning_mode(&self) -> PopupPositioningMode {
|
||||||
|
self.positioning_mode
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn calculated_top_left_x(&self) -> f32 {
|
||||||
|
if self.positioning_mode.center_x() {
|
||||||
|
self.reference_x - (self.width / 2.0)
|
||||||
|
} else {
|
||||||
|
self.reference_x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn calculated_top_left_y(&self) -> f32 {
|
||||||
|
if self.positioning_mode.center_y() {
|
||||||
|
self.reference_y - (self.height / 2.0)
|
||||||
|
} else {
|
||||||
|
self.reference_y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
domain/src/value_objects/popup_positioning_mode.rs
Normal file
40
domain/src/value_objects/popup_positioning_mode.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub enum PopupPositioningMode {
|
||||||
|
TopLeft,
|
||||||
|
TopCenter,
|
||||||
|
TopRight,
|
||||||
|
CenterLeft,
|
||||||
|
Center,
|
||||||
|
CenterRight,
|
||||||
|
BottomLeft,
|
||||||
|
BottomCenter,
|
||||||
|
BottomRight,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PopupPositioningMode {
|
||||||
|
#[must_use]
|
||||||
|
pub const fn center_x(self) -> bool {
|
||||||
|
matches!(self, Self::TopCenter | Self::Center | Self::BottomCenter)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn center_y(self) -> bool {
|
||||||
|
matches!(self, Self::CenterLeft | Self::Center | Self::CenterRight)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn from_flags(center_x: bool, center_y: bool) -> Self {
|
||||||
|
match (center_x, center_y) {
|
||||||
|
(false, false) => Self::TopLeft,
|
||||||
|
(true, false) => Self::TopCenter,
|
||||||
|
(false, true) => Self::CenterLeft,
|
||||||
|
(true, true) => Self::Center,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PopupPositioningMode {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::TopLeft
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue