mirror of
https://codeberg.org/waydeer/layer-shika.git
synced 2025-11-04 07:24:24 +00:00
feat: make popup requests explicit and typed
This commit is contained in:
parent
f604a49268
commit
a32140d41d
5 changed files with 252 additions and 101 deletions
|
|
@ -180,11 +180,25 @@ impl WaylandWindowingSystem {
|
||||||
|
|
||||||
let serial = serial_holder.get();
|
let serial = serial_holder.get();
|
||||||
|
|
||||||
let params = popup_manager_clone.take_pending_popup_config();
|
let params = if let Some((request, width, height)) = popup_manager_clone.take_pending_popup_request() {
|
||||||
|
log::info!(
|
||||||
|
"Using popup request: component='{}', position=({}, {}), size={}x{}, mode={:?}",
|
||||||
|
request.component,
|
||||||
|
request.at.position().0,
|
||||||
|
request.at.position().1,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
request.mode
|
||||||
|
);
|
||||||
|
|
||||||
let params = if let Some(mut p) = params {
|
CreatePopupParams {
|
||||||
p.last_pointer_serial = serial;
|
last_pointer_serial: serial,
|
||||||
p
|
reference_x: request.at.position().0,
|
||||||
|
reference_y: request.at.position().1,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
positioning_mode: request.mode,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let output_size = popup_manager_clone.output_size();
|
let output_size = popup_manager_clone.output_size();
|
||||||
#[allow(clippy::cast_precision_loss)]
|
#[allow(clippy::cast_precision_loss)]
|
||||||
|
|
@ -192,7 +206,7 @@ impl WaylandWindowingSystem {
|
||||||
#[allow(clippy::cast_precision_loss)]
|
#[allow(clippy::cast_precision_loss)]
|
||||||
let default_height = output_size.height as f32;
|
let default_height = output_size.height as f32;
|
||||||
|
|
||||||
log::warn!("No popup config provided, using output size ({default_width}x{default_height}) as defaults");
|
log::warn!("No popup request provided, using output size ({default_width}x{default_height}) as defaults");
|
||||||
CreatePopupParams {
|
CreatePopupParams {
|
||||||
last_pointer_serial: serial,
|
last_pointer_serial: serial,
|
||||||
reference_x: 0.0,
|
reference_x: 0.0,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use crate::rendering::egl::context::EGLContext;
|
||||||
use crate::rendering::femtovg::popup_window::PopupWindow;
|
use crate::rendering::femtovg::popup_window::PopupWindow;
|
||||||
use layer_shika_domain::value_objects::popup_config::PopupConfig;
|
use layer_shika_domain::value_objects::popup_config::PopupConfig;
|
||||||
use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
|
use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
|
||||||
|
use layer_shika_domain::value_objects::popup_request::PopupRequest;
|
||||||
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};
|
||||||
|
|
@ -72,7 +73,7 @@ pub struct PopupManager {
|
||||||
popups: RefCell<Slab<ActivePopup>>,
|
popups: RefCell<Slab<ActivePopup>>,
|
||||||
current_scale_factor: RefCell<f32>,
|
current_scale_factor: RefCell<f32>,
|
||||||
current_output_size: RefCell<PhysicalSize>,
|
current_output_size: RefCell<PhysicalSize>,
|
||||||
pending_popup_config: RefCell<Option<CreatePopupParams>>,
|
pending_popup_request: RefCell<Option<(PopupRequest, f32, f32)>>,
|
||||||
last_popup_key: RefCell<Option<usize>>,
|
last_popup_key: RefCell<Option<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,33 +85,18 @@ impl PopupManager {
|
||||||
popups: RefCell::new(Slab::new()),
|
popups: RefCell::new(Slab::new()),
|
||||||
current_scale_factor: RefCell::new(initial_scale_factor),
|
current_scale_factor: RefCell::new(initial_scale_factor),
|
||||||
current_output_size: RefCell::new(PhysicalSize::new(0, 0)),
|
current_output_size: RefCell::new(PhysicalSize::new(0, 0)),
|
||||||
pending_popup_config: RefCell::new(None),
|
pending_popup_request: RefCell::new(None),
|
||||||
last_popup_key: RefCell::new(None),
|
last_popup_key: RefCell::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_pending_popup_config(
|
pub fn set_pending_popup_request(&self, request: PopupRequest, width: f32, height: f32) {
|
||||||
&self,
|
*self.pending_popup_request.borrow_mut() = Some((request, width, height));
|
||||||
reference_x: f32,
|
|
||||||
reference_y: f32,
|
|
||||||
width: f32,
|
|
||||||
height: f32,
|
|
||||||
positioning_mode: PopupPositioningMode,
|
|
||||||
) {
|
|
||||||
let last_pointer_serial = 0;
|
|
||||||
*self.pending_popup_config.borrow_mut() = Some(CreatePopupParams {
|
|
||||||
last_pointer_serial,
|
|
||||||
reference_x,
|
|
||||||
reference_y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
positioning_mode,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn take_pending_popup_config(&self) -> Option<CreatePopupParams> {
|
pub fn take_pending_popup_request(&self) -> Option<(PopupRequest, f32, f32)> {
|
||||||
self.pending_popup_config.borrow_mut().take()
|
self.pending_popup_request.borrow_mut().take()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close_current_popup(&self) {
|
pub fn close_current_popup(&self) {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@ use layer_shika_adapters::wayland::{
|
||||||
use layer_shika_domain::config::WindowConfig;
|
use layer_shika_domain::config::WindowConfig;
|
||||||
use layer_shika_domain::errors::DomainError;
|
use layer_shika_domain::errors::DomainError;
|
||||||
use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
|
use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
|
||||||
|
use layer_shika_domain::value_objects::popup_request::{
|
||||||
|
PopupAt, PopupHandle, PopupRequest, PopupSize,
|
||||||
|
};
|
||||||
use std::cell::{Ref, RefCell};
|
use std::cell::{Ref, RefCell};
|
||||||
use std::os::unix::io::AsFd;
|
use std::os::unix::io::AsFd;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
|
|
@ -129,6 +132,69 @@ impl RuntimeState<'_> {
|
||||||
self.window_state.compilation_result()
|
self.window_state.compilation_result()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn show_popup(&mut self, req: PopupRequest) -> Result<()> {
|
||||||
|
let compilation_result = self.compilation_result().ok_or_else(|| {
|
||||||
|
Error::Domain(DomainError::Configuration {
|
||||||
|
message: "No compilation result available for popup creation".to_string(),
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let definition = compilation_result
|
||||||
|
.component(&req.component)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
Error::Domain(DomainError::Configuration {
|
||||||
|
message: format!(
|
||||||
|
"{} component not found in compilation result",
|
||||||
|
req.component
|
||||||
|
),
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.close_current_popup()?;
|
||||||
|
|
||||||
|
let (width, height) = match req.size {
|
||||||
|
PopupSize::Fixed { w, h } => {
|
||||||
|
log::debug!("Using fixed popup size: {}x{}", w, h);
|
||||||
|
(w, h)
|
||||||
|
}
|
||||||
|
PopupSize::Content => self.measure_popup_dimensions(&definition)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
let popup_manager = self
|
||||||
|
.window_state
|
||||||
|
.popup_manager()
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
Error::Domain(DomainError::Configuration {
|
||||||
|
message: "No popup manager available".to_string(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.map(Rc::clone)?;
|
||||||
|
|
||||||
|
log::debug!(
|
||||||
|
"Setting pending popup request for '{}' with dimensions {}x{} at position ({}, {}), mode: {:?}",
|
||||||
|
req.component,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
req.at.position().0,
|
||||||
|
req.at.position().1,
|
||||||
|
req.mode
|
||||||
|
);
|
||||||
|
|
||||||
|
popup_manager.set_pending_popup_request(req, width, height);
|
||||||
|
|
||||||
|
Self::create_popup_instance(&definition, &popup_manager)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close_popup(&mut self, handle: PopupHandle) -> Result<()> {
|
||||||
|
if let Some(popup_manager) = self.window_state.popup_manager() {
|
||||||
|
popup_manager.destroy_popup(handle.key());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn close_current_popup(&mut self) -> Result<()> {
|
pub fn close_current_popup(&mut self) -> Result<()> {
|
||||||
if let Some(popup_manager) = self.window_state.popup_manager() {
|
if let Some(popup_manager) = self.window_state.popup_manager() {
|
||||||
popup_manager.close_current_popup();
|
popup_manager.close_current_popup();
|
||||||
|
|
@ -208,78 +274,6 @@ impl RuntimeState<'_> {
|
||||||
|
|
||||||
Ok(instance)
|
Ok(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_popup_component(
|
|
||||||
&mut self,
|
|
||||||
component_name: &str,
|
|
||||||
position: Option<(f32, f32)>,
|
|
||||||
size: Option<(f32, f32)>,
|
|
||||||
positioning_mode: PopupPositioningMode,
|
|
||||||
) -> Result<()> {
|
|
||||||
let compilation_result = self.compilation_result().ok_or_else(|| {
|
|
||||||
Error::Domain(DomainError::Configuration {
|
|
||||||
message: "No compilation result available for popup creation".to_string(),
|
|
||||||
})
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let definition = compilation_result
|
|
||||||
.component(component_name)
|
|
||||||
.ok_or_else(|| {
|
|
||||||
Error::Domain(DomainError::Configuration {
|
|
||||||
message: format!(
|
|
||||||
"{} component not found in compilation result",
|
|
||||||
component_name
|
|
||||||
),
|
|
||||||
})
|
|
||||||
})?;
|
|
||||||
|
|
||||||
self.close_current_popup()?;
|
|
||||||
|
|
||||||
let (width, height) = if let Some(explicit_size) = size {
|
|
||||||
log::debug!(
|
|
||||||
"Using explicit popup size: {}x{}",
|
|
||||||
explicit_size.0,
|
|
||||||
explicit_size.1
|
|
||||||
);
|
|
||||||
explicit_size
|
|
||||||
} else {
|
|
||||||
self.measure_popup_dimensions(&definition)?
|
|
||||||
};
|
|
||||||
|
|
||||||
let popup_manager = self
|
|
||||||
.window_state
|
|
||||||
.popup_manager()
|
|
||||||
.as_ref()
|
|
||||||
.ok_or_else(|| {
|
|
||||||
Error::Domain(DomainError::Configuration {
|
|
||||||
message: "No popup manager available".to_string(),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.map(Rc::clone)?;
|
|
||||||
|
|
||||||
let (reference_x, reference_y) = position.unwrap_or((0.0, 0.0));
|
|
||||||
|
|
||||||
popup_manager.set_pending_popup_config(
|
|
||||||
reference_x,
|
|
||||||
reference_y,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
positioning_mode,
|
|
||||||
);
|
|
||||||
|
|
||||||
log::debug!(
|
|
||||||
"Creating final popup instance with dimensions {}x{} at position ({}, {}), mode: {:?}",
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
reference_x,
|
|
||||||
reference_y,
|
|
||||||
positioning_mode
|
|
||||||
);
|
|
||||||
|
|
||||||
Self::create_popup_instance(&definition, &popup_manager)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WindowingSystem {
|
pub struct WindowingSystem {
|
||||||
|
|
@ -344,9 +338,14 @@ impl WindowingSystem {
|
||||||
let (_token, sender) = event_loop_handle.add_channel(
|
let (_token, sender) = event_loop_handle.add_channel(
|
||||||
move |(component_name, x, y): (String, f32, f32), mut state| {
|
move |(component_name, x, y): (String, f32, f32), mut state| {
|
||||||
let mode = *popup_mode_for_channel.borrow();
|
let mode = *popup_mode_for_channel.borrow();
|
||||||
if let Err(e) =
|
|
||||||
state.show_popup_component(&component_name, Some((x, y)), None, mode)
|
let request = PopupRequest::builder(component_name)
|
||||||
{
|
.at(PopupAt::absolute(x, y))
|
||||||
|
.size(PopupSize::content())
|
||||||
|
.mode(mode)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if let Err(e) = state.show_popup(request) {
|
||||||
log::error!("Failed to show popup: {}", e);
|
log::error!("Failed to show popup: {}", e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,4 @@ pub mod layer;
|
||||||
pub mod margins;
|
pub mod margins;
|
||||||
pub mod popup_config;
|
pub mod popup_config;
|
||||||
pub mod popup_positioning_mode;
|
pub mod popup_positioning_mode;
|
||||||
|
pub mod popup_request;
|
||||||
|
|
|
||||||
151
domain/src/value_objects/popup_request.rs
Normal file
151
domain/src/value_objects/popup_request.rs
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
use super::popup_positioning_mode::PopupPositioningMode;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
|
pub struct PopupHandle(usize);
|
||||||
|
|
||||||
|
impl PopupHandle {
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(key: usize) -> Self {
|
||||||
|
Self(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn key(self) -> usize {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct PopupRequest {
|
||||||
|
pub component: String,
|
||||||
|
pub at: PopupAt,
|
||||||
|
pub size: PopupSize,
|
||||||
|
pub mode: PopupPositioningMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PopupRequest {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(
|
||||||
|
component: String,
|
||||||
|
at: PopupAt,
|
||||||
|
size: PopupSize,
|
||||||
|
mode: PopupPositioningMode,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
component,
|
||||||
|
at,
|
||||||
|
size,
|
||||||
|
mode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn builder(component: String) -> PopupRequestBuilder {
|
||||||
|
PopupRequestBuilder::new(component)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum PopupAt {
|
||||||
|
Absolute { x: f32, y: f32 },
|
||||||
|
Cursor,
|
||||||
|
AnchorRect { x: f32, y: f32, w: f32, h: f32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PopupAt {
|
||||||
|
#[must_use]
|
||||||
|
pub const fn absolute(x: f32, y: f32) -> Self {
|
||||||
|
Self::Absolute { x, y }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn cursor() -> Self {
|
||||||
|
Self::Cursor
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn anchor_rect(x: f32, y: f32, w: f32, h: f32) -> Self {
|
||||||
|
Self::AnchorRect { x, y, w, h }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn position(&self) -> (f32, f32) {
|
||||||
|
match *self {
|
||||||
|
Self::Absolute { x, y } | Self::AnchorRect { x, y, .. } => (x, y),
|
||||||
|
Self::Cursor => (0.0, 0.0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum PopupSize {
|
||||||
|
Fixed { w: f32, h: f32 },
|
||||||
|
Content,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PopupSize {
|
||||||
|
#[must_use]
|
||||||
|
pub const fn fixed(w: f32, h: f32) -> Self {
|
||||||
|
Self::Fixed { w, h }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn content() -> Self {
|
||||||
|
Self::Content
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn dimensions(&self) -> Option<(f32, f32)> {
|
||||||
|
match *self {
|
||||||
|
Self::Fixed { w, h } => Some((w, h)),
|
||||||
|
Self::Content => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PopupRequestBuilder {
|
||||||
|
component: String,
|
||||||
|
at: PopupAt,
|
||||||
|
size: PopupSize,
|
||||||
|
mode: PopupPositioningMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PopupRequestBuilder {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(component: String) -> Self {
|
||||||
|
Self {
|
||||||
|
component,
|
||||||
|
at: PopupAt::Cursor,
|
||||||
|
size: PopupSize::Content,
|
||||||
|
mode: PopupPositioningMode::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn at(mut self, at: PopupAt) -> Self {
|
||||||
|
self.at = at;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn size(mut self, size: PopupSize) -> Self {
|
||||||
|
self.size = size;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn mode(mut self, mode: PopupPositioningMode) -> Self {
|
||||||
|
self.mode = mode;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn build(self) -> PopupRequest {
|
||||||
|
PopupRequest {
|
||||||
|
component: self.component,
|
||||||
|
at: self.at,
|
||||||
|
size: self.size,
|
||||||
|
mode: self.mode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue