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

text cursor blink in TextEdit #4121

Closed
wants to merge 73 commits into from
Closed
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
b553092
Update visuals.rs
rustbasic Mar 2, 2024
11e31ea
Update builder.rs
rustbasic Mar 2, 2024
8dd93b4
Update visuals.rs
rustbasic Mar 2, 2024
e56ad08
Update builder.rs
rustbasic Mar 2, 2024
c6a0fca
Update builder.rs
rustbasic Mar 2, 2024
61362e5
Update builder.rs
rustbasic Mar 2, 2024
53991c4
Update builder.rs
rustbasic Mar 2, 2024
ae48093
Update visuals.rs
rustbasic Mar 2, 2024
f534359
Update visuals.rs
rustbasic Mar 2, 2024
86e0910
Update visuals.rs
rustbasic Mar 2, 2024
f748437
Update builder.rs
rustbasic Mar 2, 2024
443e68b
Merge branch 'emilk:master' into patch19
rustbasic Mar 5, 2024
5a55d0b
Merge branch 'emilk:master' into patch19
rustbasic Mar 8, 2024
790609c
Merge branch 'emilk:master' into patch19
rustbasic Mar 11, 2024
183500b
Merge branch 'emilk:master' into patch19
rustbasic Mar 12, 2024
8d21de6
Merge branch 'emilk:master' into patch19
rustbasic Mar 13, 2024
6b76c1c
Update state.rs
rustbasic Mar 13, 2024
e20c05f
Update builder.rs
rustbasic Mar 13, 2024
ff68bd2
Update builder.rs
rustbasic Mar 13, 2024
7ce3353
Update builder.rs
rustbasic Mar 14, 2024
35704f7
Update state.rs
rustbasic Mar 14, 2024
ee4a20b
Update builder.rs
rustbasic Mar 14, 2024
691308b
Update builder.rs
rustbasic Mar 14, 2024
bc1e54a
Update builder.rs
rustbasic Mar 14, 2024
ea247ec
Update builder.rs
rustbasic Mar 14, 2024
ded8e31
Update builder.rs
rustbasic Mar 14, 2024
c813943
Update builder.rs
rustbasic Mar 14, 2024
3c8bc78
Merge branch 'emilk:master' into patch19
rustbasic Mar 14, 2024
8cbe04b
Merge branch 'emilk:master' into patch19
rustbasic Mar 15, 2024
037c4ac
Merge branch 'emilk:master' into patch19
rustbasic Mar 18, 2024
ce54c56
Update style.rs
rustbasic Mar 20, 2024
0b3c88e
Update builder.rs
rustbasic Mar 20, 2024
043ac3f
Merge branch 'emilk:master' into patch19
rustbasic Mar 20, 2024
782fd9d
Merge branch 'emilk:master' into patch19
rustbasic Mar 20, 2024
01675d1
Update style.rs
rustbasic Mar 21, 2024
d5fcd5c
Merge branch 'emilk:master' into patch19
rustbasic Mar 21, 2024
55a7c5e
Update style.rs
rustbasic Mar 21, 2024
ea89cf6
Update builder.rs
rustbasic Mar 21, 2024
79eb765
Update visuals.rs
rustbasic Mar 21, 2024
8faf0f5
Update builder.rs
rustbasic Mar 21, 2024
894fc2f
Update style.rs
rustbasic Mar 21, 2024
6ca5eeb
Update visuals.rs
rustbasic Mar 21, 2024
f231579
Update style.rs
rustbasic Mar 21, 2024
14ef3f4
Update style.rs
rustbasic Mar 21, 2024
f62a193
Update visuals.rs
rustbasic Mar 21, 2024
0ba726e
Update visuals.rs
rustbasic Mar 21, 2024
79dddbf
Update visuals.rs
rustbasic Mar 21, 2024
08daf51
Update visuals.rs
rustbasic Mar 21, 2024
875114f
Merge branch 'emilk:master' into patch19
rustbasic Mar 22, 2024
eb64586
Merge branch 'emilk:master' into patch19
rustbasic Mar 25, 2024
c293e19
Merge branch 'master' into patch19
rustbasic Mar 27, 2024
956b853
Merge branch 'master' into patch19
rustbasic Mar 28, 2024
135b88d
Update style.rs
rustbasic Mar 29, 2024
9505776
Update visuals.rs
rustbasic Mar 29, 2024
9ee6ca6
Update style.rs
rustbasic Mar 29, 2024
ec0f56a
Merge branch 'emilk:master' into patch19
rustbasic Mar 29, 2024
55467b3
Update style.rs
rustbasic Mar 29, 2024
a1a3d11
Update visuals.rs
rustbasic Mar 29, 2024
0681300
Update builder.rs
rustbasic Mar 29, 2024
de4fa6e
Update visuals.rs
rustbasic Mar 29, 2024
0b4ea7f
Update style.rs
rustbasic Mar 29, 2024
1600d32
Update input_state.rs
rustbasic Mar 29, 2024
fbabc24
Update visuals.rs
rustbasic Mar 29, 2024
a2eee07
Update builder.rs
rustbasic Mar 29, 2024
82d3814
Update builder.rs
rustbasic Mar 29, 2024
24e86d1
Update style.rs
rustbasic Mar 29, 2024
d098a8f
Update visuals.rs
rustbasic Mar 29, 2024
27098a1
Update builder.rs
rustbasic Mar 29, 2024
e50f80d
Update visuals.rs
rustbasic Mar 29, 2024
7dd8226
Update input_state.rs
rustbasic Mar 29, 2024
94f8424
Merge branch 'emilk:master' into patch19
rustbasic Mar 30, 2024
f101c92
Merge branch 'emilk:master' into patch19
rustbasic Mar 30, 2024
837c277
Merge branch 'emilk:master' into patch19
rustbasic Mar 30, 2024
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
31 changes: 28 additions & 3 deletions crates/egui/src/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,15 @@ pub struct Visuals {
/// show where the text cursor would be if you clicked
pub text_cursor_preview: bool,

/// set the text cursor to blink
pub text_cursor_blink: bool,

/// set the text cursor on duration
pub text_cursor_on_duration: f64,

/// set the text cursor off duration
pub text_cursor_off_duration: f64,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's time to group all these in a struct TextCursorStyle

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

…but I can do that in a later PR


/// Allow child widgets to be just on the border and still have a stroke with some thickness
pub clip_rect_margin: f32,

Expand Down Expand Up @@ -1097,6 +1106,10 @@ impl Visuals {
text_cursor: Stroke::new(2.0, Color32::from_rgb(192, 222, 255)),
text_cursor_preview: false,

text_cursor_blink: true,
text_cursor_on_duration: 1.0,
text_cursor_off_duration: 0.3,

clip_rect_margin: 3.0, // should be at least half the size of the widest frame stroke + max WidgetVisuals::expansion
button_frame: true,
collapsing_header_frame: false,
Expand Down Expand Up @@ -1581,10 +1594,10 @@ impl Interaction {
impl Widgets {
pub fn ui(&mut self, ui: &mut crate::Ui) {
let Self {
active,
hovered,
inactive,
noninteractive,
inactive,
hovered,
active,
open,
} = self;

Expand Down Expand Up @@ -1739,6 +1752,9 @@ impl Visuals {
resize_corner_size,
text_cursor,
text_cursor_preview,
text_cursor_blink,
text_cursor_on_duration,
text_cursor_off_duration,
clip_rect_margin,
button_frame,
collapsing_header_frame,
Expand Down Expand Up @@ -1846,6 +1862,15 @@ impl Visuals {
ui.checkbox(text_cursor_preview, "Preview text cursor on hover");
ui.add(Slider::new(clip_rect_margin, 0.0..=20.0).text("clip_rect_margin"));

ui.add(Slider::new(resize_corner_size, 0.0..=20.0).text("resize_corner_size"));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ui.add(Slider::new(resize_corner_size, 0.0..=20.0).text("resize_corner_size"));

ui.checkbox(text_cursor_preview, "Preview text cursor on hover");
ui.checkbox(text_cursor_blink, "text cursor to blink");
ui.add(Slider::new(text_cursor_on_duration, 0.0..=2.0).text("text cursor on duration"));
ui.add(
Slider::new(text_cursor_off_duration, 0.0..=2.0).text("text cursor off duration")
);
ui.add(Slider::new(clip_rect_margin, 0.0..=20.0).text("clip_rect_margin"));

ui.checkbox(button_frame, "Button has a frame");
ui.checkbox(collapsing_header_frame, "Collapsing header has a frame");
ui.checkbox(
Expand Down
41 changes: 41 additions & 0 deletions crates/egui/src/text_selection/visuals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,44 @@ pub fn paint_cursor(painter: &Painter, visuals: &Visuals, cursor_rect: Rect) {
);
}
}

/// Paint text cursor.
pub fn paint_text_cursor(
Comment on lines +77 to +78
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fn paint_text_cursor and fn paint_cursor have very similar names, but one does blinking, and one does not. We should document that. fn paint_cursor should probably be made non-pub too

ui: &mut Ui,
painter: &Painter,
primary_cursor_rect: Rect,
is_stay_cursor: bool,
) {
let i_time = ui.input(|i| i.time);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently the cursor still blinks while typing, which is quite annoying. If we instead reset a timer each time the user presses a key, it won't blink until text_cursor_on_duration after the user last stopped typing.

So, I think you were right to put this timer in TextEditState. We could put a last_edit_time: Option<f64> there fed by ui.input(|i| i.time), and then paint_text_cursor is fed with time_since_last_edit which will be used as the basis for the animation

let blink_mode = ui.visuals().text_cursor_blink;
let is_blink_mode = blink_mode && is_stay_cursor;

let on_duration = ui.visuals().text_cursor_on_duration;
let off_duration = ui.visuals().text_cursor_off_duration;
let total_duration = on_duration + off_duration;

let mut is_cursor_visible = true;

if is_blink_mode {
is_cursor_visible = (i_time % total_duration) < on_duration;
}

if is_cursor_visible {
paint_cursor(painter, ui.visuals(), primary_cursor_rect);
}

if is_blink_mode {
if is_cursor_visible {
ui.ctx()
.request_repaint_after(std::time::Duration::from_millis(
(on_duration * 1000.0) as u64,
));
}
if !is_cursor_visible {
ui.ctx()
.request_repaint_after(std::time::Duration::from_millis(
(off_duration * 1000.0) as u64,
));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.request_repaint_after(std::time::Duration::from_millis(
(on_duration * 1000.0) as u64,
));
}
if !is_cursor_visible {
ui.ctx()
.request_repaint_after(std::time::Duration::from_millis(
(off_duration * 1000.0) as u64,
));
.request_repaint_after(std::time::Duration::from_secs_f32(
on_duration
));
}
if !is_cursor_visible {
ui.ctx()
.request_repaint_after(std::time::Duration::from_secs_f32(
off_duration
));

}
}
}
11 changes: 9 additions & 2 deletions crates/egui/src/widgets/text_edit/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,7 @@ impl<'t> TextEdit<'t> {
}
});
let mut state = TextEditState::load(ui.ctx(), id).unwrap_or_default();
let save_ccursor_range = state.cursor.char_range();

// On touch screens (e.g. mobile in `eframe` web), should
// dragging select text, or scroll the enclosing [`ScrollArea`] (if any)?
Expand Down Expand Up @@ -558,7 +559,7 @@ impl<'t> TextEdit<'t> {
&& response.hovered()
&& ui.input(|i| i.pointer.is_moving())
{
// preview:
// text cursor preview:
let cursor_rect =
cursor_rect(response.rect.min, &galley, &cursor_at_pointer, row_height);
paint_cursor(&painter, ui.visuals(), cursor_rect);
Expand Down Expand Up @@ -694,7 +695,13 @@ impl<'t> TextEdit<'t> {
}

if text.is_mutable() {
paint_cursor(&painter, ui.visuals(), primary_cursor_rect);
let is_stay_cursor = save_ccursor_range == state.cursor.char_range();
text_selection::visuals::paint_text_cursor(
ui,
&painter,
primary_cursor_rect,
is_stay_cursor,
);

if interactive {
// For IME, so only set it when text is editable and visible!
Expand Down
Loading