Skip to content

Commit

Permalink
Move some editor styling to floem style props (#398)
Browse files Browse the repository at this point in the history
* Move some editor styling to floem style props

* check for scroll_beyond_last_line

* fixes

* updates

* revert whitespace changes

* fix test

* fix examples add more props

* Add docs to editor style methods

* Improve gutter colors and docs

* cargo fmt

* Add default light/dark colors

* fix
  • Loading branch information
jrmoulton authored Mar 27, 2024
1 parent f0e12db commit 402c58c
Show file tree
Hide file tree
Showing 22 changed files with 865 additions and 498 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
/.lapce
/.idea
.DS_Store
rustc-ice*
9 changes: 9 additions & 0 deletions editor-core/src/indent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ pub enum IndentStyle {
Spaces(u8),
}

impl std::fmt::Display for IndentStyle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IndentStyle::Tabs => f.write_str("Tabs"),
IndentStyle::Spaces(spaces) => f.write_fmt(format_args!("{spaces} spaces")),
}
}
}

impl IndentStyle {
pub const LONGEST_INDENT: &'static str = " "; // 8 spaces
pub const DEFAULT_INDENT: IndentStyle = IndentStyle::Spaces(4);
Expand Down
24 changes: 15 additions & 9 deletions examples/editor/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use floem::{
keyboard::{Key, ModifiersState, NamedKey},
reactive::RwSignal,
view::View,
views::{
editor::{
command::{Command, CommandExecuted},
core::{command::EditCommand, editor::EditType, selection::Selection},
text::SimpleStyling,
text::{default_dark_color, SimpleStyling},
},
stack, text_editor, Decorators,
},
Expand All @@ -18,25 +19,32 @@ fn app_view() -> impl View {
.map(|s| std::fs::read_to_string(s).unwrap());
let text = text.as_deref().unwrap_or("Hello world");

let editor_a = text_editor(text).styling(SimpleStyling::dark());
let hide_gutter_a = RwSignal::new(false);
let hide_gutter_b = RwSignal::new(true);

let editor_a = text_editor(text)
.styling(SimpleStyling::new())
.style(|s| s.size_full())
.editor_style(default_dark_color)
.editor_style(move |s| s.hide_gutter(hide_gutter_a.get()));
let editor_b = editor_a
.shared_editor()
.editor_style(default_dark_color)
.editor_style(move |s| s.hide_gutter(hide_gutter_b.get()))
.style(|s| s.size_full())
.pre_command(|ev| {
if matches!(ev.cmd, Command::Edit(EditCommand::Undo)) {
println!("Undo command executed on editor B, ignoring!");
return CommandExecuted::Yes;
}
CommandExecuted::No
})
.gutter(false)
.update(|_| {
// This hooks up to both editors!
println!("Editor changed");
})
.placeholder("Some placeholder text");
let doc = editor_a.doc();
let gutter_a = editor_a.editor().gutter;
let gutter_b = editor_b.editor().gutter;

let view = stack((
editor_a,
Expand All @@ -50,10 +58,8 @@ fn app_view() -> impl View {
);
}),
button(|| "Flip Gutter").on_click_stop(move |_| {
let a = !gutter_a.get_untracked();
let b = !gutter_b.get_untracked();
gutter_a.set(a);
gutter_b.set(b);
hide_gutter_a.update(|hide| *hide = !*hide);
hide_gutter_b.update(|hide| *hide = !*hide);
}),
))
.style(|s| s.width_full().flex_row().items_center().justify_center()),
Expand Down
35 changes: 11 additions & 24 deletions examples/syntax-editor/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use floem::cosmic_text::{Attrs, AttrsList, Stretch, Style, Weight};
use floem::peniko::Color;
use floem::views::editor::color::EditorColor;
use floem::reactive::RwSignal;
use floem::views::editor::core::buffer::rope_text::RopeText;
use floem::views::editor::core::indent::IndentStyle;
use floem::views::editor::id::EditorId;
use floem::views::editor::layout::TextLayoutLine;
use floem::views::editor::text::{Document, RenderWhitespace, SimpleStylingBuilder, Styling};
use floem::views::editor::text::{default_dark_color, Document, SimpleStylingBuilder, Styling};
use floem::{
cosmic_text::FamilyOwned,
keyboard::{Key, ModifiersState, NamedKey},
Expand Down Expand Up @@ -90,10 +89,6 @@ impl<'a> Styling for SyntaxHighlightingStyle<'a> {
self.style.stretch(edid, line)
}

fn indent_style(&self) -> IndentStyle {
self.style.indent_style()
}

fn indent_line(&self, edid: EditorId, line: usize, line_content: &str) -> usize {
self.style.indent_line(edid, line, line_content)
}
Expand Down Expand Up @@ -162,22 +157,10 @@ impl<'a> Styling for SyntaxHighlightingStyle<'a> {
}
}

fn wrap(&self, edid: EditorId) -> WrapMethod {
self.style.wrap(edid)
}

fn render_whitespace(&self, edid: EditorId) -> RenderWhitespace {
self.style.render_whitespace(edid)
}

fn apply_layout_styles(&self, edid: EditorId, line: usize, layout_line: &mut TextLayoutLine) {
self.style.apply_layout_styles(edid, line, layout_line)
}

fn color(&self, edid: EditorId, color: EditorColor) -> Color {
self.style.color(edid, color)
}

fn paint_caret(&self, edid: EditorId, line: usize) -> bool {
self.style.paint_caret(edid, line)
}
Expand All @@ -191,7 +174,7 @@ fn app_view() -> impl View {
FamilyOwned::Name("Consolas".to_string()),
FamilyOwned::Monospace,
])
.build_dark();
.build();

let mut style = SyntaxHighlightingStyle::new(Rc::new(global_style));

Expand Down Expand Up @@ -221,10 +204,15 @@ mod tests {
"#,
);

let hide_gutter = RwSignal::new(false);

style.set_doc(editor.doc().clone());
let editor = editor.styling(style);
let editor = editor
.styling(style)
.editor_style(default_dark_color)
.editor_style(move |s| s.hide_gutter(hide_gutter.get()))
.style(|s| s.size_full());

let gutter = editor.editor().gutter;
let doc = editor.doc();

let view = stack((
Expand All @@ -238,8 +226,7 @@ mod tests {
);
}),
button(|| "Gutter").on_click_stop(move |_| {
let a = !gutter.get_untracked();
gutter.set(a);
hide_gutter.update(|hide| *hide = !*hide);
}),
))
.style(|s| s.width_full().flex_row().items_center().justify_center()),
Expand Down
18 changes: 17 additions & 1 deletion src/inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::context::{AppState, StyleCx};
use crate::event::{Event, EventListener};
use crate::id::Id;
use crate::profiler::profiler;
use crate::style::{Style, StylePropRef, Transition};
use crate::style::{Style, StyleClassRef, StylePropRef, Transition};
use crate::view::{view_children, AnyView, View, Widget};
use crate::view_data::ChangeFlags;
use crate::views::{
Expand Down Expand Up @@ -38,6 +38,7 @@ pub struct CapturedView {
direct_style: Style,
requested_changes: ChangeFlags,
keyboard_navigable: bool,
classes: Vec<StyleClassRef>,
focused: bool,
}

Expand All @@ -52,6 +53,7 @@ impl CapturedView {
let state = app_state.view_state(id);
let clipped = layout.intersect(clip);
let custom_name = &view.view_data().debug_name;
let classes = state.classes.clone();
let name = custom_name
.iter()
.chain(std::iter::once(&view.debug_name().to_string()))
Expand All @@ -68,6 +70,7 @@ impl CapturedView {
requested_changes: state.requested_changes,
keyboard_navigable,
focused,
classes,
children: view_children(view)
.into_iter()
.map(|view| Rc::new(CapturedView::capture(view, app_state, clipped)))
Expand Down Expand Up @@ -529,6 +532,7 @@ fn selected_view(capture: &Rc<Capture>, selected: RwSignal<Option<Id>>) -> AnyVi
let clear = stack((clear,));

let style_header = header("View Style");
let class_header = header("Class Header");

let direct: HashSet<_> = view.direct_style.map.keys().copied().collect();

Expand All @@ -552,6 +556,16 @@ fn selected_view(capture: &Rc<Capture>, selected: RwSignal<Option<Id>>) -> AnyVi

style_list.sort_unstable_by(|a, b| a.0 .1.cmp(&b.0 .1));

let mut class_list = view
.classes
.clone()
.into_iter()
.map(|val| StylePropRef { key: val.key })
.map(|val| format!("{:?}", val.key))
.collect::<Vec<_>>();

class_list.sort_unstable();

let style_list =
v_stack_from_iter(style_list.into_iter().map(|((prop, name), value)| {
let name = name.strip_prefix("floem::style::").unwrap_or(&name);
Expand Down Expand Up @@ -631,6 +645,8 @@ fn selected_view(capture: &Rc<Capture>, selected: RwSignal<Option<Id>>) -> AnyVi
clear,
style_header,
style_list,
class_header,
v_stack_from_iter(class_list.iter().map(text)).style(|s| s.gap(10, 10)),
))
.style(|s| s.width_full())
.any()
Expand Down
9 changes: 5 additions & 4 deletions src/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub trait StylePropValue: Clone + PartialEq + Debug {
impl StylePropValue for i32 {}
impl StylePropValue for bool {}
impl StylePropValue for f32 {}
impl StylePropValue for usize {}
impl StylePropValue for f64 {
fn interpolate(&self, other: &Self, value: f64) -> Option<Self> {
Some(*self * (1.0 - value) + *other * value)
Expand Down Expand Up @@ -169,7 +170,7 @@ pub trait StyleClass: Default + Copy + 'static {
}
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct StyleClassInfo {
pub(crate) name: fn() -> &'static str,
}
Expand All @@ -182,7 +183,7 @@ impl StyleClassInfo {
}
}

#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub struct StyleClassRef {
pub key: StyleKey,
}
Expand Down Expand Up @@ -451,7 +452,7 @@ macro_rules! prop_extractor {
changed
}

#[allow(dead_code)]
#[allow(dead_code)]
$vis fn read(&mut self, cx: &mut $crate::context::StyleCx) -> bool {
let mut transition = false;
let changed = self.read_explicit(&cx.direct_style(), &cx.indirect_style(), &cx.now(), &mut transition);
Expand Down Expand Up @@ -612,7 +613,7 @@ impl StyleKey {
pub(crate) fn debug_any(&self, value: &dyn Any) -> String {
match self.info {
StyleKeyInfo::Selector(..) | StyleKeyInfo::Transition => String::new(),
StyleKeyInfo::Class(..) => String::new(),
StyleKeyInfo::Class(info) => (info.name)().to_string(),
StyleKeyInfo::Prop(v) => (v.debug_any)(value),
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/views/drag_resize_window_area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ impl Widget for DragResizeWindowArea {
fn view_data_mut(&mut self) -> &mut ViewData {
&mut self.data
}

fn debug_name(&self) -> std::borrow::Cow<'static, str> {
"Drag-Resize Window Area".into()
}

fn for_each_child<'a>(&'a self, for_each: &mut dyn FnMut(&'a dyn Widget) -> bool) {
for_each(&self.child);
}
Expand Down
4 changes: 4 additions & 0 deletions src/views/drag_window_area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ impl Widget for DragWindowArea {
&mut self.data
}

fn debug_name(&self) -> std::borrow::Cow<'static, str> {
"Drag Window Area".into()
}

fn for_each_child<'a>(&'a self, for_each: &mut dyn FnMut(&'a dyn Widget) -> bool) {
for_each(&self.child);
}
Expand Down
4 changes: 2 additions & 2 deletions src/views/editor/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ fn handle_edit_command_default(
action: &dyn CommonAction,
cmd: &EditCommand,
) -> CommandExecuted {
let modal = ed.modal.get_untracked();
let smart_tab = ed.smart_tab.get_untracked();
let modal = ed.es.with_untracked(|es| es.modal());
let smart_tab = ed.es.with_untracked(|es| es.smart_tab());
let mut cursor = ed.cursor.get_untracked();
let mut register = ed.register.get_untracked();

Expand Down
Loading

0 comments on commit 402c58c

Please sign in to comment.