Merge branch 'master' into feature/test-recorder
This commit is contained in:
commit
26c9dc1709
83 changed files with 2627 additions and 1208 deletions
|
|
@ -369,6 +369,7 @@ impl Pipeline {
|
|||
color_attachments: &[Some(
|
||||
wgpu::RenderPassColorAttachment {
|
||||
view: target,
|
||||
depth_slice: None,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Load,
|
||||
|
|
@ -568,6 +569,7 @@ impl DepthPipeline {
|
|||
label: Some("cubes.pipeline.depth_pass"),
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: target,
|
||||
depth_slice: None,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Load,
|
||||
|
|
|
|||
|
|
@ -119,10 +119,10 @@ impl Editor {
|
|||
|
||||
let mut text = self.content.text();
|
||||
|
||||
if let Some(ending) = self.content.line_ending() {
|
||||
if !text.ends_with(ending.as_str()) {
|
||||
text.push_str(ending.as_str());
|
||||
}
|
||||
if let Some(ending) = self.content.line_ending()
|
||||
&& !text.ends_with(ending.as_str())
|
||||
{
|
||||
text.push_str(ending.as_str());
|
||||
}
|
||||
|
||||
Task::perform(
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ impl Image {
|
|||
.get("https://civitai.com/api/v1/images")
|
||||
.query(&[
|
||||
("sort", "Most Reactions"),
|
||||
("period", "Week"),
|
||||
("period", "Month"),
|
||||
("nsfw", "None"),
|
||||
("limit", &Image::LIMIT.to_string()),
|
||||
])
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use iced::animation;
|
|||
use iced::time::{Instant, milliseconds};
|
||||
use iced::widget::{
|
||||
button, container, float, grid, horizontal_space, image, mouse_area,
|
||||
opaque, pop, scrollable, stack,
|
||||
opaque, scrollable, sensor, stack,
|
||||
};
|
||||
use iced::window;
|
||||
use iced::{
|
||||
|
|
@ -257,7 +257,7 @@ fn card<'a>(
|
|||
.style(button::text)
|
||||
.into()
|
||||
} else {
|
||||
pop(card)
|
||||
sensor(card)
|
||||
.on_show(|_| Message::ImagePoppedIn(metadata.id))
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,17 +96,14 @@ pub fn main() -> Result<(), winit::error::EventLoopError> {
|
|||
let capabilities = surface.get_capabilities(&adapter);
|
||||
|
||||
let (device, queue) = adapter
|
||||
.request_device(
|
||||
&wgpu::DeviceDescriptor {
|
||||
label: None,
|
||||
required_features: adapter_features
|
||||
& wgpu::Features::default(),
|
||||
required_limits: wgpu::Limits::default(),
|
||||
memory_hints:
|
||||
wgpu::MemoryHints::MemoryUsage,
|
||||
},
|
||||
None,
|
||||
)
|
||||
.request_device(&wgpu::DeviceDescriptor {
|
||||
label: None,
|
||||
required_features: adapter_features
|
||||
& wgpu::Features::default(),
|
||||
required_limits: wgpu::Limits::default(),
|
||||
memory_hints: wgpu::MemoryHints::MemoryUsage,
|
||||
trace: wgpu::Trace::Off,
|
||||
})
|
||||
.await
|
||||
.expect("Request device");
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ impl Scene {
|
|||
label: None,
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: target,
|
||||
depth_slice: None,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear({
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use iced::highlighter;
|
|||
use iced::time::{self, Instant, milliseconds};
|
||||
use iced::widget::{
|
||||
self, button, center_x, container, horizontal_space, hover, image,
|
||||
markdown, pop, right, row, scrollable, text_editor, toggler,
|
||||
markdown, right, row, scrollable, sensor, text_editor, toggler,
|
||||
};
|
||||
use iced::window;
|
||||
use iced::{
|
||||
|
|
@ -267,7 +267,7 @@ impl<'a> markdown::Viewer<'a, Message> for CustomViewer<'a> {
|
|||
)
|
||||
.into()
|
||||
} else {
|
||||
pop(horizontal_space())
|
||||
sensor(horizontal_space())
|
||||
.key_ref(url.as_str())
|
||||
.delay(milliseconds(500))
|
||||
.on_show(|_size| Message::ImageShown(url.clone()))
|
||||
|
|
|
|||
|
|
@ -71,11 +71,10 @@ impl Example {
|
|||
}
|
||||
}
|
||||
Message::FocusAdjacent(direction) => {
|
||||
if let Some(pane) = self.focus {
|
||||
if let Some(adjacent) = self.panes.adjacent(pane, direction)
|
||||
{
|
||||
self.focus = Some(adjacent);
|
||||
}
|
||||
if let Some(pane) = self.focus
|
||||
&& let Some(adjacent) = self.panes.adjacent(pane, direction)
|
||||
{
|
||||
self.focus = Some(adjacent);
|
||||
}
|
||||
}
|
||||
Message::Clicked(pane) => {
|
||||
|
|
@ -106,14 +105,12 @@ impl Example {
|
|||
}
|
||||
}
|
||||
Message::CloseFocused => {
|
||||
if let Some(pane) = self.focus {
|
||||
if let Some(Pane { is_pinned, .. }) = self.panes.get(pane) {
|
||||
if !is_pinned {
|
||||
if let Some((_, sibling)) = self.panes.close(pane) {
|
||||
self.focus = Some(sibling);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(pane) = self.focus
|
||||
&& let Some(Pane { is_pinned, .. }) = self.panes.get(pane)
|
||||
&& !is_pinned
|
||||
&& let Some((_, sibling)) = self.panes.close(pane)
|
||||
{
|
||||
self.focus = Some(sibling);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -276,13 +273,13 @@ fn view_content<'a>(
|
|||
button(
|
||||
"Split vertically",
|
||||
Message::Split(pane_grid::Axis::Vertical, pane),
|
||||
)
|
||||
),
|
||||
if total_panes > 1 && !is_pinned {
|
||||
Some(button("Close", Message::Close(pane)).style(button::danger))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
]
|
||||
.push_maybe(if total_panes > 1 && !is_pinned {
|
||||
Some(button("Close", Message::Close(pane)).style(button::danger))
|
||||
} else {
|
||||
None
|
||||
})
|
||||
.spacing(5)
|
||||
.max_width(160);
|
||||
|
||||
|
|
@ -300,7 +297,7 @@ fn view_controls<'a>(
|
|||
is_pinned: bool,
|
||||
is_maximized: bool,
|
||||
) -> Element<'a, Message> {
|
||||
let row = row![].spacing(5).push_maybe(if total_panes > 1 {
|
||||
let maximize = if total_panes > 1 {
|
||||
let (content, message) = if is_maximized {
|
||||
("Restore", Message::Restore)
|
||||
} else {
|
||||
|
|
@ -315,7 +312,7 @@ fn view_controls<'a>(
|
|||
)
|
||||
} else {
|
||||
None
|
||||
});
|
||||
};
|
||||
|
||||
let close = button(text("Close").size(14))
|
||||
.style(button::danger)
|
||||
|
|
@ -326,7 +323,7 @@ fn view_controls<'a>(
|
|||
None
|
||||
});
|
||||
|
||||
row.push(close).into()
|
||||
row![maximize, close].spacing(5).into()
|
||||
}
|
||||
|
||||
mod style {
|
||||
|
|
|
|||
|
|
@ -88,18 +88,18 @@ impl QRGenerator {
|
|||
input,
|
||||
row![toggle_total_size, choose_theme]
|
||||
.spacing(20)
|
||||
.align_y(Center)
|
||||
.align_y(Center),
|
||||
self.total_size.map(|total_size| {
|
||||
slider(Self::SIZE_RANGE, total_size, Message::TotalSizeChanged)
|
||||
}),
|
||||
self.qr_code.as_ref().map(|data| {
|
||||
if let Some(total_size) = self.total_size {
|
||||
qr_code(data).total_size(total_size)
|
||||
} else {
|
||||
qr_code(data).cell_size(10.0)
|
||||
}
|
||||
})
|
||||
]
|
||||
.push_maybe(self.total_size.map(|total_size| {
|
||||
slider(Self::SIZE_RANGE, total_size, Message::TotalSizeChanged)
|
||||
}))
|
||||
.push_maybe(self.qr_code.as_ref().map(|data| {
|
||||
if let Some(total_size) = self.total_size {
|
||||
qr_code(data).total_size(total_size)
|
||||
} else {
|
||||
qr_code(data).cell_size(10.0)
|
||||
}
|
||||
}))
|
||||
.width(700)
|
||||
.spacing(20)
|
||||
.align_x(Center);
|
||||
|
|
|
|||
|
|
@ -158,15 +158,15 @@ impl Example {
|
|||
.spacing(10)
|
||||
.align_y(Center);
|
||||
|
||||
let crop_controls =
|
||||
column![crop_origin_controls, crop_dimension_controls]
|
||||
.push_maybe(
|
||||
self.crop_error
|
||||
.as_ref()
|
||||
.map(|error| text!("Crop error! \n{error}")),
|
||||
)
|
||||
.spacing(10)
|
||||
.align_x(Center);
|
||||
let crop_controls = column![
|
||||
crop_origin_controls,
|
||||
crop_dimension_controls,
|
||||
self.crop_error
|
||||
.as_ref()
|
||||
.map(|error| text!("Crop error! \n{error}")),
|
||||
]
|
||||
.spacing(10)
|
||||
.align_x(Center);
|
||||
|
||||
let controls = {
|
||||
let save_result =
|
||||
|
|
@ -208,8 +208,8 @@ impl Example {
|
|||
]
|
||||
.spacing(10)
|
||||
.align_x(Center),
|
||||
save_result.map(text)
|
||||
]
|
||||
.push_maybe(save_result.map(text))
|
||||
.spacing(40)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
30570747bb062e9f7730cdd58be961c84bcf4711a6983185bff6d903e8d29e9c
|
||||
0650eb2c27c21c5d48e1e00031a52d8471d8a3b4e827ad502c4628914f5c1c13
|
||||
|
|
@ -1 +1 @@
|
|||
d5a086a08544f98087189bd4ece8815e5290722a07cd580b933f1bf77a040c52
|
||||
ae1da92064373838152ac163072ee68135f530e0fef8146a01aea1df5cfdb494
|
||||
|
|
@ -1 +1 @@
|
|||
30e523961db89a3ee97ad1eac09e727ecb3dec485faa362534a9f5ad083b32dd
|
||||
8466dc0975c0bc7c06ed3c45df51e99b9d384394f8c3689b15231a872ba1262f
|
||||
|
|
@ -1 +1 @@
|
|||
bce5427d5105f68e1d7fa18a34fcc551cb78c2fefd9a583ba44686331133436d
|
||||
1c8f13cfb5d0bbbeb24b80ed35671e8a93d208d79ac4dbd069fe65c4a53c50c2
|
||||
|
|
@ -1 +1 @@
|
|||
c8a7edbd5a8bbf559134b84253e14e65340f4ffe3e22c272b21c8438e47ffaf7
|
||||
a1d30652db2cce98b5b86e8e29d776e2fc9091056aff8861cd54fa061161ed47
|
||||
|
|
@ -1 +1 @@
|
|||
63d646b22d3dffbb56dac2e3f345090bd26625a388dd6cc142359f2a7ac9c8df
|
||||
8c01615169803510f1cd4d051721b415adc7147672238aff1275fa3741edb507
|
||||
|
|
@ -1 +1 @@
|
|||
d26f55674cbd96bc3b534ffdd098a13199718ef9c5ffe8ece0882ddab714b776
|
||||
0b10823a1d218c145214ff2dcf751584669a3ca1d3e777a2cd618479a809523e
|
||||
|
|
@ -1 +1 @@
|
|||
482c44c13d4ff3de19e71f3dddf93bbee170e54e2d353e818811069de28e18ed
|
||||
26bc668c55650c6c25a14f76feeb1d1f78a96835aaac7a5f57b48b838cb28b14
|
||||
|
|
@ -1 +1 @@
|
|||
6738cc4fc6eb8a5d406c613a4b0f08c0e8dcd2c1a5444445eebd3888f9303841
|
||||
228eb8d64eed2f3726d27490b88a4519e36979a0ccfb0db8e164c5e5296b0739
|
||||
|
|
@ -1 +1 @@
|
|||
0a918c52538fc4848aa0c68d8f2d6f4c981ed68971dd9c725f0093a39ef7f353
|
||||
d579b14db1650e907f925302f23c53ebaba370aef6410cfa48fef70ab3138d1f
|
||||
|
|
@ -1 +1 @@
|
|||
de3e1a2c21e1a86d76ca99989c73e8a2596ef627bba95d246fab8f02d56bd0af
|
||||
896072b46221f83e1edaa37574436af6474969625f5c1a41cc5ddc2e20823cee
|
||||
|
|
@ -1 +1 @@
|
|||
3418ea4eb0f7786607ef02e7db4bc97309530f2f7c08f8aea15c768a13a09ca4
|
||||
60e1c95159caddb8bd7b8360e32ffd75472be37c4fcbd8ad23dabd0d000a4ec1
|
||||
|
|
@ -1 +1 @@
|
|||
c8474e02a9df23f123816a489c1ea7ae6cb994a0eca429592dfe6d933de1beee
|
||||
2e3c4ea86b5bd968b8ec77a7ec7b5b7ae29d5ee8e4b68a216c1fa11d92c015bc
|
||||
|
|
@ -1 +1 @@
|
|||
02095fd09c078be02dc41e29e55de25e8a79e6ad4293aa7e430257a9016dfb3d
|
||||
79ffced2a78689bac1a40ab154a478b4fff87154ee4a8bbf023d922c86b7d53b
|
||||
|
|
@ -1 +1 @@
|
|||
d82588a2aba3e7211f25b85ebb812a42dfa59137dd4b59d26f5f60d5b28e537f
|
||||
17c632cbef607502ed2c438f409a1c9bee382d9084c38772021f1f2a4ad3908c
|
||||
|
|
@ -1 +1 @@
|
|||
d6b73545929cc7794c1a918f069b5326ef129bed8f9ad2cd001be7d078a2b6a0
|
||||
359f7f2c1d7f87e6e0eb80a9a28f70f033d6321ba028d32bc372030b718ed481
|
||||
|
|
@ -1 +1 @@
|
|||
0ec7251c69755becd678b7aec398a275edf31cc077960723cd6b9364e8678548
|
||||
a908d8f154f2baf67455380b5d8b39003c08ba0c80f39e71d4bcd2377bc784fc
|
||||
|
|
@ -1 +1 @@
|
|||
4a15c475d45cf8eb0ccd6727cf6e493bd8c22454610b167a632a2328308faed1
|
||||
8d6c2bab1f6e9a8db1e2acc8eb76334170e046b709a36dd4ad4d86f8d47346a4
|
||||
|
|
@ -1 +1 @@
|
|||
49a41af93e89aab0a4e352e9cedfba3c6e18caf4267955c9d362bad40264a165
|
||||
2010df2e80bfc72e7e9274de07b77dc4843485f6be38266fdfb7a4f129d75da1
|
||||
|
|
@ -1 +1 @@
|
|||
8fcd80d4569dafdac4b4452b8ca8ab0cdceeb755f3c83d374ccd5ed4d0e8d43d
|
||||
74812d50467787ce39a33ad6bc89411d7b8bc0b13e1bbd45838fcc27c75aee98
|
||||
|
|
@ -1 +1 @@
|
|||
c37a32784c769c046f3aa881914b121af373b8c6e175ced89304d15b626a653a
|
||||
b04218ee65cd446b142596a2cd9ff69d5267969af86026a4ff394f3c13a4d842
|
||||
|
|
@ -1 +1 @@
|
|||
533d25575e8bf1111036fb082b424d0d0e60947a7da8428ab8c71e0bda01469e
|
||||
e1cbe8742f000921c86924056e9a45f95ee2a2a973743bf9f37fee65baccfb9b
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
use iced::keyboard;
|
||||
use iced::widget::{
|
||||
button, center, checkbox, column, container, horizontal_rule, pick_list,
|
||||
progress_bar, row, scrollable, slider, text, text_input, toggler,
|
||||
vertical_rule, vertical_space,
|
||||
button, center_x, center_y, checkbox, column, container, horizontal_rule,
|
||||
pick_list, progress_bar, row, scrollable, slider, text, text_input,
|
||||
toggler, vertical_rule, vertical_space,
|
||||
};
|
||||
use iced::{Center, Element, Fill, Subscription, Theme};
|
||||
use iced::{Center, Element, Fill, Shrink, Subscription, Theme};
|
||||
|
||||
pub fn main() -> iced::Result {
|
||||
iced::application(Styling::default, Styling::update, Styling::view)
|
||||
|
|
@ -78,38 +78,64 @@ impl Styling {
|
|||
.padding(10)
|
||||
.size(20);
|
||||
|
||||
let styled_button = |label| {
|
||||
button(text(label).width(Fill).center())
|
||||
.padding(10)
|
||||
.on_press(Message::ButtonPressed)
|
||||
};
|
||||
let buttons = {
|
||||
let styles = [
|
||||
("Primary", button::primary as fn(&Theme, _) -> _),
|
||||
("Secondary", button::secondary),
|
||||
("Success", button::success),
|
||||
("Warning", button::warning),
|
||||
("Danger", button::danger),
|
||||
];
|
||||
|
||||
let primary = styled_button("Primary");
|
||||
let success = styled_button("Success").style(button::success);
|
||||
let warning = styled_button("Warning").style(button::warning);
|
||||
let danger = styled_button("Danger").style(button::danger);
|
||||
let styled_button =
|
||||
|label| button(text(label).width(Fill).center()).padding(10);
|
||||
|
||||
column![
|
||||
row(styles.into_iter().map(|(name, style)| styled_button(
|
||||
name
|
||||
)
|
||||
.on_press(Message::ButtonPressed)
|
||||
.style(style)
|
||||
.into()))
|
||||
.spacing(10)
|
||||
.align_y(Center),
|
||||
row(styles.into_iter().map(|(name, style)| styled_button(
|
||||
name
|
||||
)
|
||||
.style(style)
|
||||
.into()))
|
||||
.spacing(10)
|
||||
.align_y(Center),
|
||||
]
|
||||
.spacing(10)
|
||||
};
|
||||
|
||||
let slider =
|
||||
|| slider(0.0..=100.0, self.slider_value, Message::SliderChanged);
|
||||
|
||||
let progress_bar = || progress_bar(0.0..=100.0, self.slider_value);
|
||||
|
||||
let scrollable = scrollable(column![
|
||||
let scroll_me = scrollable(column![
|
||||
"Scroll me!",
|
||||
vertical_space().height(800),
|
||||
"You did it!"
|
||||
])
|
||||
.width(Fill)
|
||||
.height(100);
|
||||
.height(Fill);
|
||||
|
||||
let checkbox = checkbox("Check me!", self.checkbox_value)
|
||||
let check = checkbox("Check me!", self.checkbox_value)
|
||||
.on_toggle(Message::CheckboxToggled);
|
||||
|
||||
let toggler = toggler(self.toggler_value)
|
||||
let check_disabled = checkbox("Disabled", self.checkbox_value);
|
||||
|
||||
let toggle = toggler(self.toggler_value)
|
||||
.label("Toggle me!")
|
||||
.on_toggle(Message::TogglerToggled)
|
||||
.spacing(10);
|
||||
|
||||
let disabled_toggle =
|
||||
toggler(self.toggler_value).label("Disabled").spacing(10);
|
||||
|
||||
let card = {
|
||||
container(
|
||||
column![
|
||||
|
|
@ -128,18 +154,17 @@ impl Styling {
|
|||
choose_theme,
|
||||
horizontal_rule(1),
|
||||
text_input,
|
||||
row![primary, success, warning, danger]
|
||||
.spacing(10)
|
||||
.align_y(Center),
|
||||
buttons,
|
||||
slider(),
|
||||
progress_bar(),
|
||||
row![
|
||||
scrollable,
|
||||
row![vertical_rule(1), column![checkbox, toggler].spacing(20)]
|
||||
.spacing(20)
|
||||
scroll_me,
|
||||
vertical_rule(1),
|
||||
column![check, check_disabled, toggle, disabled_toggle]
|
||||
.spacing(10)
|
||||
]
|
||||
.spacing(10)
|
||||
.height(100)
|
||||
.height(Shrink)
|
||||
.align_y(Center),
|
||||
card
|
||||
]
|
||||
|
|
@ -147,7 +172,9 @@ impl Styling {
|
|||
.padding(20)
|
||||
.max_width(600);
|
||||
|
||||
center(content).into()
|
||||
center_y(scrollable(center_x(content)).spacing(10))
|
||||
.padding(10)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn subscription(&self) -> Subscription<Message> {
|
||||
|
|
|
|||
10
examples/table/Cargo.toml
Normal file
10
examples/table/Cargo.toml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "table"
|
||||
version = "0.1.0"
|
||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||
edition = "2024"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
iced.workspace = true
|
||||
iced.features = ["debug"]
|
||||
252
examples/table/src/main.rs
Normal file
252
examples/table/src/main.rs
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
use iced::font;
|
||||
use iced::time::{Duration, hours, minutes};
|
||||
use iced::widget::{
|
||||
center_x, center_y, column, container, row, scrollable, slider, table,
|
||||
text, tooltip,
|
||||
};
|
||||
use iced::{Center, Element, Fill, Font, Right, Theme};
|
||||
|
||||
pub fn main() -> iced::Result {
|
||||
iced::application(Table::new, Table::update, Table::view)
|
||||
.theme(|_| Theme::CatppuccinMocha)
|
||||
.run()
|
||||
}
|
||||
|
||||
struct Table {
|
||||
events: Vec<Event>,
|
||||
padding: (f32, f32),
|
||||
separator: (f32, f32),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Message {
|
||||
PaddingChanged(f32, f32),
|
||||
SeparatorChanged(f32, f32),
|
||||
}
|
||||
|
||||
impl Table {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
events: Event::list(),
|
||||
padding: (10.0, 5.0),
|
||||
separator: (1.0, 1.0),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Message) {
|
||||
match message {
|
||||
Message::PaddingChanged(x, y) => self.padding = (x, y),
|
||||
Message::SeparatorChanged(x, y) => self.separator = (x, y),
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let table = {
|
||||
let bold = |header| {
|
||||
text(header).font(Font {
|
||||
weight: font::Weight::Bold,
|
||||
..Font::DEFAULT
|
||||
})
|
||||
};
|
||||
|
||||
let columns = [
|
||||
table::column(bold("Name"), |event: &Event| text(&event.name)),
|
||||
table::column(bold("Time"), |event: &Event| {
|
||||
let minutes = event.duration.as_secs() / 60;
|
||||
|
||||
text!("{minutes} min").style(if minutes > 90 {
|
||||
text::warning
|
||||
} else {
|
||||
text::default
|
||||
})
|
||||
})
|
||||
.align_x(Right)
|
||||
.align_y(Center),
|
||||
table::column(bold("Price"), |event: &Event| {
|
||||
if event.price > 0.0 {
|
||||
text!("${:.2}", event.price).style(
|
||||
if event.price > 100.0 {
|
||||
text::warning
|
||||
} else {
|
||||
text::default
|
||||
},
|
||||
)
|
||||
} else {
|
||||
text("Free").style(text::success).width(Fill).center()
|
||||
}
|
||||
})
|
||||
.align_x(Right)
|
||||
.align_y(Center),
|
||||
table::column(bold("Rating"), |event: &Event| {
|
||||
text!("{:.2}", event.rating).style(if event.rating > 4.7 {
|
||||
text::success
|
||||
} else if event.rating < 2.0 {
|
||||
text::danger
|
||||
} else {
|
||||
text::default
|
||||
})
|
||||
})
|
||||
.align_x(Right)
|
||||
.align_y(Center),
|
||||
];
|
||||
|
||||
table(columns, &self.events)
|
||||
.padding_x(self.padding.0)
|
||||
.padding_y(self.padding.1)
|
||||
.separator_x(self.separator.0)
|
||||
.separator_y(self.separator.1)
|
||||
};
|
||||
|
||||
let controls = {
|
||||
let labeled_slider =
|
||||
|label,
|
||||
range: std::ops::RangeInclusive<f32>,
|
||||
(x, y),
|
||||
on_change: fn(f32, f32) -> Message| {
|
||||
row![
|
||||
text(label).font(Font::MONOSPACE).size(14).width(100),
|
||||
tooltip(
|
||||
slider(range.clone(), x, move |x| on_change(x, y)),
|
||||
text!("{x:.0}px").font(Font::MONOSPACE).size(10),
|
||||
tooltip::Position::Left
|
||||
),
|
||||
tooltip(
|
||||
slider(range, y, move |y| on_change(x, y)),
|
||||
text!("{y:.0}px").font(Font::MONOSPACE).size(10),
|
||||
tooltip::Position::Right
|
||||
),
|
||||
]
|
||||
.spacing(10)
|
||||
.align_y(Center)
|
||||
};
|
||||
|
||||
column![
|
||||
labeled_slider(
|
||||
"Padding",
|
||||
0.0..=30.0,
|
||||
self.padding,
|
||||
Message::PaddingChanged
|
||||
),
|
||||
labeled_slider(
|
||||
"Separator",
|
||||
0.0..=5.0,
|
||||
self.separator,
|
||||
Message::SeparatorChanged
|
||||
)
|
||||
]
|
||||
.spacing(10)
|
||||
.width(400)
|
||||
};
|
||||
|
||||
column![
|
||||
center_y(scrollable(center_x(table)).spacing(10)).padding(10),
|
||||
center_x(controls).padding(10).style(container::dark)
|
||||
]
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
struct Event {
|
||||
name: String,
|
||||
duration: Duration,
|
||||
price: f32,
|
||||
rating: f32,
|
||||
}
|
||||
|
||||
impl Event {
|
||||
fn list() -> Vec<Self> {
|
||||
vec![
|
||||
Event {
|
||||
name: "Get lost in a hacker bookstore".to_owned(),
|
||||
duration: hours(2),
|
||||
price: 0.0,
|
||||
rating: 4.9,
|
||||
},
|
||||
Event {
|
||||
name: "Buy vintage synth at Noisebridge flea market".to_owned(),
|
||||
duration: hours(1),
|
||||
price: 150.0,
|
||||
rating: 4.8,
|
||||
},
|
||||
Event {
|
||||
name: "Eat a questionable hot dog at 2AM".to_owned(),
|
||||
duration: minutes(20),
|
||||
price: 5.0,
|
||||
rating: 1.7,
|
||||
},
|
||||
Event {
|
||||
name: "Ride the MUNI for the story".to_owned(),
|
||||
duration: minutes(60),
|
||||
price: 3.0,
|
||||
rating: 4.1,
|
||||
},
|
||||
Event {
|
||||
name: "Scream into the void from Twin Peaks".to_owned(),
|
||||
duration: minutes(40),
|
||||
price: 0.0,
|
||||
rating: 4.9,
|
||||
},
|
||||
Event {
|
||||
name: "Buy overpriced coffee and feel things".to_owned(),
|
||||
duration: minutes(25),
|
||||
price: 6.5,
|
||||
rating: 4.5,
|
||||
},
|
||||
Event {
|
||||
name: "Attend an underground robot poetry slam".to_owned(),
|
||||
duration: hours(1),
|
||||
price: 12.0,
|
||||
rating: 4.8,
|
||||
},
|
||||
Event {
|
||||
name: "Browse cursed tech at a retro computer fair".to_owned(),
|
||||
duration: hours(2),
|
||||
price: 10.0,
|
||||
rating: 4.7,
|
||||
},
|
||||
Event {
|
||||
name: "Try to order at a secret ramen place with no sign"
|
||||
.to_owned(),
|
||||
duration: minutes(50),
|
||||
price: 14.0,
|
||||
rating: 4.6,
|
||||
},
|
||||
Event {
|
||||
name: "Join a spontaneous rooftop drone rave".to_owned(),
|
||||
duration: hours(3),
|
||||
price: 0.0,
|
||||
rating: 4.9,
|
||||
},
|
||||
Event {
|
||||
name: "Sketch a stranger at Dolores Park".to_owned(),
|
||||
duration: minutes(45),
|
||||
price: 0.0,
|
||||
rating: 4.4,
|
||||
},
|
||||
Event {
|
||||
name: "Visit the Museum of Obsolete APIs".to_owned(),
|
||||
duration: hours(1),
|
||||
price: 9.99,
|
||||
rating: 4.2,
|
||||
},
|
||||
Event {
|
||||
name: "Chase the last working payphone".to_owned(),
|
||||
duration: minutes(35),
|
||||
price: 0.25,
|
||||
rating: 4.0,
|
||||
},
|
||||
Event {
|
||||
name: "Trade zines with a punk on BART".to_owned(),
|
||||
duration: minutes(30),
|
||||
price: 3.5,
|
||||
rating: 4.7,
|
||||
},
|
||||
Event {
|
||||
name: "Get a tattoo of the Git logo".to_owned(),
|
||||
duration: hours(1),
|
||||
price: 200.0,
|
||||
rating: 4.6,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
0e355b080ad33905145e9f70a3b29e2481197c8fc8f42491acd5358238ebbd5f
|
||||
99f418007af163f172e163565f166da31015521e1bf7de95fa55cda2fb5a7db5
|
||||
|
|
@ -1 +0,0 @@
|
|||
804a1bb6d49e3b3158463202960447d9e7820b967280f41dd0c34c00d3edf2c3
|
||||
|
|
@ -142,17 +142,17 @@ impl Tour {
|
|||
}
|
||||
|
||||
fn view(&self) -> Element<'_, Message> {
|
||||
let controls =
|
||||
row![]
|
||||
.push_maybe(self.screen.previous().is_some().then(|| {
|
||||
padded_button("Back")
|
||||
.on_press(Message::BackPressed)
|
||||
.style(button::secondary)
|
||||
}))
|
||||
.push(horizontal_space())
|
||||
.push_maybe(self.can_continue().then(|| {
|
||||
padded_button("Next").on_press(Message::NextPressed)
|
||||
}));
|
||||
let controls = row![
|
||||
self.screen.previous().is_some().then(|| {
|
||||
padded_button("Back")
|
||||
.on_press(Message::BackPressed)
|
||||
.style(button::secondary)
|
||||
}),
|
||||
horizontal_space(),
|
||||
self.can_continue().then(|| {
|
||||
padded_button("Next").on_press(Message::NextPressed)
|
||||
})
|
||||
];
|
||||
|
||||
let screen = match self.screen {
|
||||
Screen::Welcome => self.welcome(),
|
||||
|
|
|
|||
|
|
@ -119,11 +119,11 @@ impl WebSocket {
|
|||
let mut button = button(text("Send").height(40).align_y(Center))
|
||||
.padding([0, 20]);
|
||||
|
||||
if matches!(self.state, State::Connected(_)) {
|
||||
if let Some(message) = echo::Message::new(&self.new_message) {
|
||||
input = input.on_submit(Message::Send(message.clone()));
|
||||
button = button.on_press(Message::Send(message));
|
||||
}
|
||||
if matches!(self.state, State::Connected(_))
|
||||
&& let Some(message) = echo::Message::new(&self.new_message)
|
||||
{
|
||||
input = input.on_submit(Message::Send(message.clone()));
|
||||
button = button.on_press(Message::Send(message));
|
||||
}
|
||||
|
||||
row![input, button].spacing(10).align_y(Center)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue