chore: updates after iced rebase
This commit is contained in:
parent
7bb5ae7cfe
commit
a48c4fc47d
16 changed files with 753 additions and 736 deletions
|
|
@ -18,11 +18,7 @@ use cosmic::{
|
|||
window::Event as WindowEvent,
|
||||
},
|
||||
iced_core::{Color, Length, Pixels, clipboard::Null as NullClipboard, id::Id, renderer::Style},
|
||||
iced_runtime::{
|
||||
Action, Debug,
|
||||
program::{Program as IcedProgram, State},
|
||||
task::into_stream,
|
||||
},
|
||||
iced_runtime::{Action, task::into_stream},
|
||||
};
|
||||
use iced_tiny_skia::{
|
||||
Layer,
|
||||
|
|
@ -66,6 +62,8 @@ use smithay::{
|
|||
},
|
||||
};
|
||||
|
||||
use crate::utils::state::State;
|
||||
|
||||
static ID: LazyLock<Id> = LazyLock::new(|| Id::new("Program"));
|
||||
|
||||
pub struct IcedElement<P: Program + Send + 'static>(pub(crate) Arc<Mutex<IcedElementInternal<P>>>);
|
||||
|
|
@ -99,6 +97,26 @@ impl<P: Program + Send + 'static> Hash for IcedElement<P> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait IcedProgram {
|
||||
type Message: std::fmt::Debug + Send;
|
||||
fn update(&mut self, _message: Self::Message) -> Task<Self::Message> {
|
||||
Task::none()
|
||||
}
|
||||
fn view(&self) -> cosmic::Element<'_, Self::Message>;
|
||||
|
||||
fn background_color(&self) -> Color {
|
||||
Color::TRANSPARENT
|
||||
}
|
||||
|
||||
fn foreground(
|
||||
&self,
|
||||
_pixels: &mut tiny_skia::PixmapMut<'_>,
|
||||
_damage: &[Rectangle<i32, BufferCoords>],
|
||||
_scale: f32,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Program {
|
||||
type Message: std::fmt::Debug + Send;
|
||||
fn update(
|
||||
|
|
@ -135,8 +153,6 @@ struct ProgramWrapper<P: Program> {
|
|||
|
||||
impl<P: Program> IcedProgram for ProgramWrapper<P> {
|
||||
type Message = <P as Program>::Message;
|
||||
type Renderer = cosmic::Renderer;
|
||||
type Theme = cosmic::Theme;
|
||||
|
||||
fn update(&mut self, message: Self::Message) -> Task<Self::Message> {
|
||||
let last_seat = self.last_seat.lock().unwrap();
|
||||
|
|
@ -165,7 +181,6 @@ pub(crate) struct IcedElementInternal<P: Program + Send + 'static> {
|
|||
theme: Theme,
|
||||
renderer: cosmic::Renderer,
|
||||
state: State<ProgramWrapper<P>>,
|
||||
debug: Debug,
|
||||
|
||||
// futures
|
||||
handle: LoopHandle<'static, crate::state::State>,
|
||||
|
|
@ -189,7 +204,6 @@ impl<P: Program + Send + Clone + 'static> Clone for IcedElementInternal<P> {
|
|||
tracing::warn!("Missing force_update call");
|
||||
}
|
||||
let mut renderer = cosmic::Renderer::new(cosmic::font::default(), Pixels(16.0));
|
||||
let mut debug = Debug::new();
|
||||
let state = State::new(
|
||||
ID.clone(),
|
||||
ProgramWrapper {
|
||||
|
|
@ -199,7 +213,6 @@ impl<P: Program + Send + Clone + 'static> Clone for IcedElementInternal<P> {
|
|||
},
|
||||
IcedSize::new(self.size.w as f32, self.size.h as f32),
|
||||
&mut renderer,
|
||||
&mut debug,
|
||||
);
|
||||
|
||||
IcedElementInternal {
|
||||
|
|
@ -214,7 +227,6 @@ impl<P: Program + Send + Clone + 'static> Clone for IcedElementInternal<P> {
|
|||
theme: self.theme.clone(),
|
||||
renderer,
|
||||
state,
|
||||
debug,
|
||||
handle,
|
||||
scheduler,
|
||||
executor_token,
|
||||
|
|
@ -240,7 +252,6 @@ impl<P: Program + Send + 'static> fmt::Debug for IcedElementInternal<P> {
|
|||
.field("theme", &"...")
|
||||
.field("renderer", &"...")
|
||||
.field("state", &"...")
|
||||
.field("debug", &self.debug)
|
||||
.field("handle", &self.handle)
|
||||
.field("scheduler", &self.scheduler)
|
||||
.field("executor_token", &self.executor_token)
|
||||
|
|
@ -265,7 +276,6 @@ impl<P: Program + Send + 'static> IcedElement<P> {
|
|||
let size = size.into();
|
||||
let last_seat = Arc::new(Mutex::new(None));
|
||||
let mut renderer = cosmic::Renderer::new(cosmic::font::default(), Pixels(16.0));
|
||||
let mut debug = Debug::new();
|
||||
|
||||
let state = State::new(
|
||||
ID.clone(),
|
||||
|
|
@ -276,7 +286,6 @@ impl<P: Program + Send + 'static> IcedElement<P> {
|
|||
},
|
||||
IcedSize::new(size.w as f32, size.h as f32),
|
||||
&mut renderer,
|
||||
&mut debug,
|
||||
);
|
||||
|
||||
let (executor, scheduler) = calloop::futures::executor().expect("Out of file descriptors");
|
||||
|
|
@ -299,7 +308,6 @@ impl<P: Program + Send + 'static> IcedElement<P> {
|
|||
theme,
|
||||
renderer,
|
||||
state,
|
||||
debug,
|
||||
handle,
|
||||
scheduler,
|
||||
executor_token,
|
||||
|
|
@ -317,14 +325,16 @@ impl<P: Program + Send + 'static> IcedElement<P> {
|
|||
|
||||
pub fn minimum_size(&self) -> Size<i32, Logical> {
|
||||
let internal = self.0.lock().unwrap();
|
||||
let element = internal.state.program().program.view();
|
||||
let mut element = internal.state.program().program.view();
|
||||
|
||||
let mut tree = Tree::new(element.as_widget());
|
||||
let node = element
|
||||
.as_widget()
|
||||
.as_widget_mut()
|
||||
.layout(
|
||||
// TODO Avoid creating a new tree here?
|
||||
&mut Tree::new(element.as_widget()),
|
||||
&mut tree,
|
||||
&internal.renderer,
|
||||
&Limits::new(IcedSize::ZERO, IcedSize::INFINITY)
|
||||
&Limits::new(IcedSize::ZERO, IcedSize::INFINITE)
|
||||
.width(Length::Shrink)
|
||||
.height(Length::Shrink),
|
||||
)
|
||||
|
|
@ -432,7 +442,6 @@ impl<P: Program + Send + 'static> IcedElementInternal<P> {
|
|||
text_color: self.theme.cosmic().on_bg_color().into(),
|
||||
},
|
||||
&mut NullClipboard,
|
||||
&mut self.debug,
|
||||
)
|
||||
.1;
|
||||
|
||||
|
|
@ -922,7 +931,6 @@ where
|
|||
if size.w > 0 && size.h > 0 {
|
||||
let state_ref = &internal_ref.state;
|
||||
let mut clip_mask = tiny_skia::Mask::new(size.w as u32, size.h as u32).unwrap();
|
||||
let overlay = internal_ref.debug.overlay();
|
||||
let theme = &internal_ref.theme;
|
||||
|
||||
_ = buffer.render().draw(|buf| {
|
||||
|
|
@ -977,7 +985,6 @@ where
|
|||
&viewport,
|
||||
&damage,
|
||||
background_color,
|
||||
&overlay,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,4 +9,5 @@ pub mod prelude;
|
|||
pub mod quirks;
|
||||
pub mod rlimit;
|
||||
pub mod screenshot;
|
||||
pub mod state;
|
||||
pub mod tween;
|
||||
|
|
|
|||
222
src/utils/state.rs
Normal file
222
src/utils/state.rs
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
use super::iced::IcedProgram as Program;
|
||||
use cosmic::iced::core::event::{self, Event};
|
||||
use cosmic::iced::core::mouse;
|
||||
use cosmic::iced::core::renderer;
|
||||
use cosmic::iced::core::widget::operation::{self, Operation};
|
||||
use cosmic::iced::core::{Clipboard, Size};
|
||||
use cosmic::iced_core;
|
||||
use cosmic::iced_runtime::Task;
|
||||
use cosmic::iced_runtime::user_interface::{self, UserInterface};
|
||||
|
||||
/// The execution state of a [`Program`]. It leverages caching, event
|
||||
/// processing, and rendering primitive storage.
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct State<P>
|
||||
where
|
||||
P: Program + 'static,
|
||||
{
|
||||
program: P,
|
||||
cache: Option<user_interface::Cache>,
|
||||
queued_events: Vec<Event>,
|
||||
queued_messages: Vec<P::Message>,
|
||||
mouse_interaction: mouse::Interaction,
|
||||
}
|
||||
|
||||
impl<P> State<P>
|
||||
where
|
||||
P: Program + 'static,
|
||||
{
|
||||
/// Creates a new [`State`] with the provided [`Program`], initializing its
|
||||
/// primitive with the given logical bounds and renderer.
|
||||
pub fn new(
|
||||
id: iced_core::id::Id,
|
||||
mut program: P,
|
||||
bounds: Size,
|
||||
renderer: &mut cosmic::Renderer,
|
||||
) -> Self {
|
||||
let user_interface = build_user_interface(
|
||||
id,
|
||||
&mut program,
|
||||
user_interface::Cache::default(),
|
||||
renderer,
|
||||
bounds,
|
||||
);
|
||||
|
||||
let cache = Some(user_interface.into_cache());
|
||||
|
||||
State {
|
||||
program,
|
||||
cache,
|
||||
queued_events: Vec::new(),
|
||||
queued_messages: Vec::new(),
|
||||
mouse_interaction: mouse::Interaction::None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the [`Program`] of the [`State`].
|
||||
pub fn program(&self) -> &P {
|
||||
&self.program
|
||||
}
|
||||
|
||||
/// Queues an event in the [`State`] for processing during an [`update`].
|
||||
///
|
||||
/// [`update`]: Self::update
|
||||
pub fn queue_event(&mut self, event: Event) {
|
||||
self.queued_events.push(event);
|
||||
}
|
||||
|
||||
/// Queues a message in the [`State`] for processing during an [`update`].
|
||||
///
|
||||
/// [`update`]: Self::update
|
||||
pub fn queue_message(&mut self, message: P::Message) {
|
||||
self.queued_messages.push(message);
|
||||
}
|
||||
|
||||
/// Returns whether the event queue of the [`State`] is empty or not.
|
||||
pub fn is_queue_empty(&self) -> bool {
|
||||
self.queued_events.is_empty() && self.queued_messages.is_empty()
|
||||
}
|
||||
|
||||
/// Returns the current [`mouse::Interaction`] of the [`State`].
|
||||
pub fn mouse_interaction(&self) -> mouse::Interaction {
|
||||
self.mouse_interaction
|
||||
}
|
||||
|
||||
/// Processes all the queued events and messages, rebuilding and redrawing
|
||||
/// the widgets of the linked [`Program`] if necessary.
|
||||
///
|
||||
/// Returns a list containing the instances of [`Event`] that were not
|
||||
/// captured by any widget, and the [`Task`] obtained from [`Program`]
|
||||
/// after updating it, only if an update was necessary.
|
||||
pub fn update(
|
||||
&mut self,
|
||||
id: iced_core::id::Id,
|
||||
bounds: Size,
|
||||
cursor: mouse::Cursor,
|
||||
renderer: &mut cosmic::Renderer,
|
||||
theme: &cosmic::Theme,
|
||||
style: &renderer::Style,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
) -> (Vec<Event>, Option<Task<P::Message>>) {
|
||||
let mut user_interface = build_user_interface(
|
||||
id.clone(),
|
||||
&mut self.program,
|
||||
self.cache.take().unwrap(),
|
||||
renderer,
|
||||
bounds,
|
||||
);
|
||||
|
||||
let mut messages = Vec::new();
|
||||
|
||||
let (state, event_statuses) = user_interface.update(
|
||||
&self.queued_events,
|
||||
cursor,
|
||||
renderer,
|
||||
clipboard,
|
||||
&mut messages,
|
||||
);
|
||||
|
||||
let uncaptured_events = self
|
||||
.queued_events
|
||||
.iter()
|
||||
.zip(event_statuses)
|
||||
.filter_map(|(event, status)| matches!(status, event::Status::Ignored).then_some(event))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
self.queued_events.clear();
|
||||
messages.append(&mut self.queued_messages);
|
||||
|
||||
let task = if messages.is_empty() {
|
||||
if let cosmic::iced_runtime::user_interface::State::Updated {
|
||||
mouse_interaction, ..
|
||||
} = state
|
||||
{
|
||||
self.mouse_interaction = mouse_interaction;
|
||||
}
|
||||
|
||||
user_interface.draw(renderer, theme, style, cursor);
|
||||
|
||||
self.cache = Some(user_interface.into_cache());
|
||||
|
||||
None
|
||||
} else {
|
||||
// When there are messages, we are forced to rebuild twice
|
||||
// for now :^)
|
||||
let temp_cache = user_interface.into_cache();
|
||||
|
||||
let tasks = Task::batch(messages.into_iter().map(|message| {
|
||||
let task = self.program.update(message);
|
||||
|
||||
task
|
||||
}));
|
||||
|
||||
let mut user_interface =
|
||||
build_user_interface(id, &mut self.program, temp_cache, renderer, bounds);
|
||||
|
||||
if let cosmic::iced_runtime::user_interface::State::Updated {
|
||||
mouse_interaction, ..
|
||||
} = state
|
||||
{
|
||||
self.mouse_interaction = mouse_interaction;
|
||||
}
|
||||
|
||||
user_interface.draw(renderer, theme, style, cursor);
|
||||
|
||||
self.cache = Some(user_interface.into_cache());
|
||||
|
||||
Some(tasks)
|
||||
};
|
||||
|
||||
(uncaptured_events, task)
|
||||
}
|
||||
|
||||
/// Applies [`Operation`]s to the [`State`]
|
||||
pub fn operate(
|
||||
&mut self,
|
||||
id: iced_core::id::Id,
|
||||
renderer: &mut cosmic::Renderer,
|
||||
operations: impl Iterator<Item = Box<dyn Operation>>,
|
||||
bounds: Size,
|
||||
) {
|
||||
let mut user_interface = build_user_interface(
|
||||
id,
|
||||
&mut self.program,
|
||||
self.cache.take().unwrap(),
|
||||
renderer,
|
||||
bounds,
|
||||
);
|
||||
|
||||
for operation in operations {
|
||||
let mut current_operation = Some(operation);
|
||||
|
||||
while let Some(mut operation) = current_operation.take() {
|
||||
user_interface.operate(renderer, operation.as_mut());
|
||||
|
||||
match operation.finish() {
|
||||
operation::Outcome::None => {}
|
||||
operation::Outcome::Some(()) => {}
|
||||
operation::Outcome::Chain(next) => {
|
||||
current_operation = Some(next);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
self.cache = Some(user_interface.into_cache());
|
||||
}
|
||||
}
|
||||
|
||||
fn build_user_interface<'a, P: Program>(
|
||||
_id: iced_core::id::Id,
|
||||
program: &'a mut P,
|
||||
cache: user_interface::Cache,
|
||||
renderer: &mut cosmic::Renderer,
|
||||
size: Size,
|
||||
) -> UserInterface<'a, P::Message, cosmic::Theme, cosmic::Renderer> {
|
||||
let view = program.view();
|
||||
|
||||
let user_interface = UserInterface::build(view, size, cache, renderer);
|
||||
|
||||
user_interface
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue