Skip to content

Commit

Permalink
added two new layouts (#222)
Browse files Browse the repository at this point in the history
  • Loading branch information
dominikwilkowski authored Dec 12, 2023
1 parent 92ba640 commit 7e78abb
Show file tree
Hide file tree
Showing 6 changed files with 277 additions and 10 deletions.
122 changes: 122 additions & 0 deletions examples/layout/src/draggable_sidebar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use floem::{
event::{Event, EventListener},
peniko::Color,
reactive::{create_rw_signal, create_signal},
style::{CursorStyle, Position},
view::View,
views::{
container, h_stack, label, scroll, virtual_list, Decorators, VirtualListDirection,
VirtualListItemSize,
},
EventPropagation,
};

const SIDEBAR_WIDTH: f64 = 100.0;

pub fn draggable_sidebar_view() -> impl View {
let long_list: im::Vector<i32> = (0..100).collect();
let (long_list, _set_long_list) = create_signal(long_list);
let sidebar_width = create_rw_signal(SIDEBAR_WIDTH);
let is_sidebar_dragging = create_rw_signal(false);

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 || format!("Item {} with long lines", item)).style(move |s| {
s.text_ellipsis()
.padding(10.0)
.padding_top(3.0)
.padding_bottom(3.0)
.width(sidebar_width.get())
.items_start()
.border_bottom(1.0)
.border_color(Color::rgb8(205, 205, 205))
})
},
)
.style(move |s| s.flex_col().width(sidebar_width.get() - 1.0))
})
.style(move |s| {
s.width(sidebar_width.get())
.border_right(1.0)
.border_top(1.0)
.border_color(Color::rgb8(205, 205, 205))
});

let main_window = scroll(
container(
label(move || String::from("<-- drag me!\n \n(double click to return to default)"))
.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 dragger = label(|| "")
.style(move |s| {
s.position(Position::Absolute)
.z_index(10)
.inset_top(0)
.inset_bottom(0)
.inset_left(sidebar_width.get())
.width(10)
.border_left(1)
.border_color(Color::rgb8(205, 205, 205))
.hover(|s| {
s.border_left(2)
.border_color(Color::rgb8(41, 98, 218))
.cursor(CursorStyle::ColResize)
})
.apply_if(is_sidebar_dragging.get(), |s| {
s.border_left(2).border_color(Color::rgb8(41, 98, 218))
})
})
.draggable()
.dragging_style(|s| s.border_color(Color::TRANSPARENT))
.on_event(EventListener::DragStart, move |_| {
is_sidebar_dragging.set(true);
EventPropagation::Continue
})
.on_event(EventListener::DragEnd, move |_| {
is_sidebar_dragging.set(false);
EventPropagation::Continue
})
.on_event(EventListener::DoubleClick, move |_| {
sidebar_width.set(SIDEBAR_WIDTH);
EventPropagation::Continue
});

let view = h_stack((side_bar, dragger, main_window))
.on_event(EventListener::PointerMove, move |event| {
let pos = match event {
Event::PointerMove(p) => p.pos,
_ => (0.0, 0.0).into(),
};

if is_sidebar_dragging.get() {
sidebar_width.set(pos.x);
}
EventPropagation::Continue
})
.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();
}
}
})
}
6 changes: 3 additions & 3 deletions examples/layout/src/holy_grail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ use floem::{
};

const SIDEBAR_WIDTH: f64 = 140.0;
const SEARCHBAR_HEIGHT: f64 = 30.0;
const TOPBAR_HEIGHT: f64 = 30.0;

pub fn holy_grail_view() -> impl View {
let long_list: im::Vector<i32> = (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));
.style(|s| s.padding(10.0).width_full().height(TOPBAR_HEIGHT));

let side_bar_right = scroll({
virtual_list(
Expand Down Expand Up @@ -88,7 +88,7 @@ pub fn holy_grail_view() -> impl View {

let content = h_stack((side_bar_left, main_window, side_bar_right)).style(|s| {
s.position(Position::Absolute)
.inset_top(SEARCHBAR_HEIGHT)
.inset_top(TOPBAR_HEIGHT)
.inset_bottom(0.0)
.width_full()
});
Expand Down
6 changes: 3 additions & 3 deletions examples/layout/src/left_sidebar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ use floem::{
};

const SIDEBAR_WIDTH: f64 = 140.0;
const SEARCHBAR_HEIGHT: f64 = 30.0;
const TOPBAR_HEIGHT: f64 = 30.0;

pub fn left_sidebar_view() -> impl View {
let long_list: im::Vector<i32> = (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));
.style(|s| s.padding(10.0).width_full().height(TOPBAR_HEIGHT));

let side_bar = scroll({
virtual_list(
Expand Down Expand Up @@ -62,7 +62,7 @@ pub fn left_sidebar_view() -> impl View {

let content = h_stack((side_bar, main_window)).style(|s| {
s.position(Position::Absolute)
.inset_top(SEARCHBAR_HEIGHT)
.inset_top(TOPBAR_HEIGHT)
.inset_bottom(0.0)
.width_full()
});
Expand Down
31 changes: 30 additions & 1 deletion examples/layout/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ use floem::{
window::{new_window, WindowConfig},
};

pub mod draggable_sidebar;
pub mod holy_grail;
pub mod left_sidebar;
pub mod right_sidebar;
pub mod tab_navigation;

fn list_item<V: View + 'static>(name: String, view_fn: impl Fn() -> V) -> impl View {
h_stack((
Expand All @@ -23,7 +25,8 @@ fn list_item<V: View + 'static>(name: String, view_fn: impl Fn() -> V) -> impl V

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)),
label(move || String::from("Static 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(
Expand Down Expand Up @@ -60,6 +63,32 @@ fn app_view() -> impl View {
);
})
}),
label(move || String::from("Interactive layouts"))
.style(|s| s.font_size(30.0).margin_top(15.0).margin_bottom(15.0)),
list_item(String::from("Tab navigation"), move || {
button(|| "Open").on_click_stop(|_| {
new_window(
|_| tab_navigation::tab_navigation_view(),
Some(
WindowConfig::default()
.size(Size::new(400.0, 250.0))
.title("Tab navigation"),
),
);
})
}),
list_item(String::from("Draggable sidebar"), move || {
button(|| "Open").on_click_stop(|_| {
new_window(
|_| draggable_sidebar::draggable_sidebar_view(),
Some(
WindowConfig::default()
.size(Size::new(700.0, 400.0))
.title("Draggable sidebar"),
),
);
})
}),
))
.style(|s| {
s.flex_col()
Expand Down
6 changes: 3 additions & 3 deletions examples/layout/src/right_sidebar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ use floem::{
};

const SIDEBAR_WIDTH: f64 = 140.0;
const SEARCHBAR_HEIGHT: f64 = 30.0;
const TOPBAR_HEIGHT: f64 = 30.0;

pub fn right_sidebar_view() -> impl View {
let long_list: im::Vector<i32> = (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));
.style(|s| s.padding(10.0).width_full().height(TOPBAR_HEIGHT));

let side_bar = scroll({
virtual_list(
Expand Down Expand Up @@ -62,7 +62,7 @@ pub fn right_sidebar_view() -> impl View {

let content = h_stack((main_window, side_bar)).style(|s| {
s.position(Position::Absolute)
.inset_top(SEARCHBAR_HEIGHT)
.inset_top(TOPBAR_HEIGHT)
.inset_bottom(0.0)
.width_full()
});
Expand Down
116 changes: 116 additions & 0 deletions examples/layout/src/tab_navigation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use floem::{
cosmic_text::Weight,
event::EventListener,
peniko::Color,
reactive::{create_signal, ReadSignal, WriteSignal},
style::{CursorStyle, Position},
view::View,
views::{container, h_stack, label, scroll, tab, v_stack, Decorators},
};

#[derive(Clone, Copy, Eq, Hash, PartialEq)]
enum Tabs {
General,
Settings,
Feedback,
}

impl std::fmt::Display for Tabs {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
Tabs::General => write!(f, "General"),
Tabs::Settings => write!(f, "Settings"),
Tabs::Feedback => write!(f, "Feedback"),
}
}
}

fn tab_button(
this_tab: Tabs,
tabs: ReadSignal<im::Vector<Tabs>>,
set_active_tab: WriteSignal<usize>,
active_tab: ReadSignal<usize>,
) -> impl View {
label(move || this_tab)
.style(|s| s.justify_center())
.keyboard_navigatable()
.on_click_stop(move |_| {
set_active_tab.update(|v: &mut usize| {
*v = tabs
.get_untracked()
.iter()
.position(|it| *it == this_tab)
.unwrap();
});
})
.style(move |s| {
s.width(50)
.items_center()
.hover(|s| s.font_weight(Weight::BOLD).cursor(CursorStyle::Pointer))
.apply_if(
active_tab.get()
== tabs
.get_untracked()
.iter()
.position(|it| *it == this_tab)
.unwrap(),
|s| s.font_weight(Weight::BOLD),
)
})
}

const TABBAR_HEIGHT: f64 = 37.0;
const CONTENT_PADDING: f64 = 10.0;

pub fn tab_navigation_view() -> impl View {
let tabs = vec![Tabs::General, Tabs::Settings, Tabs::Feedback]
.into_iter()
.collect::<im::Vector<Tabs>>();
let (tabs, _set_tabs) = create_signal(tabs);
let (active_tab, set_active_tab) = create_signal(0);

let tabs_bar = h_stack((
tab_button(Tabs::General, tabs, set_active_tab, active_tab),
tab_button(Tabs::Settings, tabs, set_active_tab, active_tab),
tab_button(Tabs::Feedback, tabs, set_active_tab, active_tab),
))
.style(|s| {
s.flex_row()
.width_full()
.height(TABBAR_HEIGHT)
.gap(5, 0)
.padding(CONTENT_PADDING)
.border_bottom(1)
.border_color(Color::rgb8(205, 205, 205))
});

let main_content = container(
scroll(
tab(
move || active_tab.get(),
move || tabs.get(),
|it| *it,
|it| container(label(move || format!("{}", it))),
)
.style(|s| s.padding(CONTENT_PADDING).padding_bottom(10.0)),
)
.style(|s| s.flex_col().flex_basis(0).min_width(0).flex_grow(1.0)),
)
.style(|s| {
s.position(Position::Absolute)
.inset_top(TABBAR_HEIGHT)
.inset_bottom(0.0)
.width_full()
});

let settings_view = v_stack((tabs_bar, main_content)).style(|s| s.width_full().height_full());

let id = settings_view.id();
settings_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();
}
}
})
}

0 comments on commit 7e78abb

Please sign in to comment.