Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TextEditor widget (or multi-line text input) #2123

Merged
merged 70 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from 69 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
346af3f
Make `FontSystem` global and simplify `Paragraph` API
hecrj Sep 11, 2023
6448429
Draft `Editor` API and `TextEditor` widget
hecrj Sep 12, 2023
1455911
Add `Enter` variant to `Action` in `text::Editor`
hecrj Sep 12, 2023
abab144
Return `Cursor::Caret` if selection matches cursor position in `Edito…
hecrj Sep 12, 2023
4389ab9
Fix cursor offset with `Affinity::After` at the end of lines in `Edit…
hecrj Sep 12, 2023
a28ed82
Fix subline positioning in `Editor::cursor`
hecrj Sep 12, 2023
40eb648
Implement `Cursor::Selection` calculation in `Editor::cursor`
hecrj Sep 13, 2023
d502c9f
Unify `Focus` and `Click` updates in `widget::text_editor`
hecrj Sep 13, 2023
52b36a9
Use `Theme::Dark` in `editor` example
hecrj Sep 13, 2023
f4c51a9
Introduce `Motion` concept in `core::text::editor`
hecrj Sep 13, 2023
f14ef7a
Fix `clippy` lints
hecrj Sep 13, 2023
c829b4b
Fix unused import in `iced_renderer`
hecrj Sep 13, 2023
ab02038
Fix scrolling offset for `Cursor::Selection`
hecrj Sep 13, 2023
e6c2db8
Fix `Cursor::Caret` position on lines that wrap on whitespace
hecrj Sep 13, 2023
b24b94d
Handle motions when a selection is present in `text::Editor`
hecrj Sep 14, 2023
edd5918
Implement motion selection in `text::Editor`
hecrj Sep 14, 2023
f7d6689
Implement `Action::SelectWord` in `text::Editor`
hecrj Sep 14, 2023
8cad1d6
Implement `Action::SelectLine` in `text::Editor`
hecrj Sep 14, 2023
c7d02e2
Remove `Editor::min_bounds` and use `bounds` instead
hecrj Sep 14, 2023
3afac11
Remove `min_bounds` field in `graphics::text::Editor`
hecrj Sep 14, 2023
8e6e37e
Fix broken intra-doc links
hecrj Sep 14, 2023
f7fc13d
Fix `Copy` action being triggered without any modifiers
hecrj Sep 14, 2023
c6d0443
Implement methods to query the contents of a `TextEditor`
hecrj Sep 16, 2023
d051f21
Implement `Copy` and `Paste` actions for `text::Editor`
hecrj Sep 16, 2023
c9dbccb
Use fork of `cosmic-text` with some minor fixes
hecrj Sep 16, 2023
45c5cfe
Avoid drag on double or triple click for now in `TextEditor`
hecrj Sep 16, 2023
723111b
Remove unnecessary `into_iter` call in `graphics::text`
hecrj Sep 16, 2023
76dc82e
Draft `Highlighter` API
hecrj Sep 17, 2023
d301199
Implement basic syntax highlighting with `syntect` in `editor` example
hecrj Sep 17, 2023
23d0044
Use `saturating_sub` for `last_visible_line` in `text::Editor`
hecrj Sep 17, 2023
2897986
Notify `Highlighter` of topmost line change
hecrj Sep 17, 2023
790c0da
Implement syntax highlighting cache in `editor` example
hecrj Sep 17, 2023
86d396c
Avoid adding unnecessary spans when syntax highlighting
hecrj Sep 17, 2023
8f8528a
Fix unnecessary dereference in `editor` example
hecrj Sep 17, 2023
d1440ce
Find correct `last_visible_line` in `Editor::highlight`
hecrj Sep 18, 2023
a01b123
Shape as needed only in `update` during `layout`
hecrj Sep 18, 2023
b5466f4
Fix inconsistent `expect` messages in `text::editor`
hecrj Sep 18, 2023
61ef8f3
Update `version` properly when `FontSystem` changes in `text::editor`
hecrj Sep 18, 2023
8446fe6
Implement theme selector in `editor` example
hecrj Sep 18, 2023
e7326f0
Flesh out the `editor` example a bit more
hecrj Sep 18, 2023
161a971
Fix `clippy` lints
hecrj Sep 18, 2023
8eec003
Remove unnecessary `monospaced` flag in `Font`
hecrj Sep 18, 2023
d1d0b3a
Use `Font::MONOSPACE` in `editor` example
hecrj Sep 18, 2023
36e867d
Fix `lint` and `test` GitHub CI workflows
hecrj Sep 18, 2023
4e757a2
Implement `Scroll` action in `text::editor`
hecrj Sep 18, 2023
06dc12b
Simplify `editor` example
hecrj Sep 19, 2023
c0a141a
Save file on `Cmd+S` in `editor` example
hecrj Sep 19, 2023
f806d00
Introduce new `iced_highlighter` subcrate
hecrj Sep 19, 2023
77db169
Fix typo in `higlighter` (why is it so hard to spell?)
hecrj Sep 19, 2023
0166744
Add `iced_highlighter` to `document` workflow
hecrj Sep 19, 2023
d9fbecf
Remove `syntect` dependency from `editor` example
hecrj Sep 19, 2023
a9ee8f6
Reuse syntaxes and themes lazily in `iced_highlighter`
hecrj Sep 19, 2023
9af0a27
Draw colored glyphs in `iced_tiny_skia`
hecrj Sep 19, 2023
be340a8
Fix gamma correction for colored glyphs in `iced_wgpu`
hecrj Sep 19, 2023
93d6f74
Fix `clippy` lints in `iced_highlighter`
hecrj Sep 19, 2023
ff78e97
Introduce more themes to `iced_highlighter`
hecrj Sep 19, 2023
29fb4ea
Scroll `TextEditor` only if `cursor.is_over(bounds)`
hecrj Sep 19, 2023
25d47c3
Remove `rangemap` patch in `Cargo.toml`
hecrj Sep 21, 2023
da5dd25
Round `ScrollDelta::Lines` in `TextEditor`
hecrj Sep 21, 2023
7373dd8
Scroll at least one line on macOS in `TextEditor`
hecrj Sep 21, 2023
68d4945
Fix vertical scroll for `TextEditor`
hecrj Sep 21, 2023
70e49df
Fix selection clipping out of bounds in `TextEditor`
hecrj Sep 22, 2023
af21cf8
Remove `patch.crates-io` section for `cosmic-text` in `Cargo.toml`
hecrj Sep 22, 2023
8cc19de
Add `text` helper method for `text_editor::Content`
hecrj Sep 22, 2023
6582387
Merge branch 'master' into text-editor
hecrj Oct 27, 2023
625cd74
Write documentation for the new text APIs
hecrj Oct 27, 2023
e579d85
Implement missing debug implementations in `iced_widget`
hecrj Oct 27, 2023
57f9024
Fix intra-doc broken links
hecrj Oct 27, 2023
1b534bd
Merge branch 'master' into text-editor
hecrj Oct 27, 2023
c8eca4e
Improve `TextEditor` scroll interaction with a touchpad
hecrj Oct 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ clippy --workspace --no-deps -- \
-D clippy::useless_conversion
"""

#![allow(clippy::inherent_to_string, clippy::type_complexity)]

nitpick = """
clippy --workspace --no-deps -- \
-D warnings \
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/document.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ jobs:
RUSTDOCFLAGS="--cfg docsrs" \
cargo doc --no-deps --all-features \
-p iced_core \
-p iced_highlighter \
-p iced_style \
-p iced_futures \
-p iced_runtime \
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Lint
on: [push, pull_request]
jobs:
all:
runs-on: ubuntu-latest
runs-on: macOS-latest
steps:
- uses: hecrj/setup-rust-action@v1
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
run: |
export DEBIAN_FRONTED=noninteractive
sudo apt-get -qq update
sudo apt-get install -y libxkbcommon-dev
sudo apt-get install -y libxkbcommon-dev libgtk-3-dev
- name: Run tests
run: |
cargo test --verbose --workspace
Expand Down
10 changes: 9 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ system = ["iced_winit/system"]
web-colors = ["iced_renderer/web-colors"]
# Enables the WebGL backend, replacing WebGPU
webgl = ["iced_renderer/webgl"]
# Enables the syntax `highlighter` module
highlighter = ["iced_highlighter"]
# Enables the advanced module
advanced = []

Expand All @@ -58,6 +60,9 @@ iced_widget.workspace = true
iced_winit.features = ["application"]
iced_winit.workspace = true

iced_highlighter.workspace = true
iced_highlighter.optional = true

thiserror.workspace = true

image.workspace = true
Expand All @@ -78,8 +83,9 @@ members = [
"core",
"futures",
"graphics",
"runtime",
"highlighter",
"renderer",
"runtime",
"style",
"tiny_skia",
"wgpu",
Expand All @@ -103,6 +109,7 @@ iced = { version = "0.12", path = "." }
iced_core = { version = "0.12", path = "core" }
iced_futures = { version = "0.12", path = "futures" }
iced_graphics = { version = "0.12", path = "graphics" }
iced_highlighter = { version = "0.12", path = "highlighter" }
iced_renderer = { version = "0.12", path = "renderer" }
iced_runtime = { version = "0.12", path = "runtime" }
iced_style = { version = "0.12", path = "style" }
Expand Down Expand Up @@ -137,6 +144,7 @@ resvg = "0.35"
rustc-hash = "1.0"
smol = "1.0"
softbuffer = "0.2"
syntect = "5.1"
sysinfo = "0.28"
thiserror = "1.0"
tiny-skia = "0.10"
Expand Down
20 changes: 20 additions & 0 deletions core/src/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,26 @@ impl Color {
}
}

/// Creates a [`Color`] from its linear RGBA components.
pub fn from_linear_rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
// As described in:
// https://en.wikipedia.org/wiki/SRGB
fn gamma_component(u: f32) -> f32 {
if u < 0.0031308 {
12.92 * u
} else {
1.055 * u.powf(1.0 / 2.4) - 0.055
}
}

