mirror of
https://codeberg.org/waydeer/layer-shika.git
synced 2025-11-04 18:44:24 +00:00
refactor:extract popup builder and dimensions
This commit is contained in:
parent
a32140d41d
commit
6e5c0259e9
8 changed files with 315 additions and 31 deletions
|
|
@ -95,6 +95,10 @@ impl PopupWindow {
|
|||
pub fn scale_factor(&self) -> f32 {
|
||||
self.scale_factor.get()
|
||||
}
|
||||
|
||||
pub fn popup_key(&self) -> Option<usize> {
|
||||
self.popup_key.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowAdapter for PopupWindow {
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ impl WaylandWindowingSystem {
|
|||
|
||||
let serial = serial_holder.get();
|
||||
|
||||
let params = if let Some((request, width, height)) = popup_manager_clone.take_pending_popup_request() {
|
||||
let params = if let Some((request, width, height)) = popup_manager_clone.take_pending_popup() {
|
||||
log::info!(
|
||||
"Using popup request: component='{}', position=({}, {}), size={}x{}, mode={:?}",
|
||||
request.component,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
pub mod dimensions;
|
||||
pub mod layer_surface;
|
||||
pub mod popup_builder;
|
||||
pub mod popup_manager;
|
||||
pub mod popup_surface;
|
||||
pub mod surface_builder;
|
||||
|
|
|
|||
200
adapters/src/wayland/surfaces/popup_builder.rs
Normal file
200
adapters/src/wayland/surfaces/popup_builder.rs
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
use crate::errors::{LayerShikaError, Result};
|
||||
use crate::rendering::femtovg::popup_window::PopupWindow;
|
||||
use layer_shika_domain::value_objects::popup_dimensions::PopupDimensions;
|
||||
use layer_shika_domain::value_objects::popup_request::{PopupHandle, PopupRequest, PopupSize};
|
||||
use log::{debug, info};
|
||||
use slint::ComponentHandle;
|
||||
use slint_interpreter::{ComponentDefinition, ComponentInstance, Value};
|
||||
use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
|
||||
use std::rc::Rc;
|
||||
use wayland_client::QueueHandle;
|
||||
|
||||
use super::popup_manager::{CreatePopupParams, PopupManager};
|
||||
use super::surface_state::WindowState;
|
||||
|
||||
pub struct PopupBuilder<'a> {
|
||||
popup_manager: &'a Rc<PopupManager>,
|
||||
queue_handle: &'a QueueHandle<WindowState>,
|
||||
parent_layer_surface: &'a ZwlrLayerSurfaceV1,
|
||||
}
|
||||
|
||||
impl<'a> PopupBuilder<'a> {
|
||||
#[must_use]
|
||||
pub const fn new(
|
||||
popup_manager: &'a Rc<PopupManager>,
|
||||
queue_handle: &'a QueueHandle<WindowState>,
|
||||
parent_layer_surface: &'a ZwlrLayerSurfaceV1,
|
||||
) -> Self {
|
||||
Self {
|
||||
popup_manager,
|
||||
queue_handle,
|
||||
parent_layer_surface,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(
|
||||
&self,
|
||||
component_def: &ComponentDefinition,
|
||||
request: &PopupRequest,
|
||||
serial: u32,
|
||||
) -> Result<PopupHandle> {
|
||||
info!(
|
||||
"Building popup for component '{}' at position ({}, {}) with mode {:?}",
|
||||
request.component,
|
||||
request.at.position().0,
|
||||
request.at.position().1,
|
||||
request.mode
|
||||
);
|
||||
|
||||
let dimensions = Self::resolve_dimensions(component_def, &request.size)?;
|
||||
dimensions
|
||||
.validate()
|
||||
.map_err(|e| LayerShikaError::WindowConfiguration {
|
||||
message: format!("Invalid popup dimensions: {e}"),
|
||||
})?;
|
||||
|
||||
debug!(
|
||||
"Resolved popup dimensions: {}x{}",
|
||||
dimensions.width(),
|
||||
dimensions.height()
|
||||
);
|
||||
|
||||
let params = CreatePopupParams {
|
||||
last_pointer_serial: serial,
|
||||
reference_x: request.at.position().0,
|
||||
reference_y: request.at.position().1,
|
||||
width: dimensions.width(),
|
||||
height: dimensions.height(),
|
||||
positioning_mode: request.mode,
|
||||
};
|
||||
|
||||
let popup_window = self.popup_manager.create_popup(
|
||||
self.queue_handle,
|
||||
self.parent_layer_surface,
|
||||
params,
|
||||
)?;
|
||||
|
||||
let instance = Self::create_component_instance(component_def, &popup_window)?;
|
||||
|
||||
self.setup_popup_callbacks(&instance, &popup_window)?;
|
||||
|
||||
let handle = PopupHandle::new(popup_window.popup_key().ok_or_else(|| {
|
||||
LayerShikaError::WindowConfiguration {
|
||||
message: "Popup window has no key assigned".to_string(),
|
||||
}
|
||||
})?);
|
||||
|
||||
info!("Popup built successfully with handle {:?}", handle);
|
||||
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
fn resolve_dimensions(
|
||||
component_def: &ComponentDefinition,
|
||||
size: &PopupSize,
|
||||
) -> Result<PopupDimensions> {
|
||||
match size {
|
||||
PopupSize::Fixed { w, h } => {
|
||||
debug!("Using fixed popup size: {}x{}", w, h);
|
||||
Ok(PopupDimensions::new(*w, *h))
|
||||
}
|
||||
PopupSize::Content => {
|
||||
debug!("Measuring popup dimensions from component content");
|
||||
Self::measure_component_dimensions(component_def)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn measure_component_dimensions(
|
||||
component_def: &ComponentDefinition,
|
||||
) -> Result<PopupDimensions> {
|
||||
debug!("Creating temporary component instance to measure dimensions");
|
||||
|
||||
let temp_instance =
|
||||
component_def
|
||||
.create()
|
||||
.map_err(|e| LayerShikaError::WindowConfiguration {
|
||||
message: format!(
|
||||
"Failed to create temporary instance for dimension measurement: {}",
|
||||
e
|
||||
),
|
||||
})?;
|
||||
|
||||
temp_instance
|
||||
.show()
|
||||
.map_err(|e| LayerShikaError::WindowConfiguration {
|
||||
message: format!("Failed to show temporary instance: {}", e),
|
||||
})?;
|
||||
|
||||
let width = Self::read_property(&temp_instance, "popup-width", 120.0);
|
||||
let height = Self::read_property(&temp_instance, "popup-height", 120.0);
|
||||
|
||||
debug!(
|
||||
"Measured dimensions from component properties: {}x{}",
|
||||
width, height
|
||||
);
|
||||
|
||||
Ok(PopupDimensions::new(width, height))
|
||||
}
|
||||
|
||||
fn read_property(instance: &ComponentInstance, name: &str, default: f32) -> f32 {
|
||||
instance
|
||||
.get_property(name)
|
||||
.ok()
|
||||
.and_then(|v| v.try_into().ok())
|
||||
.unwrap_or_else(|| {
|
||||
debug!(
|
||||
"Property '{}' not found or invalid, using default: {}",
|
||||
name, default
|
||||
);
|
||||
default
|
||||
})
|
||||
}
|
||||
|
||||
fn create_component_instance(
|
||||
component_def: &ComponentDefinition,
|
||||
_popup_window: &Rc<PopupWindow>,
|
||||
) -> Result<ComponentInstance> {
|
||||
debug!("Creating popup component instance");
|
||||
|
||||
let instance =
|
||||
component_def
|
||||
.create()
|
||||
.map_err(|e| LayerShikaError::WindowConfiguration {
|
||||
message: format!("Failed to create popup instance: {}", e),
|
||||
})?;
|
||||
|
||||
instance
|
||||
.show()
|
||||
.map_err(|e| LayerShikaError::WindowConfiguration {
|
||||
message: format!("Failed to show popup instance: {}", e),
|
||||
})?;
|
||||
|
||||
debug!("Popup component instance created and shown successfully");
|
||||
|
||||
Ok(instance)
|
||||
}
|
||||
|
||||
fn setup_popup_callbacks(
|
||||
&self,
|
||||
instance: &ComponentInstance,
|
||||
_popup_window: &Rc<PopupWindow>,
|
||||
) -> Result<()> {
|
||||
debug!("Setting up popup callbacks");
|
||||
|
||||
let popup_manager = Rc::clone(self.popup_manager);
|
||||
instance
|
||||
.set_callback("closed", move |_| {
|
||||
info!("Popup 'closed' callback triggered");
|
||||
popup_manager.close_current_popup();
|
||||
Value::Void
|
||||
})
|
||||
.map_err(|e| LayerShikaError::WindowConfiguration {
|
||||
message: format!("Failed to set popup 'closed' callback: {}", e),
|
||||
})?;
|
||||
|
||||
debug!("Popup callbacks configured successfully");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -68,54 +68,84 @@ struct ActivePopup {
|
|||
window: Rc<PopupWindow>,
|
||||
}
|
||||
|
||||
struct PopupState {
|
||||
scale_factor: f32,
|
||||
output_size: PhysicalSize,
|
||||
}
|
||||
|
||||
struct PendingPopup {
|
||||
request: PopupRequest,
|
||||
width: f32,
|
||||
height: f32,
|
||||
}
|
||||
|
||||
pub struct PopupManager {
|
||||
context: PopupContext,
|
||||
popups: RefCell<Slab<ActivePopup>>,
|
||||
current_scale_factor: RefCell<f32>,
|
||||
current_output_size: RefCell<PhysicalSize>,
|
||||
pending_popup_request: RefCell<Option<(PopupRequest, f32, f32)>>,
|
||||
last_popup_key: RefCell<Option<usize>>,
|
||||
state: RefCell<PopupState>,
|
||||
current_popup_key: RefCell<Option<usize>>,
|
||||
pending_popup: RefCell<Option<PendingPopup>>,
|
||||
}
|
||||
|
||||
impl PopupManager {
|
||||
#[must_use]
|
||||
pub const fn new(context: PopupContext, initial_scale_factor: f32) -> Self {
|
||||
pub fn new(context: PopupContext, initial_scale_factor: f32) -> Self {
|
||||
Self {
|
||||
context,
|
||||
popups: RefCell::new(Slab::new()),
|
||||
current_scale_factor: RefCell::new(initial_scale_factor),
|
||||
current_output_size: RefCell::new(PhysicalSize::new(0, 0)),
|
||||
pending_popup_request: RefCell::new(None),
|
||||
last_popup_key: RefCell::new(None),
|
||||
state: RefCell::new(PopupState {
|
||||
scale_factor: initial_scale_factor,
|
||||
output_size: PhysicalSize::new(0, 0),
|
||||
}),
|
||||
current_popup_key: RefCell::new(None),
|
||||
pending_popup: RefCell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_pending_popup_request(&self, request: PopupRequest, width: f32, height: f32) {
|
||||
*self.pending_popup_request.borrow_mut() = Some((request, width, height));
|
||||
pub fn set_pending_popup(&self, request: PopupRequest, width: f32, height: f32) {
|
||||
*self.pending_popup.borrow_mut() = Some(PendingPopup {
|
||||
request,
|
||||
width,
|
||||
height,
|
||||
});
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn take_pending_popup_request(&self) -> Option<(PopupRequest, f32, f32)> {
|
||||
self.pending_popup_request.borrow_mut().take()
|
||||
pub fn take_pending_popup(&self) -> Option<(PopupRequest, f32, f32)> {
|
||||
self.pending_popup
|
||||
.borrow_mut()
|
||||
.take()
|
||||
.map(|p| (p.request, p.width, p.height))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn scale_factor(&self) -> f32 {
|
||||
self.state.borrow().scale_factor
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn output_size(&self) -> PhysicalSize {
|
||||
self.state.borrow().output_size
|
||||
}
|
||||
|
||||
pub fn update_scale_factor(&self, scale_factor: f32) {
|
||||
self.state.borrow_mut().scale_factor = scale_factor;
|
||||
}
|
||||
|
||||
pub fn update_output_size(&self, output_size: PhysicalSize) {
|
||||
self.state.borrow_mut().output_size = output_size;
|
||||
}
|
||||
|
||||
pub fn close_current_popup(&self) {
|
||||
let key = self.last_popup_key.borrow_mut().take();
|
||||
let key = self.current_popup_key.borrow_mut().take();
|
||||
if let Some(key) = key {
|
||||
self.destroy_popup(key);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_scale_factor(&self, scale_factor: f32) {
|
||||
*self.current_scale_factor.borrow_mut() = scale_factor;
|
||||
}
|
||||
|
||||
pub fn update_output_size(&self, output_size: PhysicalSize) {
|
||||
*self.current_output_size.borrow_mut() = output_size;
|
||||
}
|
||||
|
||||
pub fn output_size(&self) -> PhysicalSize {
|
||||
*self.current_output_size.borrow()
|
||||
#[must_use]
|
||||
pub fn current_popup_key(&self) -> Option<usize> {
|
||||
*self.current_popup_key.borrow()
|
||||
}
|
||||
|
||||
pub fn create_popup(
|
||||
|
|
@ -130,7 +160,7 @@ impl PopupManager {
|
|||
}
|
||||
})?;
|
||||
|
||||
let scale_factor = *self.current_scale_factor.borrow();
|
||||
let scale_factor = self.scale_factor();
|
||||
info!(
|
||||
"Creating popup window with scale factor {scale_factor}, reference=({}, {}), size=({} x {}), mode={:?}",
|
||||
params.reference_x,
|
||||
|
|
@ -192,7 +222,7 @@ impl PopupManager {
|
|||
window: Rc::clone(&popup_window),
|
||||
});
|
||||
popup_window.set_popup_manager(Rc::downgrade(self), key);
|
||||
*self.last_popup_key.borrow_mut() = Some(key);
|
||||
*self.current_popup_key.borrow_mut() = Some(key);
|
||||
|
||||
info!("Popup window created successfully with key {key}");
|
||||
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ impl RuntimeState<'_> {
|
|||
self.window_state.compilation_result()
|
||||
}
|
||||
|
||||
pub fn show_popup(&mut self, req: PopupRequest) -> Result<()> {
|
||||
pub fn show_popup(&mut self, req: PopupRequest) -> Result<PopupHandle> {
|
||||
let compilation_result = self.compilation_result().ok_or_else(|| {
|
||||
Error::Domain(DomainError::Configuration {
|
||||
message: "No compilation result available for popup creation".to_string(),
|
||||
|
|
@ -172,7 +172,7 @@ impl RuntimeState<'_> {
|
|||
.map(Rc::clone)?;
|
||||
|
||||
log::debug!(
|
||||
"Setting pending popup request for '{}' with dimensions {}x{} at position ({}, {}), mode: {:?}",
|
||||
"Creating popup for '{}' with dimensions {}x{} at position ({}, {}), mode: {:?}",
|
||||
req.component,
|
||||
width,
|
||||
height,
|
||||
|
|
@ -181,11 +181,17 @@ impl RuntimeState<'_> {
|
|||
req.mode
|
||||
);
|
||||
|
||||
popup_manager.set_pending_popup_request(req, width, height);
|
||||
popup_manager.set_pending_popup(req.clone(), width, height);
|
||||
|
||||
Self::create_popup_instance(&definition, &popup_manager)?;
|
||||
|
||||
Ok(())
|
||||
Ok(PopupHandle::new(
|
||||
popup_manager.current_popup_key().ok_or_else(|| {
|
||||
Error::Domain(DomainError::Configuration {
|
||||
message: "No popup key available after creation".to_string(),
|
||||
})
|
||||
})?,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn close_popup(&mut self, handle: PopupHandle) -> Result<()> {
|
||||
|
|
|
|||
|
|
@ -4,5 +4,6 @@ pub mod keyboard_interactivity;
|
|||
pub mod layer;
|
||||
pub mod margins;
|
||||
pub mod popup_config;
|
||||
pub mod popup_dimensions;
|
||||
pub mod popup_positioning_mode;
|
||||
pub mod popup_request;
|
||||
|
|
|
|||
42
domain/src/value_objects/popup_dimensions.rs
Normal file
42
domain/src/value_objects/popup_dimensions.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
use crate::errors::{DomainError, Result};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct PopupDimensions {
|
||||
width: f32,
|
||||
height: f32,
|
||||
}
|
||||
|
||||
impl PopupDimensions {
|
||||
#[must_use]
|
||||
pub const fn new(width: f32, height: f32) -> Self {
|
||||
Self { width, height }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn width(&self) -> f32 {
|
||||
self.width
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn height(&self) -> f32 {
|
||||
self.height
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> Result<()> {
|
||||
if self.width <= 0.0 || self.height <= 0.0 {
|
||||
return Err(DomainError::Configuration {
|
||||
message: format!(
|
||||
"Invalid popup dimensions: width={}, height={}. Both must be positive.",
|
||||
self.width, self.height
|
||||
),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PopupDimensions {
|
||||
fn default() -> Self {
|
||||
Self::new(120.0, 120.0)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue