Skip to content

Commit

Permalink
Merge pull request #7 from ten3roberts/dev
Browse files Browse the repository at this point in the history
Add ScrollArea and more debug tools
  • Loading branch information
ten3roberts authored Mar 27, 2024
2 parents bbd1b1d + 72aba6f commit 2bbd0aa
Show file tree
Hide file tree
Showing 33 changed files with 1,528 additions and 566 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ flax = { path = "./flax", version = "0.6.0", features = [
atomic_refcell = "0.1"
futures-signals = "0.3"
itertools = "0.12"
glam = { version = "0.25", features = ["bytemuck"] }
glam = { version = "0.27", features = ["bytemuck"] }
futures = "0.3"
futures-concurrency = "7.0"
flume = "0.11"
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ State and reactivity is managed locally using async Streams, such as signals or
allows composing a declarative reactive UI where data flows naturally from source to destination without re-renders or
useState hooks.

## [Live Demo](https://ten3roberts.github.io/violet/demo)

## Example
```rust
let name = Mutable::new("".to_string());
Expand Down Expand Up @@ -58,13 +60,13 @@ col((
- Declarative Widgets and reactive state
- Flexible layout system for responsive layouts
- Composable widgets
- Async widgets
- First class async and stream based widget reactivity
- Thread local `!Send` + `!Sync` state and futures
- Signal based state management
- State and Stream morphisms
- Wasm integration
- State decomposition and composition
- Renderer agnostic allowing embedding into other applications
- ECS based widget and property system (with change detection, async subscriptions, hierarchies, and more)

## State Management

Expand Down
33 changes: 10 additions & 23 deletions examples/basic.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,21 @@
use flax::{components::name, FetchExt, Query};
use futures::StreamExt;
use futures_signals::signal::Mutable;
use glam::{vec2, Vec2};
use itertools::Itertools;
use palette::{Hsva, IntoColor, Srgba};
use std::time::Duration;
use glam::Vec2;
use palette::Srgba;
use tracing_subscriber::{
prelude::__tracing_subscriber_SubscriberExt, registry, util::SubscriberInitExt, EnvFilter,
};
use tracing_tree::HierarchicalLayer;
use violet::core::{
components::{self, rect, size, text},
layout::{Alignment, Direction},
style::StyleExt,
text::{FontFamily, Style, TextSegment, Weight, Wrap},
time::interval,
unit::Unit,
widget::{Button, Image, List, Rectangle, Stack, Text, WidgetExt},
Scope, StreamEffect, Widget,
};
use violet_core::{
state::{State, StateStream},
style::{
colors::{AMBER_500, EMERALD_500, TEAL_500},
danger_background, danger_item, primary_background, secondary_background, spacing_medium,
spacing_small, Background, SizeExt, ValueOrRef,
},
style::{danger_background, Background, SizeExt},
unit::Unit,
widget::{
card, col, label, pill, row, ContainerStyle, SliderWithLabel, StreamWidget, TextInput,
card, col, label, pill, row, Rectangle, SliderWithLabel, StreamWidget, Text, TextInput,
},
Widget,
};
use violet_wgpu::renderer::RendererConfig;

pub fn main() -> anyhow::Result<()> {
registry()
Expand All @@ -42,7 +28,9 @@ pub fn main() -> anyhow::Result<()> {
.with(EnvFilter::from_default_env())
.init();

violet_wgpu::AppBuilder::new().run(app())
violet_wgpu::AppBuilder::new()
.with_renderer_config(RendererConfig { debug_mode: true })
.run(app())
}

fn app() -> impl Widget {
Expand Down Expand Up @@ -88,5 +76,4 @@ fn app() -> impl Widget {
})),
))),
))
.contain_margins(true)
}
181 changes: 181 additions & 0 deletions examples/buttons.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
use std::usize;

use futures_signals::{map_ref, signal::Mutable};

use itertools::Itertools;
use palette::{FromColor, Hsva, IntoColor, Oklcha, Srgba};
use tracing_subscriber::{layer::SubscriberExt, registry, util::SubscriberInitExt, EnvFilter};
use tracing_tree::HierarchicalLayer;

use violet::core::{
layout::Alignment,
style::StyleExt,
unit::Unit,
widget::{List, Rectangle, SignalWidget, Stack, Text},
Scope, Widget,
};
use violet_core::{
style::{self, primary_background, secondary_background, spacing_small, Background, SizeExt},
text::Wrap,
widget::{card, col, label, row, Button, ButtonStyle, SliderWithLabel, TextInput},
};
use violet_wgpu::renderer::RendererConfig;

pub fn main() -> anyhow::Result<()> {
registry()
.with(
HierarchicalLayer::default()
.with_deferred_spans(true)
.with_span_retrace(true)
.with_indent_lines(true)
.with_indent_amount(4),
)
.with(EnvFilter::from_default_env())
.init();

violet_wgpu::AppBuilder::new()
.with_renderer_config(RendererConfig { debug_mode: false })
.run(MainApp)
}

struct MainApp;

impl Widget for MainApp {
fn mount(self, scope: &mut Scope<'_>) {
let content = Mutable::new(
"This is a multiline text that is wrapped around because it is so long".into(),
);
let value = Mutable::new(24.0f32);
let count = Mutable::new(8);

let scale = value.signal();

let item_list = Box::new(map_ref! {scale, let count = count.signal() => ItemList {
scale: scale.round(),
count: *count,
}});

col((
row((Text::new("Input: "), TextInput::new(content))),
card(
col((
Button::label("Button"),
Button::label("Button").with_style(ButtonStyle {
normal_color: style::success_item().into(),
..Default::default()
}),
Button::label("Warning").with_style(ButtonStyle {
normal_color: style::warning_item().into(),
..Default::default()
}),
Button::label("Error").with_style(ButtonStyle {
normal_color: style::danger_item().into(),
..Default::default()
}),
))
.with_stretch(true),
),
Rectangle::new(secondary_background())
.with_size(Unit::rel2(1.0, 0.0) + Unit::px2(0.0, 1.0)),
card(col((
col((
row((
Text::new("Size"),
SliderWithLabel::new(value, 20.0, 200.0).editable(true),
)),
row((
Text::new("Count"),
SliderWithLabel::new(count, 1, 2).editable(true),
)),
)),
SignalWidget::new(item_list),
))),
col([
// EERIE_BLACK_DEFAULT,
// PLATINUM_DEFAULT,
// JADE_DEFAULT,
// DARK_CYAN_DEFAULT,
// ULTRA_VIOLET_DEFAULT,
// LION_DEFAULT,
// REDWOOD_DEFAULT,
]
.into_iter()
.map(|color| Tints { color })
.collect_vec()),
))
.with_background(Background::new(primary_background()))
.contain_margins(true)
.mount(scope)
}
}

struct Tints {
color: Srgba,
}

impl Widget for Tints {
fn mount(self, scope: &mut Scope<'_>) {
row((0..=10)
.map(|i| {
let tint = i * 100;
let color = style::tint(self.color, tint);
let color_bytes: Srgba<u8> = color.into_format();
let color_string = format!(
"#{:02x}{:02x}{:02x}",
color_bytes.red, color_bytes.green, color_bytes.blue
);

card(col((
Rectangle::new(color).with_size(Unit::px2(100.0, 40.0)),
label(format!("{tint}")),
label(color_string),
)))
})
.collect_vec())
.mount(scope)
}
}

struct ItemList {
scale: f32,
count: usize,
}

impl Widget for ItemList {
fn mount(self, scope: &mut Scope<'_>) {
List::new(
(0..self.count)
.map(|i| {
let size = self.scale;
let color: Srgba = Hsva::new(i as f32 * 30.0, 0.6, 0.7, 1.0).into_color();
let oklch = Oklcha::from_color(color);

Stack::new(
Text::new(format!(
"{},{},{}",
oklch.l.round(),
oklch.chroma.round(),
oklch.hue.into_positive_degrees().round()
))
.with_wrap(Wrap::None),
)
.with_background(Background::new(Srgba::from_color(Hsva::new(
i as f32 * 30.0,
0.6,
0.7,
1.0,
))))
.with_padding(spacing_small())
.with_margin(spacing_small())
// .with_cross_align(Alignment::Center)
.with_vertical_alignment(Alignment::Center)
.with_horizontal_alignment(Alignment::Center)
.with_size(Unit::px2(size, size))
.with_max_size(Unit::px2(size, size))
})
.collect::<Vec<_>>(),
)
.with_cross_align(Alignment::Center)
.mount(scope)
}
}
Loading

0 comments on commit 2bbd0aa

Please sign in to comment.