mirror of
https://github.com/danbulant/cushy
synced 2026-05-24 12:28:23 +00:00
Moved example generation into cushy
Undocumented and unsupported, but this allows generating example images. This push is testing that the image makes it through CI. Refs #125
This commit is contained in:
parent
be7145a43f
commit
15b8b3e452
12 changed files with 192 additions and 156 deletions
4
.github/workflows/docs.yml
vendored
4
.github/workflows/docs.yml
vendored
|
|
@ -57,6 +57,10 @@ jobs:
|
||||||
cargo install mdbook-variables
|
cargo install mdbook-variables
|
||||||
|
|
||||||
- name: Regenerate Example Images
|
- name: Regenerate Example Images
|
||||||
|
run: |
|
||||||
|
CAPTURE=1 cargo test -p cushy --examples
|
||||||
|
|
||||||
|
- name: Regenerate Guide Example Images
|
||||||
run: |
|
run: |
|
||||||
CAPTURE=1 cargo test -p guide-examples --examples
|
CAPTURE=1 cargo test -p guide-examples --examples
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use cushy::styles::components::{TextColor, WidgetBackground};
|
use cushy::styles::components::{TextColor, TextSize, WidgetBackground};
|
||||||
use cushy::styles::{
|
use cushy::styles::{
|
||||||
ColorScheme, ColorSchemeBuilder, ColorSource, ColorTheme, FixedTheme, SurfaceTheme, Theme,
|
ColorScheme, ColorSchemeBuilder, ColorSource, ColorTheme, Dimension, FixedTheme, SurfaceTheme,
|
||||||
ThemePair,
|
Theme, ThemePair,
|
||||||
};
|
};
|
||||||
use cushy::value::{Destination, Dynamic, MapEachCloned, Source};
|
use cushy::value::{Destination, Dynamic, MapEachCloned, Source};
|
||||||
use cushy::widget::MakeWidget;
|
use cushy::widget::MakeWidget;
|
||||||
|
|
@ -13,14 +13,17 @@ use cushy::widgets::input::InputValue;
|
||||||
use cushy::widgets::slider::Slidable;
|
use cushy::widgets::slider::Slidable;
|
||||||
use cushy::widgets::Space;
|
use cushy::widgets::Space;
|
||||||
use cushy::window::ThemeMode;
|
use cushy::window::ThemeMode;
|
||||||
use cushy::{Open, PendingApp};
|
use cushy::{Cushy, Open, PendingApp};
|
||||||
use figures::units::Lp;
|
use figures::units::Lp;
|
||||||
use kludgine::Color;
|
use kludgine::Color;
|
||||||
use palette::OklabHue;
|
use palette::OklabHue;
|
||||||
|
|
||||||
fn main() -> cushy::Result {
|
fn main() -> cushy::Result {
|
||||||
let app = PendingApp::default();
|
let app = PendingApp::default();
|
||||||
|
theme_editor(app.cushy().clone()).into_window().run_in(app)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn theme_editor(cushy: Cushy) -> impl MakeWidget {
|
||||||
let (theme_mode, theme_switcher) = dark_mode_picker();
|
let (theme_mode, theme_switcher) = dark_mode_picker();
|
||||||
|
|
||||||
let scheme = Scheme::from(ColorScheme::default());
|
let scheme = Scheme::from(ColorScheme::default());
|
||||||
|
|
@ -79,7 +82,6 @@ fn main() -> cushy::Result {
|
||||||
.and(editors.neutral.1)
|
.and(editors.neutral.1)
|
||||||
.and(editors.neutral_variant.1)
|
.and(editors.neutral_variant.1)
|
||||||
.and("Copy to Clipboard".into_button().on_click({
|
.and("Copy to Clipboard".into_button().on_click({
|
||||||
let cushy = app.cushy().clone();
|
|
||||||
move |_| {
|
move |_| {
|
||||||
if let Some(mut clipboard) = cushy.clipboard_guard() {
|
if let Some(mut clipboard) = cushy.clipboard_guard() {
|
||||||
let builder = color_scheme_builder.get();
|
let builder = color_scheme_builder.get();
|
||||||
|
|
@ -115,9 +117,7 @@ fn main() -> cushy::Result {
|
||||||
.themed(theme)
|
.themed(theme)
|
||||||
.pad()
|
.pad()
|
||||||
.expand()
|
.expand()
|
||||||
.into_window()
|
|
||||||
.themed_mode(theme_mode)
|
.themed_mode(theme_mode)
|
||||||
.run_in(app)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Scheme<Primary, Other = Primary> {
|
struct Scheme<Primary, Other = Primary> {
|
||||||
|
|
@ -436,6 +436,7 @@ fn color_theme(theme: Dynamic<ColorTheme>, label: &str) -> impl MakeWidget {
|
||||||
fn swatch(background: Dynamic<Color>, label: &str, text: Dynamic<Color>) -> impl MakeWidget {
|
fn swatch(background: Dynamic<Color>, label: &str, text: Dynamic<Color>) -> impl MakeWidget {
|
||||||
label
|
label
|
||||||
.with(&TextColor, text)
|
.with(&TextColor, text)
|
||||||
|
.with(&TextSize, Dimension::Lp(Lp::points(8)))
|
||||||
.with(&WidgetBackground, background)
|
.with(&WidgetBackground, background)
|
||||||
.fit_horizontally()
|
.fit_horizontally()
|
||||||
.fit_vertically()
|
.fit_vertically()
|
||||||
|
|
@ -492,3 +493,9 @@ impl FormatRust for ColorSchemeBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn runs() {
|
||||||
|
let theme_editor = || theme_editor(Cushy::default());
|
||||||
|
cushy::example!(theme_editor, 1600, 900).untested_still_frame();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ use cushy::styles::ThemePair;
|
||||||
use cushy::widget::MakeWidget;
|
use cushy::widget::MakeWidget;
|
||||||
use cushy::widgets::grid::{GridDimension, GridWidgets};
|
use cushy::widgets::grid::{GridDimension, GridWidgets};
|
||||||
use cushy::widgets::{Grid, Space};
|
use cushy::widgets::{Grid, Space};
|
||||||
use guide_examples::book_example;
|
|
||||||
|
|
||||||
// ANCHOR: content
|
// ANCHOR: content
|
||||||
fn content() -> impl MakeWidget {
|
fn content() -> impl MakeWidget {
|
||||||
|
|
@ -84,7 +83,7 @@ fn main() {
|
||||||
let theme = ThemePair::default();
|
let theme = ThemePair::default();
|
||||||
let container_color = theme.dark.surface.low_container;
|
let container_color = theme.dark.surface.low_container;
|
||||||
let primary = theme.dark.primary.color;
|
let primary = theme.dark.primary.color;
|
||||||
book_example!(align).still_frame(|recorder| {
|
cushy::example!(align).still_frame(|recorder| {
|
||||||
const LEFT: u32 = 145;
|
const LEFT: u32 = 145;
|
||||||
const RIGHT: u32 = 705;
|
const RIGHT: u32 = 705;
|
||||||
const H_CENTER: u32 = (RIGHT + LEFT) / 2;
|
const H_CENTER: u32 = (RIGHT + LEFT) / 2;
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ fn composition_makewidget() -> impl cushy::widget::MakeWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
guide_examples::book_example!(composition_makewidget).untested_still_frame();
|
cushy::example!(composition_makewidget).untested_still_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ fn composition_widget() -> impl cushy::widget::MakeWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
guide_examples::book_example!(composition_widget).untested_still_frame();
|
cushy::example!(composition_widget).untested_still_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ fn composition_wrapperwidget() -> impl cushy::widget::MakeWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
guide_examples::book_example!(composition_wrapperwidget).untested_still_frame();
|
cushy::example!(composition_wrapperwidget).untested_still_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -12,5 +12,5 @@ fn book() {
|
||||||
"Hello, World!"
|
"Hello, World!"
|
||||||
}
|
}
|
||||||
|
|
||||||
guide_examples::book_example!(hello_world).untested_still_frame();
|
cushy::example!(hello_world).untested_still_frame();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ fn book() {
|
||||||
name_input.and(greeting).into_rows()
|
name_input.and(greeting).into_rows()
|
||||||
}
|
}
|
||||||
|
|
||||||
guide_examples::book_example!(intro).animated(|animation| {
|
cushy::example!(intro).animated(|animation| {
|
||||||
animation.wait_for(Duration::from_secs(1)).unwrap();
|
animation.wait_for(Duration::from_secs(1)).unwrap();
|
||||||
animation
|
animation
|
||||||
.animate_text_input("Ferris 🦀", Duration::from_secs(1))
|
.animate_text_input("Ferris 🦀", Duration::from_secs(1))
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ use std::time::Duration;
|
||||||
use cushy::value::{Destination, Dynamic, Source};
|
use cushy::value::{Destination, Dynamic, Source};
|
||||||
use cushy::widget::MakeWidget;
|
use cushy::widget::MakeWidget;
|
||||||
use cushy::widgets::progress::Progressable;
|
use cushy::widgets::progress::Progressable;
|
||||||
use guide_examples::book_example;
|
|
||||||
|
|
||||||
fn thread_progress() -> impl MakeWidget {
|
fn thread_progress() -> impl MakeWidget {
|
||||||
// ANCHOR: example
|
// ANCHOR: example
|
||||||
|
|
@ -23,7 +22,7 @@ fn thread_progress() -> impl MakeWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
book_example!(thread_progress).animated(|recorder| {
|
cushy::example!(thread_progress).animated(|recorder| {
|
||||||
recorder.wait_for(Duration::from_secs(2)).unwrap();
|
recorder.wait_for(Duration::from_secs(2)).unwrap();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,141 +1 @@
|
||||||
use std::panic::AssertUnwindSafe;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use cushy::figures::units::Px;
|
|
||||||
use cushy::figures::Size;
|
|
||||||
use cushy::widget::MakeWidget;
|
|
||||||
use cushy::widgets::container::ContainerShadow;
|
|
||||||
use cushy::window::{AnimationRecorder, Rgba8, VirtualRecorder, VirtualRecorderBuilder};
|
|
||||||
|
|
||||||
pub struct BookExampleBuilder {
|
|
||||||
name: &'static str,
|
|
||||||
recorder: VirtualRecorderBuilder<Rgba8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BookExampleBuilder {
|
|
||||||
pub fn finish(self) -> BookExample {
|
|
||||||
BookExample {
|
|
||||||
name: self.name,
|
|
||||||
recorder: self.recorder.finish().expect("error creating recorder"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn untested_still_frame(self) {
|
|
||||||
self.finish().untested_still_frame()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn prepare_with<Prepare>(self, prepare: Prepare) -> BookExample
|
|
||||||
where
|
|
||||||
Prepare: FnOnce(&mut VirtualRecorder<Rgba8>),
|
|
||||||
{
|
|
||||||
self.finish().prepare_with(prepare)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn still_frame<Test>(self, test: Test)
|
|
||||||
where
|
|
||||||
Test: FnOnce(&mut VirtualRecorder<Rgba8>),
|
|
||||||
{
|
|
||||||
self.finish().still_frame(test);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn animated<Test>(self, test: Test)
|
|
||||||
where
|
|
||||||
Test: FnOnce(&mut AnimationRecorder<'_, Rgba8>),
|
|
||||||
{
|
|
||||||
self.finish().animated(test);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn target_dir() -> PathBuf {
|
|
||||||
let target_dir = std::env::current_dir()
|
|
||||||
.expect("missing current dir")
|
|
||||||
.parent()
|
|
||||||
.expect("missing guide folder")
|
|
||||||
.join("src")
|
|
||||||
.join("examples");
|
|
||||||
assert!(
|
|
||||||
target_dir.is_dir(),
|
|
||||||
"current directory is not guide-examples"
|
|
||||||
);
|
|
||||||
|
|
||||||
target_dir
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BookExample {
|
|
||||||
name: &'static str,
|
|
||||||
recorder: VirtualRecorder<Rgba8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BookExample {
|
|
||||||
pub fn build(name: &'static str, interface: impl MakeWidget) -> BookExampleBuilder {
|
|
||||||
BookExampleBuilder {
|
|
||||||
name,
|
|
||||||
recorder: interface
|
|
||||||
.contain()
|
|
||||||
.shadow(ContainerShadow::drop(Px::new(16)))
|
|
||||||
.width(Px::new(750))
|
|
||||||
.build_recorder()
|
|
||||||
.with_alpha()
|
|
||||||
.resize_to_fit()
|
|
||||||
.size(Size::new(750, 432)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn untested_still_frame(self) {
|
|
||||||
self.still_frame(|_| {});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn prepare_with<Prepare>(mut self, prepare: Prepare) -> Self
|
|
||||||
where
|
|
||||||
Prepare: FnOnce(&mut VirtualRecorder<Rgba8>),
|
|
||||||
{
|
|
||||||
prepare(&mut self.recorder);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn still_frame<Test>(mut self, test: Test)
|
|
||||||
where
|
|
||||||
Test: FnOnce(&mut VirtualRecorder<Rgba8>),
|
|
||||||
{
|
|
||||||
let capture = std::env::var("CAPTURE").is_ok();
|
|
||||||
let errored =
|
|
||||||
std::panic::catch_unwind(AssertUnwindSafe(|| test(&mut self.recorder))).is_err();
|
|
||||||
if errored || capture {
|
|
||||||
let path = target_dir().join(format!("{}.png", self.name));
|
|
||||||
self.recorder
|
|
||||||
.image()
|
|
||||||
.save(&path)
|
|
||||||
.expect("error saving file");
|
|
||||||
println!("Wrote {}", path.display());
|
|
||||||
|
|
||||||
if errored {
|
|
||||||
std::process::exit(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn animated<Test>(mut self, test: Test)
|
|
||||||
where
|
|
||||||
Test: FnOnce(&mut AnimationRecorder<'_, Rgba8>),
|
|
||||||
{
|
|
||||||
let mut animation = self.recorder.record_animated_png(60);
|
|
||||||
let capture = std::env::var("CAPTURE").is_ok();
|
|
||||||
let errored = std::panic::catch_unwind(AssertUnwindSafe(|| test(&mut animation))).is_err();
|
|
||||||
if errored || capture {
|
|
||||||
let path = target_dir().join(format!("{}.png", self.name));
|
|
||||||
animation.write_to(&path).expect("error saving file");
|
|
||||||
println!("Wrote {}", path.display());
|
|
||||||
|
|
||||||
if errored {
|
|
||||||
std::process::exit(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! book_example {
|
|
||||||
($name:ident) => {
|
|
||||||
guide_examples::BookExample::build(stringify!($name), $name())
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
||||||
164
src/example.rs
Normal file
164
src/example.rs
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
use std::panic::AssertUnwindSafe;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use cushy::figures::units::Px;
|
||||||
|
use cushy::figures::Size;
|
||||||
|
use cushy::widget::MakeWidget;
|
||||||
|
use cushy::widgets::container::ContainerShadow;
|
||||||
|
use cushy::window::{AnimationRecorder, Rgba8, VirtualRecorder, VirtualRecorderBuilder};
|
||||||
|
|
||||||
|
pub struct ExampleBuilder {
|
||||||
|
name: &'static str,
|
||||||
|
recorder: VirtualRecorderBuilder<Rgba8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExampleBuilder {
|
||||||
|
#[must_use]
|
||||||
|
pub fn finish(self) -> Example {
|
||||||
|
Example {
|
||||||
|
name: self.name,
|
||||||
|
recorder: self.recorder.finish().expect("error creating recorder"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn untested_still_frame(self) {
|
||||||
|
self.finish().untested_still_frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prepare_with<Prepare>(self, prepare: Prepare) -> Example
|
||||||
|
where
|
||||||
|
Prepare: FnOnce(&mut VirtualRecorder<Rgba8>),
|
||||||
|
{
|
||||||
|
self.finish().prepare_with(prepare)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn still_frame<Test>(self, test: Test)
|
||||||
|
where
|
||||||
|
Test: FnOnce(&mut VirtualRecorder<Rgba8>),
|
||||||
|
{
|
||||||
|
self.finish().still_frame(test);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn animated<Test>(self, test: Test)
|
||||||
|
where
|
||||||
|
Test: FnOnce(&mut AnimationRecorder<'_, Rgba8>),
|
||||||
|
{
|
||||||
|
self.finish().animated(test);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn target_dir() -> PathBuf {
|
||||||
|
let current_dir = std::env::current_dir().expect("missing current dir");
|
||||||
|
let mut target_dir = current_dir.join("guide").join("src").join("examples");
|
||||||
|
if !target_dir.is_dir() {
|
||||||
|
target_dir = current_dir
|
||||||
|
.parent()
|
||||||
|
.expect("missing guide folder")
|
||||||
|
.join("src")
|
||||||
|
.join("examples");
|
||||||
|
}
|
||||||
|
assert!(
|
||||||
|
target_dir.is_dir(),
|
||||||
|
"current directory is not guide-examples or the root directory"
|
||||||
|
);
|
||||||
|
|
||||||
|
target_dir
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Example {
|
||||||
|
name: &'static str,
|
||||||
|
recorder: VirtualRecorder<Rgba8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Example {
|
||||||
|
pub fn build(
|
||||||
|
name: &'static str,
|
||||||
|
interface: impl MakeWidget,
|
||||||
|
width: u16,
|
||||||
|
height: Option<u16>,
|
||||||
|
) -> ExampleBuilder {
|
||||||
|
let mut contents = interface
|
||||||
|
.contain()
|
||||||
|
.shadow(ContainerShadow::drop(Px::new(16)))
|
||||||
|
.width(Px::new(i32::from(width)));
|
||||||
|
if let Some(height) = height {
|
||||||
|
contents = contents.height(Px::new(i32::from(height)));
|
||||||
|
}
|
||||||
|
ExampleBuilder {
|
||||||
|
name,
|
||||||
|
recorder: contents
|
||||||
|
.build_recorder()
|
||||||
|
.with_alpha()
|
||||||
|
.resize_to_fit()
|
||||||
|
.size(Size::new(
|
||||||
|
u32::from(width),
|
||||||
|
u32::from(height.unwrap_or(432)),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn untested_still_frame(self) {
|
||||||
|
self.still_frame(|_| {});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn prepare_with<Prepare>(mut self, prepare: Prepare) -> Self
|
||||||
|
where
|
||||||
|
Prepare: FnOnce(&mut VirtualRecorder<Rgba8>),
|
||||||
|
{
|
||||||
|
prepare(&mut self.recorder);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn still_frame<Test>(mut self, test: Test)
|
||||||
|
where
|
||||||
|
Test: FnOnce(&mut VirtualRecorder<Rgba8>),
|
||||||
|
{
|
||||||
|
let capture = std::env::var("CAPTURE").is_ok();
|
||||||
|
let errored =
|
||||||
|
std::panic::catch_unwind(AssertUnwindSafe(|| test(&mut self.recorder))).is_err();
|
||||||
|
if errored || capture {
|
||||||
|
let path = target_dir().join(format!("{}.png", self.name));
|
||||||
|
self.recorder
|
||||||
|
.image()
|
||||||
|
.save(&path)
|
||||||
|
.expect("error saving file");
|
||||||
|
println!("Wrote {}", path.display());
|
||||||
|
|
||||||
|
if errored {
|
||||||
|
std::process::exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn animated<Test>(mut self, test: Test)
|
||||||
|
where
|
||||||
|
Test: FnOnce(&mut AnimationRecorder<'_, Rgba8>),
|
||||||
|
{
|
||||||
|
let mut animation = self.recorder.record_animated_png(60);
|
||||||
|
let capture = std::env::var("CAPTURE").is_ok();
|
||||||
|
let errored = std::panic::catch_unwind(AssertUnwindSafe(|| test(&mut animation))).is_err();
|
||||||
|
if errored || capture {
|
||||||
|
let path = target_dir().join(format!("{}.png", self.name));
|
||||||
|
animation.write_to(&path).expect("error saving file");
|
||||||
|
println!("Wrote {}", path.display());
|
||||||
|
|
||||||
|
if errored {
|
||||||
|
std::process::exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! example {
|
||||||
|
($name:ident) => {
|
||||||
|
$crate::example!($name, 750)
|
||||||
|
};
|
||||||
|
($name:ident, $width:expr) => {
|
||||||
|
$crate::example::Example::build(stringify!($name), $name(), $width, None)
|
||||||
|
};
|
||||||
|
($name:ident, $width:expr, $height:expr) => {
|
||||||
|
$crate::example::Example::build(stringify!($name), $name(), $width, Some($height))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -23,6 +23,9 @@ pub mod value;
|
||||||
pub mod widget;
|
pub mod widget;
|
||||||
pub mod widgets;
|
pub mod widgets;
|
||||||
pub mod window;
|
pub mod window;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub mod example;
|
||||||
use std::ops::{Add, AddAssign, Sub, SubAssign};
|
use std::ops::{Add, AddAssign, Sub, SubAssign};
|
||||||
|
|
||||||
#[cfg(feature = "tokio")]
|
#[cfg(feature = "tokio")]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue