-
-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add build_pattern for iced_layershell
- Loading branch information
1 parent
a08d676
commit f279fc8
Showing
2 changed files
with
321 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,320 @@ | ||
use iced::{Element, Task}; | ||
|
||
use super::DefaultStyle; | ||
use super::Settings; | ||
// layershell application | ||
pub trait Program: Sized { | ||
/// The [`Executor`] that will run commands and subscriptions. | ||
/// | ||
/// The [default executor] can be a good starting point! | ||
/// | ||
/// [`Executor`]: Self::Executor | ||
/// [default executor]: iced::executor::Default | ||
type Executor: iced::Executor; | ||
type State; | ||
type Renderer: iced_renderer::Renderer; | ||
|
||
/// The type of __messages__ your [`Application`] will produce. | ||
type Message: std::fmt::Debug + Send; | ||
|
||
/// The theme of your [`Application`]. | ||
type Theme: Default + DefaultStyle; | ||
|
||
/// The data needed to initialize your [`Application`]. | ||
type Flags; | ||
|
||
/// Initializes the [`Application`] with the flags provided to | ||
/// [`run`] as part of the [`Settings`]. | ||
/// | ||
/// Here is where you should return the initial state of your app. | ||
/// | ||
/// Additionally, you can return a [`Task`] if you need to perform some | ||
/// async action in the background on startup. This is useful if you want to | ||
/// load state from a file, perform an initial HTTP request, etc. | ||
/// | ||
/// | ||
/// This title can be dynamic! The runtime will automatically update the | ||
/// title of your application when necessary. | ||
fn namespace(&self) -> String { | ||
"A cool iced application".to_string() | ||
} | ||
|
||
/// Handles a __message__ and updates the state of the [`Application`]. | ||
/// | ||
/// This is where you define your __update logic__. All the __messages__, | ||
/// produced by either user interactions or commands, will be handled by | ||
/// this method. | ||
/// | ||
/// Any [`Task`] returned will be executed immediately in the background. | ||
fn update(&mut self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message>; | ||
|
||
/// Returns the widgets to display in the [`Application`]. | ||
/// | ||
/// These widgets can produce __messages__ based on user interaction. | ||
fn view( | ||
&self, | ||
state: &'a Self::State, | ||
) -> Element<'_, Self::Message, Self::Theme, Self::Renderer>; | ||
|
||
/// Returns the current [`Theme`] of the [`Application`]. | ||
/// | ||
/// [`Theme`]: Self::Theme | ||
fn theme(&self, _state: &Self::State) -> Self::Theme { | ||
Self::Theme::default() | ||
} | ||
|
||
/// Returns the current `Style` of the [`Theme`]. | ||
/// | ||
/// [`Theme`]: Self::Theme | ||
fn style(&self, _state: &Self::State, theme: &Self::Theme) -> super::Appearance { | ||
theme.default_style() | ||
} | ||
|
||
/// Returns the event [`Subscription`] for the current state of the | ||
/// application. | ||
/// | ||
/// A [`Subscription`] will be kept alive as long as you keep returning it, | ||
/// and the __messages__ produced will be handled by | ||
/// [`update`](#tymethod.update). | ||
/// | ||
/// By default, this method returns an empty [`Subscription`]. | ||
fn subscription(&self, _state: &Self::State) -> iced::Subscription<Self::Message> { | ||
iced::Subscription::none() | ||
} | ||
|
||
/// Returns the scale factor of the [`Application`]. | ||
/// | ||
/// It can be used to dynamically control the size of the UI at runtime | ||
/// (i.e. zooming). | ||
/// | ||
/// For instance, a scale factor of `2.0` will make widgets twice as big, | ||
/// while a scale factor of `0.5` will shrink them to half their size. | ||
/// | ||
/// By default, it returns `1.0`. | ||
fn scale_factor(&self, state: &'a Self::State) -> f64 { | ||
1.0 | ||
} | ||
|
||
fn run(self, settings: Settings<Self::Flags>) -> Result | ||
where | ||
Self: 'static, | ||
Self::State: Default, | ||
{ | ||
#[allow(clippy::needless_update)] | ||
let renderer_settings = iced_graphics::Settings { | ||
default_font: settings.default_font, | ||
default_text_size: settings.default_text_size, | ||
antialiasing: if settings.antialiasing { | ||
Some(iced_graphics::Antialiasing::MSAAx4) | ||
} else { | ||
None | ||
}, | ||
..iced_graphics::Settings::default() | ||
}; | ||
|
||
todo!() | ||
//super::application::run::<Instance<Self>, Self::Executor, iced_renderer::Compositor>( | ||
// settings, | ||
// renderer_settings, | ||
//) | ||
} | ||
} | ||
|
||
pub trait NameSpace<State> { | ||
/// Produces the title of the [`Application`]. | ||
fn namespace(&self, state: &State) -> String; | ||
} | ||
|
||
impl<State> NameSpace<State> for &'static str { | ||
fn namespace(&self, _state: &State) -> String { | ||
self.to_string() | ||
} | ||
} | ||
|
||
impl<T, State> NameSpace<State> for T | ||
where | ||
T: Fn(&State) -> String, | ||
{ | ||
fn namespace(&self, state: &State) -> String { | ||
self(state) | ||
} | ||
} | ||
|
||
/// The update logic of some [`Application`]. | ||
/// | ||
/// This trait allows the [`application`] builder to take any closure that | ||
/// returns any `Into<Task<Message>>`. | ||
pub trait Update<State, Message> { | ||
/// Processes the message and updates the state of the [`Application`]. | ||
fn update(&self, state: &mut State, message: Message) -> impl Into<Task<Message>>; | ||
} | ||
|
||
impl<State, Message> Update<State, Message> for () { | ||
fn update(&self, _state: &mut State, _message: Message) -> impl Into<Task<Message>> {} | ||
} | ||
|
||
impl<T, State, Message, C> Update<State, Message> for T | ||
where | ||
T: Fn(&mut State, Message) -> C, | ||
C: Into<Task<Message>>, | ||
{ | ||
fn update(&self, state: &mut State, message: Message) -> impl Into<Task<Message>> { | ||
self(state, message) | ||
} | ||
} | ||
|
||
/// The view logic of some [`Application`]. | ||
/// | ||
/// This trait allows the [`application`] builder to take any closure that | ||
/// returns any `Into<Element<'_, Message>>`. | ||
pub trait View<'a, State, Message, Theme, Renderer> { | ||
/// Produces the widget of the [`Application`]. | ||
fn view(&self, state: &'a State) -> impl Into<Element<'a, Message, Theme, Renderer>>; | ||
} | ||
|
||
impl<'a, T, State, Message, Theme, Renderer, Widget> View<'a, State, Message, Theme, Renderer> for T | ||
where | ||
T: Fn(&'a State) -> Widget, | ||
State: 'static, | ||
Widget: Into<Element<'a, Message, Theme, Renderer>>, | ||
{ | ||
fn view(&self, state: &'a State) -> impl Into<Element<'a, Message, Theme, Renderer>> { | ||
self(state) | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
struct SingleApplication<A: Program, T> { | ||
raw: A, | ||
settings: Settings<T>, | ||
} | ||
|
||
pub fn application<State, Message, Theme, Renderer, Flags>( | ||
title: impl NameSpace, | ||
update: impl Update<State, Message>, | ||
view: impl for<'a> self::View<'a, State, Message, Theme, Renderer>, | ||
) -> SingleApplication<impl Program<Message = Message, Theme = Theme, State = State>, Flags> | ||
where | ||
State: 'static, | ||
Message: Send + std::fmt::Debug + 'static, | ||
Theme: Default + DefaultStyle, | ||
Renderer: iced_renderer::Renderer, | ||
{ | ||
use std::marker::PhantomData; | ||
struct Instance<State, Message, Theme, Renderer, Update, View> { | ||
update: Update, | ||
view: View, | ||
_state: PhantomData<State>, | ||
_message: PhantomData<Message>, | ||
_theme: PhantomData<Theme>, | ||
_renderer: PhantomData<Renderer>, | ||
} | ||
impl<State, Message, Theme, Renderer, Update, View, Flags> Program | ||
for Instance<State, Message, Theme, Renderer, Update, View> | ||
where | ||
Message: Send + std::fmt::Debug + 'static, | ||
Theme: Default + DefaultStyle, | ||
Renderer: iced_renderer::Renderer, | ||
Update: self::Update<State, Message>, | ||
View: for<'a> self::View<'a, State, Message, Theme, Renderer>, | ||
{ | ||
type State = State; | ||
type Renderer = Renderer; | ||
type Message = Message; | ||
type Theme = Theme; | ||
type Flags = Flags; | ||
type Executor = iced_futures::backend::default::Executor; | ||
|
||
fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> { | ||
self.update.update(state, message).into() | ||
} | ||
|
||
fn view<'a>( | ||
&self, | ||
state: &'a Self::State, | ||
) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> { | ||
self.view.view(state).into() | ||
} | ||
} | ||
SingleApplication { | ||
raw: Instance { | ||
update, | ||
view, | ||
_state: PhantomData, | ||
_message: PhantomData, | ||
_theme: PhantomData, | ||
_renderer: PhantomData, | ||
}, | ||
settings: Settings::default(), | ||
} | ||
} | ||
|
||
fn with_namespace<P: Program>( | ||
program: P, | ||
namespace: impl Fn(&P::State) -> String, | ||
) -> impl Program<State = P::State, Message = P::Message, Theme = P::Theme> { | ||
struct WithNamespace<P, NameSpace> { | ||
program: P, | ||
namespace: NameSpace, | ||
} | ||
impl<P, Namespace> Program for WithNamespace<P, Namespace> | ||
where | ||
P: Program, | ||
Namespace: Fn(&P::State) -> String, | ||
{ | ||
type State = P::State; | ||
type Message = P::Message; | ||
type Theme = P::Theme; | ||
type Renderer = P::Renderer; | ||
type Executor = P::Executor; | ||
type Flags = P::Flags; | ||
|
||
fn namespace(&self, state: &Self::State) -> String { | ||
(self.namespace)(state) | ||
} | ||
|
||
fn update(&self, state: &mut Self::State, message: Self::Message) -> Task<Self::Message> { | ||
self.program.update(state, message) | ||
} | ||
|
||
fn view<'a>( | ||
&self, | ||
state: &'a Self::State, | ||
) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> { | ||
self.program.view(state) | ||
} | ||
|
||
fn theme(&self, state: &Self::State) -> Self::Theme { | ||
self.program.theme(state) | ||
} | ||
|
||
fn subscription(&self, state: &Self::State) -> iced::Subscription<Self::Message> { | ||
self.program.subscription(state) | ||
} | ||
|
||
fn style(&self, state: &Self::State, theme: &Self::Theme) -> super::Appearance { | ||
self.program.style(state, theme) | ||
} | ||
|
||
fn scale_factor(&self, state: &Self::State) -> f64 { | ||
self.program.scale_factor(state) | ||
} | ||
} | ||
|
||
WithNamespace { program, namespace } | ||
} | ||
|
||
impl<P: Program, Flags> SingleApplication<P, Flags> { | ||
pub fn namespace( | ||
self, | ||
namespace: impl NameSpace<P::State>, | ||
) -> SingleApplication< | ||
impl Program<State = P::State, Message = P::Message, Theme = P::Theme, Flags = P::Flags>, | ||
Flags, | ||
> { | ||
SingleApplication { | ||
raw: with_namespace(self.raw, move |state| namespace.namespace(state)), | ||
settings: self.settings, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters