refactor: remove the convention over configuration concept and decouple popup management

This commit is contained in:
drendog 2025-11-25 01:31:46 +01:00
parent dac315b589
commit 58278cecef
Signed by: dwenya
GPG key ID: 8DD77074645332D0
8 changed files with 340 additions and 342 deletions

View file

@ -1,7 +1,6 @@
#![allow(clippy::pub_use)]
mod builder;
mod slint_callbacks;
mod system;
use layer_shika_adapters::errors::LayerShikaError;
@ -22,8 +21,7 @@ pub use layer_shika_domain::value_objects::popup_positioning_mode::PopupPosition
pub use layer_shika_domain::value_objects::popup_request::{
PopupAt, PopupHandle, PopupRequest, PopupSize,
};
pub use slint_callbacks::{SlintCallbackContract, SlintCallbackNames};
pub use system::{App, EventLoopHandle, ShellContext};
pub use system::{App, EventLoopHandle, ShellContext, ShellControl};
pub mod calloop {
pub use layer_shika_adapters::platform::calloop::{
@ -50,7 +48,7 @@ pub mod prelude {
AnchorEdges, App, EventLoopHandle, KeyboardInteractivity, Layer, LayerShika,
OutputGeometry, OutputHandle, OutputInfo, OutputPolicy, OutputRegistry, PopupAt,
PopupHandle, PopupPositioningMode, PopupRequest, PopupSize, PopupWindow, Result,
ShellContext, SlintCallbackContract, SlintCallbackNames,
ShellContext, ShellControl,
};
pub use crate::calloop::{Generic, Interest, Mode, PostAction, RegistrationToken, Timer};

View file

@ -1,277 +0,0 @@
use crate::system::PopupCommand;
use crate::{Error, Result};
use layer_shika_adapters::PopupManager;
use layer_shika_adapters::platform::calloop::channel;
use layer_shika_adapters::platform::slint::SharedString;
use layer_shika_adapters::platform::slint_interpreter::{ComponentInstance, Value};
use layer_shika_domain::errors::DomainError;
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::{Cell, RefCell};
use std::rc::Rc;
pub struct SlintCallbackNames;
impl SlintCallbackNames {
pub const SHOW_POPUP: &'static str = "show_popup";
pub const CHANGE_POPUP_SIZE: &'static str = "change_popup_size";
pub const SET_POPUP_POSITIONING_MODE: &'static str = "set_popup_positioning_mode";
pub const POPUP_CLOSED: &'static str = "closed";
}
pub struct SlintCallbackContract {
popup_positioning_mode: Rc<RefCell<PopupPositioningMode>>,
popup_command_sender: channel::Sender<PopupCommand>,
}
impl SlintCallbackContract {
#[must_use]
pub fn new(
popup_positioning_mode: Rc<RefCell<PopupPositioningMode>>,
popup_command_sender: channel::Sender<PopupCommand>,
) -> Self {
Self {
popup_positioning_mode,
popup_command_sender,
}
}
pub fn register_on_main_component(&self, component_instance: &ComponentInstance) -> Result<()> {
self.register_set_popup_positioning_mode_callback(component_instance)?;
self.register_show_popup_callback(component_instance)?;
Ok(())
}
pub fn register_on_popup_component(
instance: &ComponentInstance,
popup_manager: &Rc<PopupManager>,
resize_sender: Option<channel::Sender<PopupCommand>>,
popup_key_cell: &Rc<Cell<usize>>,
) -> Result<()> {
Self::register_popup_closed_callback(instance, popup_manager)?;
Self::register_change_popup_size_callback(
instance,
popup_manager,
resize_sender,
popup_key_cell,
);
Ok(())
}
fn register_set_popup_positioning_mode_callback(
&self,
component_instance: &ComponentInstance,
) -> Result<()> {
let popup_mode_clone = Rc::clone(&self.popup_positioning_mode);
component_instance
.set_callback(
SlintCallbackNames::SET_POPUP_POSITIONING_MODE,
move |args| {
let center_x: bool = args
.first()
.and_then(|v| v.clone().try_into().ok())
.unwrap_or(false);
let center_y: bool = args
.get(1)
.and_then(|v| v.clone().try_into().ok())
.unwrap_or(false);
let mode = PopupPositioningMode::from_flags(center_x, center_y);
*popup_mode_clone.borrow_mut() = mode;
log::info!(
"Popup positioning mode set to: {:?} (center_x: {}, center_y: {})",
mode,
center_x,
center_y
);
Value::Void
},
)
.map_err(|e| {
Error::Domain(DomainError::Configuration {
message: format!(
"Failed to register {} callback: {}",
SlintCallbackNames::SET_POPUP_POSITIONING_MODE,
e
),
})
})
}
fn register_show_popup_callback(&self, component_instance: &ComponentInstance) -> Result<()> {
let sender = self.popup_command_sender.clone();
let popup_mode_for_callback = Rc::clone(&self.popup_positioning_mode);
component_instance
.set_callback(SlintCallbackNames::SHOW_POPUP, move |args| {
let component_name: SharedString = args
.first()
.and_then(|v| v.clone().try_into().ok())
.unwrap_or_else(|| SharedString::from(""));
if component_name.is_empty() {
log::error!(
"{} called without component name",
SlintCallbackNames::SHOW_POPUP
);
return Value::Void;
}
let x: f32 = args
.get(1)
.and_then(|v| v.clone().try_into().ok())
.unwrap_or(0.0);
let y: f32 = args
.get(2)
.and_then(|v| v.clone().try_into().ok())
.unwrap_or(0.0);
let mode = *popup_mode_for_callback.borrow();
let request = PopupRequest::builder(component_name.to_string())
.at(PopupAt::absolute(x, y))
.size(PopupSize::content())
.mode(mode)
.build();
if sender.send(PopupCommand::Show(request)).is_err() {
log::error!("Failed to send popup show command through channel");
}
Value::Void
})
.map_err(|e| {
Error::Domain(DomainError::Configuration {
message: format!(
"Failed to register {} callback: {}",
SlintCallbackNames::SHOW_POPUP,
e
),
})
})
}
fn register_popup_closed_callback(
instance: &ComponentInstance,
popup_manager: &Rc<PopupManager>,
) -> Result<()> {
let popup_manager_weak = Rc::downgrade(popup_manager);
instance
.set_callback(SlintCallbackNames::POPUP_CLOSED, move |_| {
if let Some(popup_manager) = popup_manager_weak.upgrade() {
popup_manager.close_current_popup();
}
Value::Void
})
.map_err(|e| {
Error::Domain(DomainError::Configuration {
message: format!(
"Failed to set {} callback: {}",
SlintCallbackNames::POPUP_CLOSED,
e
),
})
})
}
fn register_change_popup_size_callback(
instance: &ComponentInstance,
popup_manager: &Rc<PopupManager>,
resize_sender: Option<channel::Sender<PopupCommand>>,
popup_key_cell: &Rc<Cell<usize>>,
) {
let result = if let Some(sender) = resize_sender {
let key_cell = Rc::clone(popup_key_cell);
instance.set_callback(SlintCallbackNames::CHANGE_POPUP_SIZE, move |args| {
let width: f32 = args
.first()
.and_then(|v| v.clone().try_into().ok())
.unwrap_or(200.0);
let height: f32 = args
.get(1)
.and_then(|v| v.clone().try_into().ok())
.unwrap_or(150.0);
let popup_key = key_cell.get();
log::info!(
"{} callback invoked: {}x{} for key {}",
SlintCallbackNames::CHANGE_POPUP_SIZE,
width,
height,
popup_key
);
if sender
.send(PopupCommand::Resize {
handle: PopupHandle::new(popup_key),
width,
height,
})
.is_err()
{
log::error!("Failed to send popup resize command through channel");
}
Value::Void
})
} else {
let popup_manager_for_resize = Rc::downgrade(popup_manager);
let key_cell = Rc::clone(popup_key_cell);
instance.set_callback(SlintCallbackNames::CHANGE_POPUP_SIZE, move |args| {
let width: f32 = args
.first()
.and_then(|v| v.clone().try_into().ok())
.unwrap_or(200.0);
let height: f32 = args
.get(1)
.and_then(|v| v.clone().try_into().ok())
.unwrap_or(150.0);
let popup_key = key_cell.get();
log::info!(
"{} callback invoked: {}x{} for key {}",
SlintCallbackNames::CHANGE_POPUP_SIZE,
width,
height,
popup_key
);
if let Some(popup_manager) = popup_manager_for_resize.upgrade() {
if let Some(popup_window) = popup_manager.get_popup_window(popup_key) {
popup_window.request_resize(width, height);
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_possible_wrap)]
let logical_width = width as i32;
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_possible_wrap)]
let logical_height = height as i32;
popup_manager.update_popup_viewport(popup_key, logical_width, logical_height);
log::debug!(
"Updated popup viewport to logical size: {}x{} (from direct resize to {}x{})",
logical_width,
logical_height,
width,
height
);
}
}
Value::Void
})
};
if let Err(e) = result {
log::warn!(
"Failed to set {} callback: {}",
SlintCallbackNames::CHANGE_POPUP_SIZE,
e
);
} else {
log::info!(
"{} callback registered successfully",
SlintCallbackNames::CHANGE_POPUP_SIZE
);
}
}
}

View file

@ -1,4 +1,3 @@
use crate::slint_callbacks::SlintCallbackContract;
use crate::{Error, Result};
use layer_shika_adapters::errors::EventLoopError;
use layer_shika_adapters::platform::calloop::{
@ -7,7 +6,7 @@ use layer_shika_adapters::platform::calloop::{
};
use layer_shika_adapters::platform::slint::ComponentHandle;
use layer_shika_adapters::platform::slint_interpreter::{
CompilationResult, ComponentDefinition, ComponentInstance,
CompilationResult, ComponentDefinition, ComponentInstance, Value,
};
use layer_shika_adapters::{
AppState, PopupManager, WaylandWindowConfig, WindowState, WindowingSystemFacade,
@ -17,7 +16,7 @@ use layer_shika_domain::entities::output_registry::OutputRegistry;
use layer_shika_domain::errors::DomainError;
use layer_shika_domain::value_objects::output_handle::OutputHandle;
use layer_shika_domain::value_objects::output_info::OutputInfo;
use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
use layer_shika_domain::value_objects::dimensions::PopupDimensions;
use layer_shika_domain::value_objects::popup_request::{PopupHandle, PopupRequest, PopupSize};
use std::cell::Cell;
use std::cell::RefCell;
@ -36,6 +35,47 @@ pub enum PopupCommand {
},
}
#[derive(Clone)]
pub struct ShellControl {
sender: channel::Sender<PopupCommand>,
}
impl ShellControl {
pub fn show_popup(&self, request: &PopupRequest) -> Result<()> {
self.sender
.send(PopupCommand::Show(request.clone()))
.map_err(|_| {
Error::Domain(DomainError::Configuration {
message: "Failed to send popup show command: channel closed".to_string(),
})
})
}
pub fn close_popup(&self, handle: PopupHandle) -> Result<()> {
self.sender
.send(PopupCommand::Close(handle))
.map_err(|_| {
Error::Domain(DomainError::Configuration {
message: "Failed to send popup close command: channel closed".to_string(),
})
})
}
pub fn resize_popup(&self, handle: PopupHandle, width: f32, height: f32) -> Result<()> {
self.sender
.send(PopupCommand::Resize {
handle,
width,
height,
})
.map_err(|_| {
Error::Domain(DomainError::Configuration {
message: "Failed to send popup resize command: channel closed".to_string(),
})
})
}
}
pub struct EventLoopHandle {
system: Weak<RefCell<WindowingSystemFacade>>,
}
@ -128,6 +168,18 @@ pub struct ShellContext<'a> {
app_state: &'a mut AppState,
}
fn extract_dimensions_from_callback(args: &[Value]) -> PopupDimensions {
let defaults = PopupDimensions::default();
PopupDimensions::new(
args.first()
.and_then(|v| v.clone().try_into().ok())
.unwrap_or(defaults.width),
args.get(1)
.and_then(|v| v.clone().try_into().ok())
.unwrap_or(defaults.height),
)
}
impl ShellContext<'_> {
#[must_use]
pub fn component_instance(&self) -> Option<&ComponentInstance> {
@ -204,8 +256,8 @@ impl ShellContext<'_> {
pub fn show_popup(
&mut self,
req: PopupRequest,
resize_sender: Option<channel::Sender<PopupCommand>>,
req: &PopupRequest,
resize_control: Option<ShellControl>,
) -> Result<PopupHandle> {
let compilation_result = self.compilation_result().ok_or_else(|| {
Error::Domain(DomainError::Configuration {
@ -266,10 +318,10 @@ impl ShellContext<'_> {
);
let popup_handle =
popup_manager.request_popup(req, initial_dimensions.0, initial_dimensions.1);
popup_manager.request_popup(req.clone(), initial_dimensions.0, initial_dimensions.1);
let (instance, popup_key_cell) =
Self::create_popup_instance(&definition, &popup_manager, resize_sender)?;
Self::create_popup_instance(&definition, &popup_manager, resize_control, req)?;
popup_key_cell.set(popup_handle.key());
@ -307,7 +359,7 @@ impl ShellContext<'_> {
handle: PopupHandle,
width: f32,
height: f32,
resize_sender: Option<channel::Sender<PopupCommand>>,
resize_control: Option<ShellControl>,
) -> Result<()> {
let active_window = self.active_or_primary_output().ok_or_else(|| {
Error::Domain(DomainError::Configuration {
@ -345,13 +397,21 @@ impl ShellContext<'_> {
self.close_popup(handle)?;
let new_request = PopupRequest::builder(request.component)
let mut builder = PopupRequest::builder(request.component)
.at(request.at)
.size(PopupSize::fixed(width, height))
.mode(request.mode)
.build();
.mode(request.mode);
self.show_popup(new_request, resize_sender)?;
if let Some(close_cb) = &request.close_callback {
builder = builder.close_on(close_cb.clone());
}
if let Some(resize_cb) = &request.resize_callback {
builder = builder.resize_on(resize_cb.clone());
}
let new_request = builder.build();
self.show_popup(&new_request, resize_control)?;
} else if size_changed {
if let Some(popup_window) = popup_manager.get_popup_window(handle.key()) {
popup_window.request_resize(width, height);
@ -380,7 +440,8 @@ impl ShellContext<'_> {
fn create_popup_instance(
definition: &ComponentDefinition,
popup_manager: &Rc<PopupManager>,
resize_sender: Option<channel::Sender<PopupCommand>>,
resize_control: Option<ShellControl>,
req: &PopupRequest,
) -> Result<(ComponentInstance, Rc<Cell<usize>>)> {
let instance = definition.create().map_err(|e| {
Error::Domain(DomainError::Configuration {
@ -390,11 +451,12 @@ impl ShellContext<'_> {
let popup_key_cell = Rc::new(Cell::new(0));
SlintCallbackContract::register_on_popup_component(
Self::register_popup_callbacks(
&instance,
popup_manager,
resize_sender,
resize_control,
&popup_key_cell,
req,
)?;
instance.show().map_err(|e| {
@ -405,12 +467,158 @@ impl ShellContext<'_> {
Ok((instance, popup_key_cell))
}
fn register_popup_callbacks(
instance: &ComponentInstance,
popup_manager: &Rc<PopupManager>,
resize_control: Option<ShellControl>,
popup_key_cell: &Rc<Cell<usize>>,
req: &PopupRequest,
) -> Result<()> {
if let Some(close_callback_name) = &req.close_callback {
Self::register_close_callback(instance, popup_manager, close_callback_name)?;
}
if let Some(resize_callback_name) = &req.resize_callback {
Self::register_resize_callback(
instance,
popup_manager,
resize_control,
popup_key_cell,
resize_callback_name,
)?;
}
Ok(())
}
fn register_close_callback(
instance: &ComponentInstance,
popup_manager: &Rc<PopupManager>,
callback_name: &str,
) -> Result<()> {
let popup_manager_weak = Rc::downgrade(popup_manager);
instance
.set_callback(callback_name, move |_| {
if let Some(popup_manager) = popup_manager_weak.upgrade() {
popup_manager.close_current_popup();
}
Value::Void
})
.map_err(|e| {
Error::Domain(DomainError::Configuration {
message: format!("Failed to set '{}' callback: {}", callback_name, e),
})
})
}
fn register_resize_callback(
instance: &ComponentInstance,
popup_manager: &Rc<PopupManager>,
resize_control: Option<ShellControl>,
popup_key_cell: &Rc<Cell<usize>>,
callback_name: &str,
) -> Result<()> {
if let Some(control) = resize_control {
Self::register_resize_with_control(instance, popup_key_cell, &control, callback_name)
} else {
Self::register_resize_direct(instance, popup_manager, popup_key_cell, callback_name)
}
}
fn register_resize_with_control(
instance: &ComponentInstance,
popup_key_cell: &Rc<Cell<usize>>,
control: &ShellControl,
callback_name: &str,
) -> Result<()> {
let key_cell = Rc::clone(popup_key_cell);
let control = control.clone();
instance
.set_callback(callback_name, move |args| {
let dimensions = extract_dimensions_from_callback(args);
let popup_key = key_cell.get();
log::info!(
"Resize callback invoked: {}x{} for key {}",
dimensions.width,
dimensions.height,
popup_key
);
if control
.resize_popup(PopupHandle::new(popup_key), dimensions.width, dimensions.height)
.is_err()
{
log::error!("Failed to resize popup through control");
}
Value::Void
})
.map_err(|e| {
Error::Domain(DomainError::Configuration {
message: format!("Failed to set '{}' callback: {}", callback_name, e),
})
})
}
fn register_resize_direct(
instance: &ComponentInstance,
popup_manager: &Rc<PopupManager>,
popup_key_cell: &Rc<Cell<usize>>,
callback_name: &str,
) -> Result<()> {
let popup_manager_weak = Rc::downgrade(popup_manager);
let key_cell = Rc::clone(popup_key_cell);
instance
.set_callback(callback_name, move |args| {
let dimensions = extract_dimensions_from_callback(args);
let popup_key = key_cell.get();
log::info!(
"Resize callback invoked: {}x{} for key {}",
dimensions.width,
dimensions.height,
popup_key
);
if let Some(popup_manager) = popup_manager_weak.upgrade() {
if let Some(popup_window) = popup_manager.get_popup_window(popup_key) {
popup_window.request_resize(dimensions.width, dimensions.height);
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_possible_wrap)]
let logical_width = dimensions.width as i32;
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_possible_wrap)]
let logical_height = dimensions.height as i32;
popup_manager.update_popup_viewport(
popup_key,
logical_width,
logical_height,
);
log::debug!(
"Updated popup viewport to logical size: {}x{} (from direct resize to {}x{})",
logical_width,
logical_height,
dimensions.width,
dimensions.height
);
}
}
Value::Void
})
.map_err(|e| {
Error::Domain(DomainError::Configuration {
message: format!("Failed to set '{}' callback: {}", callback_name, e),
})
})
}
}
pub struct App {
inner: Rc<RefCell<WindowingSystemFacade>>,
popup_command_sender: channel::Sender<PopupCommand>,
callback_contract: SlintCallbackContract,
}
impl App {
@ -430,25 +638,19 @@ impl App {
let (sender, receiver) = channel::channel();
let popup_positioning_mode = Rc::new(RefCell::new(PopupPositioningMode::Center));
let callback_contract =
SlintCallbackContract::new(Rc::clone(&popup_positioning_mode), sender.clone());
let system = Self {
inner: Rc::clone(&inner_rc),
popup_command_sender: sender,
callback_contract,
};
system.setup_popup_command_handler(receiver)?;
system.register_popup_callbacks();
Ok(system)
}
fn setup_popup_command_handler(&self, receiver: channel::Channel<PopupCommand>) -> Result<()> {
let loop_handle = self.inner.borrow().inner_ref().event_loop_handle();
let sender_for_handler = self.popup_command_sender.clone();
let control = self.control();
loop_handle
.insert_source(receiver, move |event, (), app_state| {
@ -457,8 +659,7 @@ impl App {
match command {
PopupCommand::Show(request) => {
if let Err(e) =
shell_context.show_popup(request, Some(sender_for_handler.clone()))
if let Err(e) = shell_context.show_popup(&request, Some(control.clone()))
{
log::error!("Failed to show popup: {}", e);
}
@ -473,12 +674,9 @@ impl App {
width,
height,
} => {
if let Err(e) = shell_context.resize_popup(
handle,
width,
height,
Some(sender_for_handler.clone()),
) {
if let Err(e) =
shell_context.resize_popup(handle, width, height, Some(control.clone()))
{
log::error!("Failed to resize popup: {}", e);
}
}
@ -497,15 +695,11 @@ impl App {
Ok(())
}
fn register_popup_callbacks(&self) {
self.with_all_component_instances(|component_instance| {
if let Err(e) = self
.callback_contract
.register_on_main_component(component_instance)
{
log::error!("Failed to register popup callbacks on output: {}", e);
#[must_use]
pub fn control(&self) -> ShellControl {
ShellControl {
sender: self.popup_command_sender.clone(),
}
});
}
#[must_use]
@ -515,24 +709,55 @@ impl App {
}
}
pub fn request_show_popup(&self, request: PopupRequest) -> Result<()> {
self.popup_command_sender
.send(PopupCommand::Show(request))
.map_err(|_| {
Error::Domain(DomainError::Configuration {
message: "Failed to send popup show command: channel closed".to_string(),
})
})
pub fn on_callback<F>(&self, callback_name: &str, handler: F) -> Result<()>
where
F: Fn(&[Value], ShellControl) -> Value + 'static,
{
let control = self.control();
let handler = Rc::new(handler);
self.with_all_component_instances(|instance| {
let handler_rc = Rc::clone(&handler);
let control_clone = control.clone();
if let Err(e) = instance.set_callback(callback_name, move |args| {
handler_rc(args, control_clone.clone())
}) {
log::error!(
"Failed to register callback '{}' on component: {}",
callback_name,
e
);
}
});
Ok(())
}
pub fn request_close_popup(&self, handle: PopupHandle) -> Result<()> {
self.popup_command_sender
.send(PopupCommand::Close(handle))
.map_err(|_| {
Error::Domain(DomainError::Configuration {
message: "Failed to send popup close command: channel closed".to_string(),
})
})
pub fn bind_popup<F>(&self, callback_name: &str, config_builder: F) -> Result<()>
where
F: Fn() -> PopupRequest + 'static,
{
let control = self.control();
let builder = Rc::new(config_builder);
self.with_all_component_instances(|instance| {
let builder_clone = Rc::clone(&builder);
let control_clone = control.clone();
if let Err(e) = instance.set_callback(callback_name, move |_args| {
let request = builder_clone();
if let Err(e) = control_clone.show_popup(&request) {
log::error!("Failed to show popup: {}", e);
}
Value::Void
}) {
log::error!(
"Failed to bind popup callback '{}': {}",
callback_name,
e
);
}
});
Ok(())
}
pub fn run(&mut self) -> Result<()> {

View file

@ -11,7 +11,7 @@ pub use crate::entities::window::WindowHandle;
pub use crate::errors::{DomainError, Result};
pub use crate::surface_dimensions::SurfaceDimensions;
pub use crate::value_objects::anchor::AnchorEdges;
pub use crate::value_objects::dimensions::WindowHeight;
pub use crate::value_objects::dimensions::{PopupDimensions, WindowHeight};
pub use crate::value_objects::keyboard_interactivity::KeyboardInteractivity;
pub use crate::value_objects::layer::Layer;
pub use crate::value_objects::margins::Margins;

View file

@ -31,3 +31,35 @@ impl From<u32> for WindowHeight {
Self::new(height)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PopupDimensions {
pub width: f32,
pub height: f32,
}
impl Default for PopupDimensions {
fn default() -> Self {
Self {
width: 200.0,
height: 150.0,
}
}
}
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
}
}

View file

@ -22,6 +22,8 @@ pub struct PopupRequest {
pub size: PopupSize,
pub mode: PopupPositioningMode,
pub grab: bool,
pub close_callback: Option<String>,
pub resize_callback: Option<String>,
}
impl PopupRequest {
@ -38,6 +40,8 @@ impl PopupRequest {
size,
mode,
grab: false,
close_callback: None,
resize_callback: None,
}
}
@ -111,6 +115,8 @@ pub struct PopupRequestBuilder {
size: PopupSize,
mode: PopupPositioningMode,
grab: bool,
close_callback: Option<String>,
resize_callback: Option<String>,
}
impl PopupRequestBuilder {
@ -122,6 +128,8 @@ impl PopupRequestBuilder {
size: PopupSize::Content,
mode: PopupPositioningMode::default(),
grab: false,
close_callback: None,
resize_callback: None,
}
}
@ -149,6 +157,18 @@ impl PopupRequestBuilder {
self
}
#[must_use]
pub fn close_on(mut self, callback_name: impl Into<String>) -> Self {
self.close_callback = Some(callback_name.into());
self
}
#[must_use]
pub fn resize_on(mut self, callback_name: impl Into<String>) -> Self {
self.resize_callback = Some(callback_name.into());
self
}
#[must_use]
pub fn build(self) -> PopupRequest {
PopupRequest {
@ -157,6 +177,8 @@ impl PopupRequestBuilder {
size: self.size,
mode: self.mode,
grab: self.grab,
close_callback: self.close_callback,
resize_callback: self.resize_callback,
}
}
}

View file

@ -44,8 +44,7 @@ pub mod prelude;
pub use layer_shika_composition::{
AnchorEdges, App, Error, EventLoopHandle, KeyboardInteractivity, Layer, LayerShika,
OutputGeometry, OutputHandle, OutputInfo, OutputPolicy, OutputRegistry, PopupAt, PopupHandle,
PopupPositioningMode, PopupRequest, PopupSize, PopupWindow, Result, ShellContext,
SlintCallbackContract, SlintCallbackNames,
PopupPositioningMode, PopupRequest, PopupSize, PopupWindow, Result, ShellContext, ShellControl,
};
pub use layer_shika_composition::{slint, slint_interpreter};

View file

@ -10,8 +10,7 @@
// Core API types
pub use crate::{
App, Error, EventLoopHandle, LayerShika, PopupWindow, Result, ShellContext,
SlintCallbackContract, SlintCallbackNames,
App, Error, EventLoopHandle, LayerShika, PopupWindow, Result, ShellContext, ShellControl,
};
// Domain value objects