-
-
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 02f488c
Showing
2 changed files
with
365 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,364 @@ | ||
use std::borrow::Cow; | ||
|
||
use iced::{Element, Task}; | ||
use iced::{Font, Pixels}; | ||
|
||
use crate::settings::{LayerShellSettings, VirtualKeyboardSettings}; | ||
|
||
use super::DefaultStyle; | ||
|
||
use super::Settings; | ||
|
||
#[derive(Debug, Default)] | ||
pub struct MainSettings { | ||
/// The identifier of the application. | ||
/// | ||
/// If provided, this identifier may be used to identify the application or | ||
/// communicate with it through the windowing system. | ||
pub id: Option<String>, | ||
|
||
/// settings for layer shell | ||
pub layer_settings: LayerShellSettings, | ||
/// The data needed to initialize an [`Application`]. | ||
/// | ||
/// The fonts to load on boot. | ||
pub fonts: Vec<Cow<'static, [u8]>>, | ||
|
||
/// The default [`Font`] to be used. | ||
/// | ||
/// By default, it uses [`Family::SansSerif`](iced::font::Family::SansSerif). | ||
pub default_font: Font, | ||
|
||
/// The text size that will be used by default. | ||
/// | ||
/// The default value is `16.0`. | ||
pub default_text_size: Pixels, | ||
|
||
/// If set to true, the renderer will try to perform antialiasing for some | ||
/// primitives. | ||
/// | ||
/// Enabling it can produce a smoother result in some widgets, like the | ||
/// `Canvas`, at a performance cost. | ||
/// | ||
/// By default, it is disabled. | ||
/// | ||
pub antialiasing: bool, | ||
|
||
pub virtual_keyboard_support: Option<VirtualKeyboardSettings>, | ||
} | ||
/// The renderer of some [`Program`]. | ||
pub trait Renderer: iced_core::text::Renderer + iced_graphics::compositor::Default {} | ||
|
||
impl<T> Renderer for T where T: iced_core::text::Renderer + iced_graphics::compositor::Default {} | ||
// 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: 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`]. | ||
/// 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, _state: &Self::State) -> 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(&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<'a>( | ||
&self, | ||
state: &'a Self::State, | ||
) -> Element<'a, 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<'a>(&self, state: &'a Self::State) -> f64 { | ||
1.0 | ||
} | ||
|
||
fn run(self, settings: MainSettings) -> Result<(), super::error::Error> | ||
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> { | ||
raw: A, | ||
settings: MainSettings, | ||
} | ||
|
||
pub fn application<State, Message, Theme, Renderer>( | ||
title: impl NameSpace<State>, | ||
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>> | ||
where | ||
State: 'static, | ||
Message: Send + std::fmt::Debug + 'static, | ||
Theme: Default + DefaultStyle, | ||
Renderer: self::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> Program | ||
for Instance<State, Message, Theme, Renderer, Update, View> | ||
where | ||
Message: Send + std::fmt::Debug + 'static, | ||
Theme: Default + DefaultStyle, | ||
Renderer: self::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 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: MainSettings::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; | ||
|
||
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> SingleApplication<P> { | ||
pub fn namespace( | ||
self, | ||
namespace: impl NameSpace<P::State>, | ||
) -> SingleApplication< | ||
impl Program<State = P::State, Message = P::Message, Theme = P::Theme>, | ||
> { | ||
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