mirror of
https://codeberg.org/waydeer/layer-shika.git
synced 2026-01-22 08:15:54 +00:00
refactor: improve popup state management for compile-time safety
This commit is contained in:
parent
c64bf8859e
commit
d7008cd065
3 changed files with 42 additions and 23 deletions
|
|
@ -42,7 +42,7 @@ pub use layer_shika_domain::value_objects::{
|
||||||
pub use layer_surface::{LayerSurfaceHandle, ShellSurfaceConfigHandler};
|
pub use layer_surface::{LayerSurfaceHandle, ShellSurfaceConfigHandler};
|
||||||
pub use lock_selection::LockSelection;
|
pub use lock_selection::LockSelection;
|
||||||
pub use popup::PopupShell;
|
pub use popup::PopupShell;
|
||||||
pub use popup_builder::PopupBuilder;
|
pub use popup_builder::{Bound, PopupBuilder, Unbound};
|
||||||
pub use selection::{PropertyError, Selection, SelectionResult};
|
pub use selection::{PropertyError, Selection, SelectionResult};
|
||||||
pub use selector::{Output, Selector, Surface, SurfaceInfo};
|
pub use selector::{Output, Selector, Surface, SurfaceInfo};
|
||||||
pub use session_lock::{SessionLock, SessionLockBuilder};
|
pub use session_lock::{SessionLock, SessionLockBuilder};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::popup_builder::PopupBuilder;
|
use crate::popup_builder::{Bound, PopupBuilder};
|
||||||
use crate::system::{PopupCommand, ShellCommand, ShellControl};
|
use crate::system::{PopupCommand, ShellCommand, ShellControl};
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use layer_shika_adapters::platform::calloop::channel;
|
use layer_shika_adapters::platform::calloop::channel;
|
||||||
|
|
@ -17,8 +17,11 @@ impl PopupShell {
|
||||||
Self { sender }
|
Self { sender }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a popup builder bound to this shell
|
||||||
|
///
|
||||||
|
/// The returned builder can call `.show()` directly because it's bound to a shell.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn builder(&self, component: impl Into<String>) -> PopupBuilder {
|
pub fn builder(&self, component: impl Into<String>) -> PopupBuilder<Bound> {
|
||||||
PopupBuilder::new(component).with_shell(self.clone())
|
PopupBuilder::new(component).with_shell(self.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
|
use crate::Result;
|
||||||
use crate::popup::PopupShell;
|
use crate::popup::PopupShell;
|
||||||
use crate::{Error, Result};
|
|
||||||
use layer_shika_domain::dimensions::LogicalRect;
|
use layer_shika_domain::dimensions::LogicalRect;
|
||||||
use layer_shika_domain::errors::DomainError;
|
|
||||||
use layer_shika_domain::value_objects::handle::PopupHandle;
|
use layer_shika_domain::value_objects::handle::PopupHandle;
|
||||||
use layer_shika_domain::value_objects::output_target::OutputTarget;
|
use layer_shika_domain::value_objects::output_target::OutputTarget;
|
||||||
use layer_shika_domain::value_objects::popup_behavior::ConstraintAdjustment;
|
use layer_shika_domain::value_objects::popup_behavior::ConstraintAdjustment;
|
||||||
|
|
@ -11,9 +10,19 @@ use layer_shika_domain::value_objects::popup_position::{
|
||||||
};
|
};
|
||||||
use layer_shika_domain::value_objects::popup_size::PopupSize;
|
use layer_shika_domain::value_objects::popup_size::PopupSize;
|
||||||
|
|
||||||
|
/// Type state indicating the builder is not bound to a shell
|
||||||
|
pub struct Unbound;
|
||||||
|
|
||||||
|
/// Type state indicating the builder is bound to a shell
|
||||||
|
pub struct Bound {
|
||||||
|
shell: PopupShell,
|
||||||
|
}
|
||||||
|
|
||||||
/// Builder for configuring popups
|
/// Builder for configuring popups
|
||||||
///
|
///
|
||||||
/// Produces a [`PopupConfig`] and can show it via [`PopupShell`].
|
/// The builder uses phantom types to ensure compile-time safety:
|
||||||
|
/// - [`PopupBuilder<Unbound>`] - Configuration only, cannot show popups
|
||||||
|
/// - [`PopupBuilder<Bound>`] - Has shell reference, can show popups
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
|
|
@ -25,27 +34,34 @@ use layer_shika_domain::value_objects::popup_size::PopupSize;
|
||||||
/// .show()?;
|
/// .show()?;
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
pub struct PopupBuilder {
|
pub struct PopupBuilder<State = Unbound> {
|
||||||
shell: Option<PopupShell>,
|
state: State,
|
||||||
config: PopupConfig,
|
config: PopupConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PopupBuilder {
|
impl PopupBuilder<Unbound> {
|
||||||
/// Creates a new popup builder for the specified component
|
/// Creates a new popup builder for the specified component
|
||||||
|
///
|
||||||
|
/// This builder is unbound and cannot show popups directly.
|
||||||
|
/// Use [`PopupShell::builder`] to create a bound builder that can call `.show()`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(component: impl Into<String>) -> Self {
|
pub fn new(component: impl Into<String>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
shell: None,
|
state: Unbound,
|
||||||
config: PopupConfig::new(component),
|
config: PopupConfig::new(component),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn with_shell(mut self, shell: PopupShell) -> Self {
|
pub(crate) fn with_shell(self, shell: PopupShell) -> PopupBuilder<Bound> {
|
||||||
self.shell = Some(shell);
|
PopupBuilder {
|
||||||
self
|
state: Bound { shell },
|
||||||
|
config: self.config,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<State> PopupBuilder<State> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn position(mut self, position: PopupPosition) -> Self {
|
pub fn position(mut self, position: PopupPosition) -> Self {
|
||||||
self.config.position = position;
|
self.config.position = position;
|
||||||
|
|
@ -203,21 +219,21 @@ impl PopupBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds the configuration without showing the popup
|
||||||
|
///
|
||||||
|
/// Returns a [`PopupConfig`] that can be shown later using [`PopupShell::show`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn build(self) -> PopupConfig {
|
pub fn build(self) -> PopupConfig {
|
||||||
self.config
|
self.config
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PopupBuilder<Bound> {
|
||||||
|
/// Shows the popup with the configured settings
|
||||||
|
///
|
||||||
|
/// This method is only available on builders created via [`PopupShell::builder`],
|
||||||
|
/// ensuring at compile time that the builder has access to a shell.
|
||||||
pub fn show(self) -> Result<PopupHandle> {
|
pub fn show(self) -> Result<PopupHandle> {
|
||||||
let Some(shell) = self.shell else {
|
self.state.shell.show(self.config)
|
||||||
return Err(Error::Domain(DomainError::Configuration {
|
|
||||||
message: "PopupBuilder::show() requires a builder created via `shell.popups().builder(...)`".to_string(),
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
shell.show(self.config)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_with_shell(self, shell: &PopupShell) -> Result<PopupHandle> {
|
|
||||||
shell.show(self.build())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue