-
Notifications
You must be signed in to change notification settings - Fork 138
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
92ba640
commit 7e78abb
Showing
6 changed files
with
277 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} | ||
}) | ||
} |