Self {
r: gamma_component(r),
g: gamma_component(g),
b: gamma_component(b),
a,
}
}

/// Converts the [`Color`] into its RGBA8 equivalent.
#[must_use]
pub fn into_rgba8(self) -> [u8; 4] {
Expand Down
4 changes: 0 additions & 4 deletions core/src/font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ pub struct Font {
pub stretch: Stretch,
/// The [`Style`] of the [`Font`].
pub style: Style,
/// Whether if the [`Font`] is monospaced or not.
pub monospaced: bool,
}

impl Font {
Expand All @@ -23,13 +21,11 @@ impl Font {
weight: Weight::Normal,
stretch: Stretch::Normal,
style: Style::Normal,
monospaced: false,
};

/// A monospaced font with normal [`Weight`].
pub const MONOSPACE: Font = Font {
family: Family::Monospace,
monospaced: true,
..Self::DEFAULT
};

Expand Down
2 changes: 1 addition & 1 deletion core/src/layout/limits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use crate::{Length, Padding, Size};

/// A set of size constraints for layouting.
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Limits {
min: Size,
max: Size,
Expand Down
5 changes: 5 additions & 0 deletions core/src/mouse/click.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ impl Click {
self.kind
}

/// Returns the position of the [`Click`].
pub fn position(&self) -> Point {
self.position
}

fn is_consecutive(&self, new_position: Point, time: Instant) -> bool {
let duration = if time > self.time {
Some(time - self.time)
Expand Down
91 changes: 63 additions & 28 deletions core/src/renderer/null.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ impl Renderer for Null {
impl text::Renderer for Null {
type Font = Font;
type Paragraph = ();
type Editor = ();

const ICON_FONT: Font = Font::DEFAULT;
const CHECKMARK_ICON: char = '0';
Expand All @@ -58,19 +59,17 @@ impl text::Renderer for Null {

fn load_font(&mut self, _font: Cow<'static, [u8]>) {}

fn create_paragraph(&self, _text: Text<'_, Self::Font>) -> Self::Paragraph {
}

fn resize_paragraph(
&self,
_paragraph: &mut Self::Paragraph,
_new_bounds: Size,
fn fill_paragraph(
&mut self,
_paragraph: &Self::Paragraph,
_position: Point,
_color: Color,
) {
}

fn fill_paragraph(
fn fill_editor(
&mut self,
_paragraph: &Self::Paragraph,
_editor: &Self::Editor,
_position: Point,
_color: Color,
) {
Expand All @@ -88,47 +87,83 @@ impl text::Renderer for Null {
impl text::Paragraph for () {
type Font = Font;

fn content(&self) -> &str {
""
fn with_text(_text: Text<'_, Self::Font>) -> Self {}

fn resize(&mut self, _new_bounds: Size) {}

fn compare(&self, _text: Text<'_, Self::Font>) -> text::Difference {
text::Difference::None
}

fn text_size(&self) -> Pixels {
Pixels(16.0)
fn horizontal_alignment(&self) -> alignment::Horizontal {
alignment::Horizontal::Left
}

fn font(&self) -> Self::Font {
Font::default()
fn vertical_alignment(&self) -> alignment::Vertical {
alignment::Vertical::Top
}

fn line_height(&self) -> text::LineHeight {
text::LineHeight::default()
fn grapheme_position(&self, _line: usize, _index: usize) -> Option<Point> {
None
}

fn shaping(&self) -> text::Shaping {
text::Shaping::default()
fn min_bounds(&self) -> Size {
Size::ZERO
}

fn horizontal_alignment(&self) -> alignment::Horizontal {
alignment::Horizontal::Left
fn hit_test(&self, _point: Point) -> Option<text::Hit> {
None
}
}

fn vertical_alignment(&self) -> alignment::Vertical {
alignment::Vertical::Top
impl text::Editor for () {
type Font = Font;

fn with_text(_text: &str) -> Self {}

fn cursor(&self) -> text::editor::Cursor {
text::editor::Cursor::Caret(Point::ORIGIN)
}

fn grapheme_position(&self, _line: usize, _index: usize) -> Option<Point> {
fn cursor_position(&self) -> (usize, usize) {
(0, 0)
}

fn selection(&self) -> Option<String> {
None
}

fn line(&self, _index: usize) -> Option<&str> {
None
}

fn line_count(&self) -> usize {
0
}

fn perform(&mut self, _action: text::editor::Action) {}

fn bounds(&self) -> Size {
Size::ZERO
}

fn min_bounds(&self) -> Size {
Size::ZERO
fn update(
&mut self,
_new_bounds: Size,
_new_font: Self::Font,
_new_size: Pixels,
_new_line_height: text::LineHeight,
_new_highlighter: &mut impl text::Highlighter,
) {
}

fn hit_test(&self, _point: Point) -> Option<text::Hit> {
None
fn highlight<H: text::Highlighter>(
&mut self,
_font: Self::Font,
_highlighter: &mut H,
_format_highlight: impl Fn(
&H::Highlight,
) -> text::highlighter::Format<Self::Font>,
) {
}
}
Loading
Loading