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::slint_integration::platform::{
|
||||
clear_popup_position_override, close_current_popup, get_popup_position_override,
|
||||
set_popup_position_override, clear_popup_size_override, get_popup_size_override,
|
||||
set_popup_size_override,
|
||||
clear_popup_config, close_current_popup, get_popup_config, set_popup_config,
|
||||
};
|
||||
|
||||
pub mod platform {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
|
||||
use slint::{
|
||||
PlatformError,
|
||||
platform::{Platform, WindowAdapter},
|
||||
|
|
@ -9,6 +10,7 @@ use crate::rendering::femtovg::main_window::FemtoVGWindow;
|
|||
use crate::rendering::femtovg::popup_window::PopupWindow;
|
||||
|
||||
type PopupCreator = dyn Fn() -> Result<Rc<dyn WindowAdapter>, PlatformError>;
|
||||
type PopupConfigData = (f32, f32, f32, f32, PopupPositioningMode);
|
||||
|
||||
thread_local! {
|
||||
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| {
|
||||
if let Some(weak_platform) = platform.borrow().as_ref() {
|
||||
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| {
|
||||
platform
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.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| {
|
||||
if let Some(weak_platform) = platform.borrow().as_ref() {
|
||||
if let Some(strong_platform) = weak_platform.upgrade() {
|
||||
strong_platform.clear_popup_position();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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();
|
||||
strong_platform.clear_popup_config();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -89,8 +73,7 @@ pub struct CustomSlintPlatform {
|
|||
popup_creator: RefCell<Option<Rc<PopupCreator>>>,
|
||||
first_call: Cell<bool>,
|
||||
last_popup: RefCell<Option<Weak<PopupWindow>>>,
|
||||
popup_position: RefCell<Option<(f32, f32)>>,
|
||||
popup_size: RefCell<Option<(f32, f32)>>,
|
||||
popup_config: RefCell<Option<PopupConfigData>>,
|
||||
}
|
||||
|
||||
impl CustomSlintPlatform {
|
||||
|
|
@ -101,8 +84,7 @@ impl CustomSlintPlatform {
|
|||
popup_creator: RefCell::new(None),
|
||||
first_call: Cell::new(true),
|
||||
last_popup: RefCell::new(None),
|
||||
popup_position: RefCell::new(None),
|
||||
popup_size: RefCell::new(None),
|
||||
popup_config: RefCell::new(None),
|
||||
});
|
||||
|
||||
CURRENT_PLATFORM.with(|current| {
|
||||
|
|
@ -133,29 +115,25 @@ 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));
|
||||
pub fn set_popup_config(
|
||||
&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]
|
||||
pub fn get_popup_position(&self) -> Option<(f32, f32)> {
|
||||
*self.popup_position.borrow()
|
||||
pub fn get_popup_config(&self) -> Option<PopupConfigData> {
|
||||
*self.popup_config.borrow()
|
||||
}
|
||||
|
||||
pub fn clear_popup_position(&self) {
|
||||
*self.popup_position.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;
|
||||
pub fn clear_popup_config(&self) {
|
||||
*self.popup_config.borrow_mut() = None;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::wayland::{
|
|||
config::{LayerSurfaceParams, WaylandWindowConfig},
|
||||
globals::context::GlobalContext,
|
||||
surfaces::layer_surface::{SurfaceCtx, SurfaceSetupParams},
|
||||
surfaces::popup_manager::{PopupContext, PopupManager},
|
||||
surfaces::popup_manager::{CreatePopupParams, PopupContext, PopupManager},
|
||||
surfaces::{
|
||||
surface_builder::WindowStateBuilder,
|
||||
surface_state::{SharedPointerSerial, WindowState},
|
||||
|
|
@ -11,13 +11,15 @@ use crate::wayland::{
|
|||
use crate::{
|
||||
errors::{EventLoopError, LayerShikaError, RenderingError, Result},
|
||||
rendering::{
|
||||
egl::context::EGLContext, femtovg::main_window::FemtoVGWindow,
|
||||
slint_integration::platform::CustomSlintPlatform,
|
||||
egl::context::EGLContext,
|
||||
femtovg::main_window::FemtoVGWindow,
|
||||
slint_integration::platform::{CustomSlintPlatform, clear_popup_config, get_popup_config},
|
||||
},
|
||||
};
|
||||
use core::result::Result as CoreResult;
|
||||
use layer_shika_domain::errors::DomainError;
|
||||
use layer_shika_domain::ports::windowing::WindowingSystemPort;
|
||||
use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
|
||||
use log::{error, info};
|
||||
use slint::{
|
||||
LogicalPosition, PhysicalSize, PlatformError, WindowPosition,
|
||||
|
|
@ -173,14 +175,45 @@ impl WaylandWindowingSystem {
|
|||
let layer_surface = state.layer_surface();
|
||||
let queue_handle = event_queue.handle();
|
||||
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 || {
|
||||
info!("Popup creator called! Creating popup window...");
|
||||
|
||||
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
|
||||
.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}")))?;
|
||||
|
||||
if let Some(platform) = platform_weak.upgrade() {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
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,
|
||||
clear_popup_size_override, get_popup_size_override,
|
||||
};
|
||||
use layer_shika_domain::value_objects::popup_config::PopupConfig;
|
||||
use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
|
||||
use log::info;
|
||||
use slab::Slab;
|
||||
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::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 {
|
||||
compositor: WlCompositor,
|
||||
xdg_wm_base: Option<XdgWmBase>,
|
||||
|
|
@ -89,7 +97,7 @@ impl PopupManager {
|
|||
self: &Rc<Self>,
|
||||
queue_handle: &QueueHandle<WindowState>,
|
||||
parent_layer_surface: &ZwlrLayerSurfaceV1,
|
||||
last_pointer_serial: u32,
|
||||
params: CreatePopupParams,
|
||||
) -> Result<Rc<PopupWindow>> {
|
||||
let xdg_wm_base = self.context.xdg_wm_base.as_ref().ok_or_else(|| {
|
||||
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 output_size = *self.current_output_size.borrow();
|
||||
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_sign_loss)]
|
||||
let popup_size = PhysicalSize::new(
|
||||
(logical_size.width * scale_factor) as u32,
|
||||
(logical_size.height * scale_factor) as u32,
|
||||
(params.width * 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 {
|
||||
compositor: &self.context.compositor,
|
||||
|
|
@ -140,12 +139,12 @@ impl PopupManager {
|
|||
fractional_scale_manager: self.context.fractional_scale_manager.as_ref(),
|
||||
viewporter: self.context.viewporter.as_ref(),
|
||||
queue_handle,
|
||||
position: pointer_position,
|
||||
size: popup_size,
|
||||
popup_config,
|
||||
physical_size: popup_size,
|
||||
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()
|
||||
.with_display_id(self.context.display.id())
|
||||
|
|
@ -158,7 +157,10 @@ impl PopupManager {
|
|||
|
||||
let popup_window = PopupWindow::new(renderer);
|
||||
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 {
|
||||
surface: popup_surface,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use layer_shika_domain::value_objects::popup_config::PopupConfig;
|
||||
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 std::rc::Rc;
|
||||
use wayland_client::{
|
||||
|
|
@ -30,8 +31,8 @@ pub struct PopupSurfaceParams<'a> {
|
|||
pub fractional_scale_manager: Option<&'a WpFractionalScaleManagerV1>,
|
||||
pub viewporter: Option<&'a WpViewporter>,
|
||||
pub queue_handle: &'a QueueHandle<WindowState>,
|
||||
pub position: LogicalPosition,
|
||||
pub size: PhysicalSize,
|
||||
pub popup_config: PopupConfig,
|
||||
pub physical_size: PhysicalSize,
|
||||
pub scale_factor: f32,
|
||||
}
|
||||
|
||||
|
|
@ -76,14 +77,14 @@ impl PopupSurface {
|
|||
#[allow(clippy::cast_precision_loss)]
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
if let Some(ref vp) = viewport {
|
||||
let logical_width = (params.size.width as f32 / params.scale_factor) as i32;
|
||||
let logical_height = (params.size.height 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.physical_size.height as f32 / params.scale_factor) as i32;
|
||||
info!(
|
||||
"Setting viewport destination to logical size: {}x{} (physical: {}x{}, scale: {})",
|
||||
logical_width,
|
||||
logical_height,
|
||||
params.size.width,
|
||||
params.size.height,
|
||||
params.physical_size.width,
|
||||
params.physical_size.height,
|
||||
params.scale_factor
|
||||
);
|
||||
vp.set_destination(logical_width, logical_height);
|
||||
|
|
@ -102,24 +103,29 @@ impl PopupSurface {
|
|||
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
#[allow(clippy::cast_precision_loss)]
|
||||
fn create_positioner(params: &PopupSurfaceParams<'_>) -> XdgPositioner {
|
||||
let positioner = params
|
||||
.xdg_wm_base
|
||||
.create_positioner(params.queue_handle, ());
|
||||
|
||||
let x = params.position.x as i32;
|
||||
let y = params.position.y as i32;
|
||||
let calculated_x = params.popup_config.calculated_top_left_x() as i32;
|
||||
let calculated_y = params.popup_config.calculated_top_left_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;
|
||||
info!(
|
||||
"Popup positioning: reference=({}, {}), mode={:?}, calculated_top_left=({}, {})",
|
||||
params.popup_config.reference_x(),
|
||||
params.popup_config.reference_y(),
|
||||
params.popup_config.positioning_mode(),
|
||||
calculated_x,
|
||||
calculated_y
|
||||
);
|
||||
|
||||
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_anchor(Anchor::TopLeft);
|
||||
positioner.set_gravity(Gravity::BottomRight);
|
||||
|
|
|
|||
|
|
@ -11,11 +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,
|
||||
clear_popup_size_override, get_popup_size_override, set_popup_size_override,
|
||||
};
|
||||
pub use layer_shika_adapters::{clear_popup_config, get_popup_config, set_popup_config};
|
||||
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>;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,3 +2,5 @@ pub mod anchor;
|
|||
pub mod dimensions;
|
||||
pub mod layer;
|
||||
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