mirror of
https://github.com/emilk/egui.git
synced 2026-08-30 13:20:05 -04:00
Make the "tab-as-character" behaviour opt-in.
Added `tab_moves_focus()` to `TextEdit` so we can opt-in to the "tab-as-character" behaviour. Also because we decided to lock the tab size to 4 spaces, we gave up on the `tab_size` property, but we kept the opt-in for the "tab-as-spaces" behaviour. An updated example of how to use `TextEdit` with those two opt-in behaviours can be found in the "Misc Demos" demo.
This commit is contained in:
@@ -190,6 +190,7 @@ impl Focus {
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
self.id = None;
|
self.id = None;
|
||||||
|
self.is_focus_locked = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,9 +294,17 @@ impl Memory {
|
|||||||
self.interaction.focus.id == Some(id)
|
self.interaction.focus.id == Some(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn lock_focus(&mut self, id: Id) {
|
pub(crate) fn lock_focus(&mut self, id: Id, b: bool) {
|
||||||
if self.had_focus_last_frame(id) && self.has_focus(id) {
|
if self.had_focus_last_frame(id) && self.has_focus(id) {
|
||||||
self.interaction.focus.is_focus_locked = true;
|
self.interaction.focus.is_focus_locked = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn has_lock_focus(&mut self, id: Id) -> bool {
|
||||||
|
if self.had_focus_last_frame(id) && self.has_focus(id) {
|
||||||
|
self.interaction.focus.is_focus_locked
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ pub struct TextEdit<'t> {
|
|||||||
desired_width: Option<f32>,
|
desired_width: Option<f32>,
|
||||||
desired_height_rows: usize,
|
desired_height_rows: usize,
|
||||||
tab_as_spaces: bool,
|
tab_as_spaces: bool,
|
||||||
tab_size: usize,
|
tab_moves_focus: bool,
|
||||||
}
|
}
|
||||||
impl<'t> TextEdit<'t> {
|
impl<'t> TextEdit<'t> {
|
||||||
pub fn cursor(ui: &Ui, id: Id) -> Option<CursorPair> {
|
pub fn cursor(ui: &Ui, id: Id) -> Option<CursorPair> {
|
||||||
@@ -167,8 +167,8 @@ impl<'t> TextEdit<'t> {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
desired_width: None,
|
desired_width: None,
|
||||||
desired_height_rows: 1,
|
desired_height_rows: 1,
|
||||||
tab_as_spaces: true,
|
tab_as_spaces: false,
|
||||||
tab_size: 4,
|
tab_moves_focus: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,8 +186,8 @@ impl<'t> TextEdit<'t> {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
desired_width: None,
|
desired_width: None,
|
||||||
desired_height_rows: 4,
|
desired_height_rows: 4,
|
||||||
tab_as_spaces: true,
|
tab_as_spaces: false,
|
||||||
tab_size: 4,
|
tab_moves_focus: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,14 +202,18 @@ impl<'t> TextEdit<'t> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers if this widget will insert spaces instead of tab char
|
/// When this is true, then pass focus to the next
|
||||||
|
/// widget.
|
||||||
|
///
|
||||||
|
/// When this is false, then insert identation based on the value of
|
||||||
|
/// `tab_as_spaces` property.
|
||||||
///
|
///
|
||||||
/// ```rust, ignore
|
/// ```rust, ignore
|
||||||
/// ui.add(egui::TextEdit::multiline(&mut self.multiline_text_input)
|
/// ui.add(egui::TextEdit::multiline(&mut self.multiline_text_input)
|
||||||
/// .tab_size(4));
|
/// .tab_moves_focus(true));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn tab_size(mut self, size: usize) -> Self {
|
pub fn tab_moves_focus(mut self, b: bool) -> Self {
|
||||||
self.tab_size = size;
|
self.tab_moves_focus = b;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,7 +330,7 @@ impl<'t> TextEdit<'t> {
|
|||||||
desired_width,
|
desired_width,
|
||||||
desired_height_rows,
|
desired_height_rows,
|
||||||
tab_as_spaces,
|
tab_as_spaces,
|
||||||
tab_size,
|
tab_moves_focus,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let text_style = text_style.unwrap_or_else(|| ui.style().body_text_style);
|
let text_style = text_style.unwrap_or_else(|| ui.style().body_text_style);
|
||||||
@@ -413,9 +417,7 @@ impl<'t> TextEdit<'t> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ui.memory().has_focus(id) && enabled {
|
if ui.memory().has_focus(id) && enabled {
|
||||||
if multiline {
|
ui.memory().lock_focus(id, !tab_moves_focus);
|
||||||
ui.memory().lock_focus(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut cursorp = state
|
let mut cursorp = state
|
||||||
.cursorp
|
.cursorp
|
||||||
@@ -481,16 +483,12 @@ impl<'t> TextEdit<'t> {
|
|||||||
if multiline {
|
if multiline {
|
||||||
let mut ccursor = delete_selected(text, &cursorp);
|
let mut ccursor = delete_selected(text, &cursorp);
|
||||||
|
|
||||||
if tab_as_spaces {
|
if ui.memory().has_lock_focus(id) {
|
||||||
let mut spaces = String::with_capacity(tab_size);
|
if tab_as_spaces {
|
||||||
|
insert_text(&mut ccursor, text, " ");
|
||||||
for _ in 0..tab_size {
|
} else {
|
||||||
spaces.push(' ');
|
insert_text(&mut ccursor, text, "\t");
|
||||||
}
|
}
|
||||||
|
|
||||||
insert_text(&mut ccursor, text, &spaces);
|
|
||||||
} else {
|
|
||||||
insert_text(&mut ccursor, text, "\t");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(CCursorPair::one(ccursor))
|
Some(CCursorPair::one(ccursor))
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ pub struct Widgets {
|
|||||||
single_line_text_input: String,
|
single_line_text_input: String,
|
||||||
tab_size: usize,
|
tab_size: usize,
|
||||||
tab_as_spaces: bool,
|
tab_as_spaces: bool,
|
||||||
|
tab_moves_focus: bool,
|
||||||
multiline_text_input: String,
|
multiline_text_input: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +41,7 @@ impl Default for Widgets {
|
|||||||
|
|
||||||
tab_size: 4,
|
tab_size: 4,
|
||||||
tab_as_spaces: true,
|
tab_as_spaces: true,
|
||||||
|
tab_moves_focus: false,
|
||||||
multiline_text_input: r#"Text can both be so wide that it needs a line break, but you can also add manual line break by pressing enter, creating new paragraphs.
|
multiline_text_input: r#"Text can both be so wide that it needs a line break, but you can also add manual line break by pressing enter, creating new paragraphs.
|
||||||
This is the start of the next paragraph.
|
This is the start of the next paragraph.
|
||||||
|
|
||||||
@@ -149,17 +151,14 @@ impl Widgets {
|
|||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
ui.add(egui::Slider::usize(&mut self.tab_size, 2..=8).text("Tab size"));
|
|
||||||
|
|
||||||
ui.separator();
|
|
||||||
|
|
||||||
ui.checkbox(&mut self.tab_as_spaces, "Tabs as spaces");
|
ui.checkbox(&mut self.tab_as_spaces, "Tabs as spaces");
|
||||||
|
ui.checkbox(&mut self.tab_moves_focus, "Tabs moves focus");
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.add(
|
ui.add(
|
||||||
egui::TextEdit::multiline(&mut self.multiline_text_input)
|
egui::TextEdit::multiline(&mut self.multiline_text_input)
|
||||||
.tab_as_spaces(self.tab_as_spaces)
|
.tab_moves_focus(self.tab_moves_focus)
|
||||||
.tab_size(self.tab_size),
|
.tab_as_spaces(self.tab_as_spaces),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user