#iced #stories #experiment #gui #storybook #augmented-audio

audio-processor-iced-storybook

Iced GUI的Storybook • 增强音频实验

2个版本 (1个稳定版)

1.0.0 2023年3月22日
0.2.0 2022年9月29日

#1097 in 音频

MIT 许可证

255KB
2K SLoC

audio-processor-iced-storybook

这是一个为Iced编写的“storybook”风格库的非常简单的草案。

它与"React的Storybook"在精神上相似。

目前它只是

  • 显示带有故事名称的侧边栏
  • 点击时在内容视图中显示故事

用法

故事使用builder函数配置。它们可以通过两种方式之一进行注册。

第一种方式是将故事声明为story_fn,它仅用于渲染无状态元素

use iced::{Text, Length, Container};

use audio_processor_iced_storybook as storybook;

type Message = ();

fn main() {
    storybook::builder::<Message>()
        .story_fn("Hello world", || {
            Container::new(Text::new("Hey!"))
                .padding(50)
                .center_x()
                .center_y()
                .height(Length::Fill)
                .width(Length::Fill)
                .into()
        })
        .run()
        .unwrap();
}

storybook::builder将子消息类型作为类型参数。要求此类型符合'static + Clone + Debug

故事可以有不同类型的Message,只要它们可以通过From转换为根类型。

注册故事的第二种方式如下

您有一个my_view模块,它声明了一个按钮视图

mod my_view {
    use iced::*;

    // This view has the state of the button
    pub struct MyView {
        button_state: iced::button::State,
    }

    // This view fires a `Message::ButtonClicked` message
    #[derive(Clone, Debug)]
    pub enum Message {
        ButtonClicked,
    }

    impl MyView {
        pub fn new() -> Self {
            Self {
                button_state: iced::button::State::default(),
            }
        }

        pub fn view(&mut self) -> Element<Message> {
            Button::new(&mut self.button_state, Text::new("Hello world"))
                .on_press(Message::ButtonClicked)
                .into()
        }
    }

    // You will declare a `story` module, which may be conditionally compiled on your set-up
    pub mod story {
        use audio_processor_iced_storybook::StoryView;

        use super::*;

        // You will declare some helper types
        struct Story(MyView);
        pub fn default() -> Story {
            Story::default()
        }

        // You will implement the `StoryView` trait for your story. This will be parameterized over the `Message` type,
        // however it doesn't have to be a global type, as long as the root type is convertible to/from this.
        impl StoryView<Message> for Story {
            // You may implement an update function for your story
            fn update(&mut self, _message: Message) -> Command<Message> { Command::none() }

            // You will implement the view function
            fn view(&mut self) -> Element<Message> {
                self.0.view()
            }
        }
    }
}

// In order to have different message types, you'll implement a "super-type" for Message, which derives `From` and
// `TryInto`

use derive_more::{From, TryInto}; // <- You need this to derive `From`/`TryInto` automatically for the child message

#[derive(Debug, From, Clone, TryInto)]
enum Message {
    MyView(my_view::Message),
    None(()) // <- Adding a `None(())` will let you continue using stateless stories as well.
}

// examples/stories.rs
fn main() {
    audio_processor_iced_storybook::builder::<Message>()
        // You will register the story with `story` rather than `story_fn`.
        .story("MyView - default", my_view::story::default())
        .run()
        .unwrap();
}

更详细的示例,请参见crates/plugin-host-gui2

许可证:MIT

依赖关系

~18–35MB
~624K SLoC