From 331f658937d992509bb0564e8464fb5eda9d8fc7 Mon Sep 17 00:00:00 2001 From: Dominik Wilkowski Date: Mon, 20 Nov 2023 17:08:00 +1000 Subject: [PATCH] added layout example (#190) --- examples/layout/Cargo.toml | 8 ++ examples/layout/src/holy_grail.rs | 106 +++++++++++++++++++++++++++ examples/layout/src/left_sidebar.rs | 80 ++++++++++++++++++++ examples/layout/src/main.rs | 85 +++++++++++++++++++++ examples/layout/src/right_sidebar.rs | 80 ++++++++++++++++++++ 5 files changed, 359 insertions(+) create mode 100644 examples/layout/Cargo.toml create mode 100644 examples/layout/src/holy_grail.rs create mode 100644 examples/layout/src/left_sidebar.rs create mode 100644 examples/layout/src/main.rs create mode 100644 examples/layout/src/right_sidebar.rs diff --git a/examples/layout/Cargo.toml b/examples/layout/Cargo.toml new file mode 100644 index 00000000..e8eba25a --- /dev/null +++ b/examples/layout/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "layout" +version = "0.1.0" +edition = "2021" + +[dependencies] +im = "15.1.0" +floem = { path = "../.." } diff --git a/examples/layout/src/holy_grail.rs b/examples/layout/src/holy_grail.rs new file mode 100644 index 00000000..ac0632d2 --- /dev/null +++ b/examples/layout/src/holy_grail.rs @@ -0,0 +1,106 @@ +use floem::{ + event::EventListener, + peniko::Color, + reactive::create_signal, + style::Position, + view::View, + views::{ + container, h_stack, label, scroll, v_stack, virtual_list, Decorators, VirtualListDirection, + VirtualListItemSize, + }, +}; + +const SIDEBAR_WIDTH: f64 = 140.0; +const SEARCHBAR_HEIGHT: f64 = 30.0; + +pub fn holy_grail_view() -> impl View { + let long_list: im::Vector = (0..100).collect(); + let (long_list, _set_long_list) = create_signal(long_list); + + let top_bar = label(|| String::from("Top bar")) + .style(|s| s.padding(10.0).width_full().height(SEARCHBAR_HEIGHT)); + + let side_bar_right = scroll({ + virtual_list( + VirtualListDirection::Vertical, + VirtualListItemSize::Fixed(Box::new(|| 22.0)), + move || long_list.get(), + move |item| *item, + move |item| { + label(move || item.to_string()).style(move |s| { + s.padding(10.0) + .padding_top(3.0) + .padding_bottom(3.0) + .width(SIDEBAR_WIDTH) + .items_start() + .border_bottom(1.0) + .border_color(Color::rgb8(205, 205, 205)) + }) + }, + ) + .style(|s| s.flex_col().width(SIDEBAR_WIDTH - 1.0)) + }) + .style(|s| { + s.width(SIDEBAR_WIDTH) + .border_left(1.0) + .border_top(1.0) + .border_color(Color::rgb8(205, 205, 205)) + }); + + let side_bar_left = scroll({ + virtual_list( + VirtualListDirection::Vertical, + VirtualListItemSize::Fixed(Box::new(|| 22.0)), + move || long_list.get(), + move |item| *item, + move |item| { + label(move || item.to_string()).style(move |s| { + s.padding(10.0) + .padding_top(3.0) + .padding_bottom(3.0) + .width(SIDEBAR_WIDTH) + .items_start() + .border_bottom(1.0) + .border_color(Color::rgb8(205, 205, 205)) + }) + }, + ) + .style(|s| s.flex_col().width(SIDEBAR_WIDTH - 1.0)) + }) + .style(|s| { + s.width(SIDEBAR_WIDTH) + .border_right(1.0) + .border_top(1.0) + .border_color(Color::rgb8(205, 205, 205)) + }); + + let main_window = scroll( + container(label(move || String::from("Hello world")).style(|s| s.padding(10.0))) + .style(|s| s.flex_col().items_start().padding_bottom(10.0)), + ) + .style(|s| s.flex_col().flex_basis(0).min_width(0).flex_grow(1.0)) + .style(|s| { + s.border_top(1.0) + .border_color(Color::rgb8(205, 205, 205)) + .width_full() + .min_width(150.0) + }); + + let content = h_stack((side_bar_left, main_window, side_bar_right)).style(|s| { + s.position(Position::Absolute) + .inset_top(SEARCHBAR_HEIGHT) + .inset_bottom(0.0) + .width_full() + }); + + let view = v_stack((top_bar, content)).style(|s| s.width_full().height_full()); + + let id = view.id(); + view.on_event_stop(EventListener::KeyUp, move |e| { + if let floem::event::Event::KeyUp(e) = e { + if e.key.logical_key == floem::keyboard::Key::Named(floem::keyboard::NamedKey::F11) { + id.inspect(); + } + } + }) +} diff --git a/examples/layout/src/left_sidebar.rs b/examples/layout/src/left_sidebar.rs new file mode 100644 index 00000000..953e2327 --- /dev/null +++ b/examples/layout/src/left_sidebar.rs @@ -0,0 +1,80 @@ +use floem::{ + event::EventListener, + peniko::Color, + reactive::create_signal, + style::Position, + view::View, + views::{ + container, h_stack, label, scroll, v_stack, virtual_list, Decorators, VirtualListDirection, + VirtualListItemSize, + }, +}; + +const SIDEBAR_WIDTH: f64 = 140.0; +const SEARCHBAR_HEIGHT: f64 = 30.0; + +pub fn left_sidebar_view() -> impl View { + let long_list: im::Vector = (0..100).collect(); + let (long_list, _set_long_list) = create_signal(long_list); + + let top_bar = label(|| String::from("Top bar")) + .style(|s| s.padding(10.0).width_full().height(SEARCHBAR_HEIGHT)); + + let side_bar = scroll({ + virtual_list( + VirtualListDirection::Vertical, + VirtualListItemSize::Fixed(Box::new(|| 22.0)), + move || long_list.get(), + move |item| *item, + move |item| { + label(move || item.to_string()).style(move |s| { + s.padding(10.0) + .padding_top(3.0) + .padding_bottom(3.0) + .width(SIDEBAR_WIDTH) + .items_start() + .border_bottom(1.0) + .border_color(Color::rgb8(205, 205, 205)) + }) + }, + ) + .style(|s| s.flex_col().width(SIDEBAR_WIDTH - 1.0)) + }) + .style(|s| { + s.width(SIDEBAR_WIDTH) + .border_right(1.0) + .border_top(1.0) + .border_color(Color::rgb8(205, 205, 205)) + }); + + let main_window = scroll( + container(label(move || String::from("Hello world")).style(|s| s.padding(10.0))) + .style(|s| s.flex_col().items_start().padding_bottom(10.0)), + ) + .style(|s| { + s.flex_col() + .flex_basis(0) + .min_width(0) + .flex_grow(1.0) + .border_top(1.0) + .border_color(Color::rgb8(205, 205, 205)) + }); + + let content = h_stack((side_bar, main_window)).style(|s| { + s.position(Position::Absolute) + .inset_top(SEARCHBAR_HEIGHT) + .inset_bottom(0.0) + .width_full() + }); + + let view = v_stack((top_bar, content)).style(|s| s.width_full().height_full()); + + let id = view.id(); + view.on_event_stop(EventListener::KeyUp, move |e| { + if let floem::event::Event::KeyUp(e) = e { + if e.key.logical_key == floem::keyboard::Key::Named(floem::keyboard::NamedKey::F11) { + id.inspect(); + } + } + }) +} diff --git a/examples/layout/src/main.rs b/examples/layout/src/main.rs new file mode 100644 index 00000000..0107c449 --- /dev/null +++ b/examples/layout/src/main.rs @@ -0,0 +1,85 @@ +use floem::{ + event::{Event, EventListener}, + keyboard::{Key, NamedKey}, + kurbo::Size, + style::AlignContent, + view::View, + views::{container, h_stack, label, v_stack, Decorators}, + widgets::button, + window::{new_window, WindowConfig}, +}; + +pub mod holy_grail; +pub mod left_sidebar; +pub mod right_sidebar; + +fn list_item(name: String, view_fn: impl Fn() -> V) -> impl View { + h_stack(( + label(move || name.clone()).style(|s| s), + container(view_fn()).style(|s| s.width_full().justify_content(AlignContent::End)), + )) + .style(|s| s.width(200)) +} + +fn app_view() -> impl View { + let view = v_stack(( + label(move || String::from("Layouts")).style(|s| s.font_size(30.0).margin_bottom(15.0)), + list_item(String::from("Left sidebar"), move || { + button(|| "Open").on_click_stop(|_| { + new_window( + |_| left_sidebar::left_sidebar_view(), + Some( + WindowConfig::default() + .size(Size::new(700.0, 400.0)) + .title("Left sidebar"), + ), + ); + }) + }), + list_item(String::from("Right sidebar"), move || { + button(|| "Open").on_click_stop(|_| { + new_window( + |_| right_sidebar::right_sidebar_view(), + Some( + WindowConfig::default() + .size(Size::new(700.0, 400.0)) + .title("Right sidebar"), + ), + ); + }) + }), + list_item(String::from("Holy grail"), move || { + button(|| "Open").on_click_stop(|_| { + new_window( + |_| holy_grail::holy_grail_view(), + Some( + WindowConfig::default() + .size(Size::new(700.0, 400.0)) + .title("Holy Grail"), + ), + ); + }) + }), + )) + .style(|s| { + s.flex_col() + .width_full() + .height_full() + .padding(10.0) + .gap(0.0, 10.0) + }); + + let id = view.id(); + view.on_event_stop(EventListener::KeyUp, move |e| { + if let Event::KeyUp(e) = e { + if e.key.logical_key == Key::Named(NamedKey::F11) { + id.inspect(); + } + } + }) + .window_title(|| String::from("Layout examples")) +} + +fn main() { + floem::launch(app_view); +} diff --git a/examples/layout/src/right_sidebar.rs b/examples/layout/src/right_sidebar.rs new file mode 100644 index 00000000..ef032c87 --- /dev/null +++ b/examples/layout/src/right_sidebar.rs @@ -0,0 +1,80 @@ +use floem::{ + event::EventListener, + peniko::Color, + reactive::create_signal, + style::Position, + view::View, + views::{ + container, h_stack, label, scroll, v_stack, virtual_list, Decorators, VirtualListDirection, + VirtualListItemSize, + }, +}; + +const SIDEBAR_WIDTH: f64 = 140.0; +const SEARCHBAR_HEIGHT: f64 = 30.0; + +pub fn right_sidebar_view() -> impl View { + let long_list: im::Vector = (0..100).collect(); + let (long_list, _set_long_list) = create_signal(long_list); + + let top_bar = label(|| String::from("Top bar")) + .style(|s| s.padding(10.0).width_full().height(SEARCHBAR_HEIGHT)); + + let side_bar = scroll({ + virtual_list( + VirtualListDirection::Vertical, + VirtualListItemSize::Fixed(Box::new(|| 22.0)), + move || long_list.get(), + move |item| *item, + move |item| { + label(move || item.to_string()).style(move |s| { + s.padding(10.0) + .padding_top(3.0) + .padding_bottom(3.0) + .width(SIDEBAR_WIDTH) + .items_start() + .border_bottom(1.0) + .border_color(Color::rgb8(205, 205, 205)) + }) + }, + ) + .style(|s| s.flex_col().width(SIDEBAR_WIDTH - 1.0)) + }) + .style(|s| { + s.width(SIDEBAR_WIDTH) + .border_left(1.0) + .border_top(1.0) + .border_color(Color::rgb8(205, 205, 205)) + }); + + let main_window = scroll( + container(label(move || String::from("Hello world")).style(|s| s.padding(10.0))) + .style(|s| s.flex_col().items_start().padding_bottom(10.0)), + ) + .style(|s| { + s.flex_col() + .flex_basis(0) + .min_width(0) + .flex_grow(1.0) + .border_top(1.0) + .border_color(Color::rgb8(205, 205, 205)) + }); + + let content = h_stack((main_window, side_bar)).style(|s| { + s.position(Position::Absolute) + .inset_top(SEARCHBAR_HEIGHT) + .inset_bottom(0.0) + .width_full() + }); + + let view = v_stack((top_bar, content)).style(|s| s.width_full().height_full()); + + let id = view.id(); + view.on_event_stop(EventListener::KeyUp, move |e| { + if let floem::event::Event::KeyUp(e) = e { + if e.key.logical_key == floem::keyboard::Key::Named(floem::keyboard::NamedKey::F11) { + id.inspect(); + } + } + }) +}