mirror of
https://github.com/emilk/egui.git
synced 2026-08-29 04:40:03 -04:00
Add StyleProvider support for TextEdit, and classes for DragValue
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
use emath::Vec2;
|
use emath::Vec2;
|
||||||
use epaint::{Shadow, Stroke, text::TextWrapMode};
|
use epaint::{Color32, Margin, Shadow, Stroke, text::TextWrapMode};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Frame, TextStyle,
|
Frame, TextStyle,
|
||||||
theme::StyleProvider,
|
theme::StyleProvider,
|
||||||
widget_style::{
|
widget_style::{
|
||||||
BaseStyle, ButtonStyle, CheckboxStyle, HasClasses as _, LabelStyle, SELECTED_CLASS,
|
BaseStyle, ButtonStyle, CheckboxStyle, HasClasses as _, LabelStyle, READ_ONLY_CLASS,
|
||||||
SeparatorStyle, StyleArgs, TextVisuals, WidgetState,
|
SELECTED_CLASS, SeparatorStyle, StyleArgs, TextEditStyle, TextVisuals, WidgetState,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -92,6 +92,61 @@ impl StyleProvider<ButtonStyle> for DefaultStyle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StyleProvider<TextEditStyle> for DefaultStyle {
|
||||||
|
fn style(&mut self, modifiers: &StyleArgs<'_>) -> TextEditStyle {
|
||||||
|
let StyleArgs {
|
||||||
|
ctx,
|
||||||
|
classes,
|
||||||
|
style,
|
||||||
|
state,
|
||||||
|
..
|
||||||
|
} = modifiers;
|
||||||
|
|
||||||
|
let widget_visuals = match state {
|
||||||
|
WidgetState::Noninteractive => style.visuals.widgets.noninteractive,
|
||||||
|
WidgetState::Inactive => style.visuals.widgets.inactive,
|
||||||
|
WidgetState::Hovered => style.visuals.widgets.hovered,
|
||||||
|
WidgetState::Active => style.visuals.widgets.active,
|
||||||
|
};
|
||||||
|
|
||||||
|
// A text edit over an immutable buffer is painted without a background.
|
||||||
|
let (fill, stroke) = if classes.has(READ_ONLY_CLASS) {
|
||||||
|
let visuals = &style.visuals.widgets.inactive;
|
||||||
|
(Color32::TRANSPARENT, visuals.bg_stroke)
|
||||||
|
} else if *state == WidgetState::Active {
|
||||||
|
// While focused, the frame is outlined in the selection color.
|
||||||
|
(
|
||||||
|
style.visuals.text_edit_bg_color(),
|
||||||
|
style.visuals.selection.stroke,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(style.visuals.text_edit_bg_color(), widget_visuals.bg_stroke)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut ws: BaseStyle = ctx.get_widget_style(modifiers);
|
||||||
|
|
||||||
|
// The text of a text edit doesn't brighten on hover — that would be distracting while
|
||||||
|
// typing — so it keeps the inactive color no matter the state.
|
||||||
|
ws.text.color = style.visuals.widgets.inactive.text_color();
|
||||||
|
|
||||||
|
TextEditStyle {
|
||||||
|
frame: Frame {
|
||||||
|
fill,
|
||||||
|
stroke,
|
||||||
|
corner_radius: widget_visuals.corner_radius,
|
||||||
|
// The stroke is painted centered on the frame edge, so half of it eats into the
|
||||||
|
// padding; compensate, like the other widgets do.
|
||||||
|
inner_margin: Margin::symmetric(4, 2)
|
||||||
|
+ Margin::same((widget_visuals.expansion - stroke.width).round() as i8),
|
||||||
|
outer_margin: Margin::same(-(widget_visuals.expansion as i8)),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
text: ws.text,
|
||||||
|
hint_text_color: style.visuals.weak_text_color(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl StyleProvider<CheckboxStyle> for DefaultStyle {
|
impl StyleProvider<CheckboxStyle> for DefaultStyle {
|
||||||
fn style(&mut self, modifiers: &StyleArgs<'_>) -> CheckboxStyle {
|
fn style(&mut self, modifiers: &StyleArgs<'_>) -> CheckboxStyle {
|
||||||
let StyleArgs {
|
let StyleArgs {
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ use crate::{
|
|||||||
theme::{StyleProvider, default_style::DefaultStyle},
|
theme::{StyleProvider, default_style::DefaultStyle},
|
||||||
util::IdTypeMap,
|
util::IdTypeMap,
|
||||||
widget_style::{
|
widget_style::{
|
||||||
BaseStyle, ButtonStyle, CheckboxStyle, LabelStyle, SeparatorStyle, WidgetStyle,
|
BaseStyle, ButtonStyle, CheckboxStyle, LabelStyle, SeparatorStyle, TextEditStyle,
|
||||||
|
WidgetStyle,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -51,6 +52,11 @@ impl Default for Themes {
|
|||||||
Arc::new(Mutex::new(Box::new(DefaultStyle))),
|
Arc::new(Mutex::new(Box::new(DefaultStyle))),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
themes.insert_temp::<ThemeWrap<TextEditStyle>>(
|
||||||
|
Id::NULL,
|
||||||
|
Arc::new(Mutex::new(Box::new(DefaultStyle))),
|
||||||
|
);
|
||||||
|
|
||||||
themes.insert_temp::<ThemeWrap<LabelStyle>>(
|
themes.insert_temp::<ThemeWrap<LabelStyle>>(
|
||||||
Id::NULL,
|
Id::NULL,
|
||||||
Arc::new(Mutex::new(Box::new(DefaultStyle))),
|
Arc::new(Mutex::new(Box::new(DefaultStyle))),
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ pub const ROOT_CLASS: &str = "root";
|
|||||||
/// The selected class is a special class present on selected [`crate::Button`].
|
/// The selected class is a special class present on selected [`crate::Button`].
|
||||||
pub const SELECTED_CLASS: &str = "selected";
|
pub const SELECTED_CLASS: &str = "selected";
|
||||||
|
|
||||||
|
/// The read-only class is present on a [`crate::TextEdit`] whose buffer can't be edited.
|
||||||
|
pub const READ_ONLY_CLASS: &str = "read-only";
|
||||||
|
|
||||||
/// A class is a static string identifier.
|
/// A class is a static string identifier.
|
||||||
pub type ClassName = Cow<'static, str>;
|
pub type ClassName = Cow<'static, str>;
|
||||||
|
|
||||||
@@ -67,6 +70,18 @@ pub trait HasClasses {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add all the given classes by consuming `self`
|
||||||
|
///
|
||||||
|
/// Useful to forward the classes of a composite widget to the widgets it is built from.
|
||||||
|
#[inline]
|
||||||
|
fn with_classes(mut self, classes: Classes) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.classes_mut().classes.extend(classes.classes);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Add the given class by consuming `self` if the condition is true
|
/// Add the given class by consuming `self` if the condition is true
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_class_if(mut self, class: impl Into<ClassName>, condition: bool) -> Self
|
fn with_class_if(mut self, class: impl Into<ClassName>, condition: bool) -> Self
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
|
|
||||||
mod classes;
|
mod classes;
|
||||||
|
|
||||||
pub use self::classes::{ClassName, Classes, HasClasses, ROOT_CLASS, SELECTED_CLASS};
|
pub use self::classes::{
|
||||||
|
ClassName, Classes, HasClasses, READ_ONLY_CLASS, ROOT_CLASS, SELECTED_CLASS,
|
||||||
|
};
|
||||||
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
|
||||||
@@ -53,6 +55,21 @@ pub struct ButtonStyle {
|
|||||||
|
|
||||||
impl WidgetStyle for ButtonStyle {}
|
impl WidgetStyle for ButtonStyle {}
|
||||||
|
|
||||||
|
/// Dedicated text edit style
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TextEditStyle {
|
||||||
|
/// Frame around the text, including its padding.
|
||||||
|
pub frame: Frame,
|
||||||
|
|
||||||
|
/// The text being edited.
|
||||||
|
pub text: TextVisuals,
|
||||||
|
|
||||||
|
/// The color of the hint text shown while the buffer is empty.
|
||||||
|
pub hint_text_color: Color32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetStyle for TextEditStyle {}
|
||||||
|
|
||||||
/// Dedicated checkbox style
|
/// Dedicated checkbox style
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CheckboxStyle {
|
pub struct CheckboxStyle {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::{
|
|||||||
Atom, AtomExt as _, AtomKind, Atoms, Button, CursorIcon, Id, IntoAtoms, Key, MINUS_CHAR_STR,
|
Atom, AtomExt as _, AtomKind, Atoms, Button, CursorIcon, Id, IntoAtoms, Key, MINUS_CHAR_STR,
|
||||||
Modifiers, NumExt as _, Response, RichText, Sense, TextEdit, TextWrapMode, Ui, Widget,
|
Modifiers, NumExt as _, Response, RichText, Sense, TextEdit, TextWrapMode, Ui, Widget,
|
||||||
WidgetInfo, emath, text,
|
WidgetInfo, emath, text,
|
||||||
|
widget_style::{Classes, HasClasses},
|
||||||
};
|
};
|
||||||
use core::{cmp::Ordering, ops::RangeInclusive};
|
use core::{cmp::Ordering, ops::RangeInclusive};
|
||||||
use emath::Vec2;
|
use emath::Vec2;
|
||||||
@@ -63,6 +64,7 @@ pub struct DragValue<'a> {
|
|||||||
custom_formatter: Option<NumFormatter<'a>>,
|
custom_formatter: Option<NumFormatter<'a>>,
|
||||||
custom_parser: Option<NumParser<'a>>,
|
custom_parser: Option<NumParser<'a>>,
|
||||||
update_while_editing: bool,
|
update_while_editing: bool,
|
||||||
|
classes: Classes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DragValue<'a> {
|
impl<'a> DragValue<'a> {
|
||||||
@@ -97,6 +99,7 @@ impl<'a> DragValue<'a> {
|
|||||||
custom_formatter: None,
|
custom_formatter: None,
|
||||||
custom_parser: None,
|
custom_parser: None,
|
||||||
update_while_editing: true,
|
update_while_editing: true,
|
||||||
|
classes: Classes::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,6 +452,7 @@ impl Widget for DragValue<'_> {
|
|||||||
custom_formatter,
|
custom_formatter,
|
||||||
custom_parser,
|
custom_parser,
|
||||||
update_while_editing,
|
update_while_editing,
|
||||||
|
classes,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let mut prefix_text = String::new();
|
let mut prefix_text = String::new();
|
||||||
@@ -583,6 +587,7 @@ impl Widget for DragValue<'_> {
|
|||||||
.map_or_else(|| value_text.clone(), |edit_state| edit_state.text);
|
.map_or_else(|| value_text.clone(), |edit_state| edit_state.text);
|
||||||
let response = ui.add(
|
let response = ui.add(
|
||||||
TextEdit::singleline(&mut value_text)
|
TextEdit::singleline(&mut value_text)
|
||||||
|
.with_classes(classes)
|
||||||
.clip_text(false)
|
.clip_text(false)
|
||||||
.horizontal_align(ui.layout().horizontal_align())
|
.horizontal_align(ui.layout().horizontal_align())
|
||||||
.vertical_align(ui.layout().vertical_align())
|
.vertical_align(ui.layout().vertical_align())
|
||||||
@@ -634,6 +639,7 @@ impl Widget for DragValue<'_> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
let button = Button::new(atoms)
|
let button = Button::new(atoms)
|
||||||
|
.with_classes(classes)
|
||||||
.wrap_mode(TextWrapMode::Extend)
|
.wrap_mode(TextWrapMode::Extend)
|
||||||
.sense(Sense::click_and_drag())
|
.sense(Sense::click_and_drag())
|
||||||
.gap(0.0)
|
.gap(0.0)
|
||||||
@@ -864,3 +870,13 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl HasClasses for DragValue<'_> {
|
||||||
|
fn classes(&self) -> &Classes {
|
||||||
|
&self.classes
|
||||||
|
}
|
||||||
|
|
||||||
|
fn classes_mut(&mut self) -> &mut Classes {
|
||||||
|
&mut self.classes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ use crate::{
|
|||||||
self, CCursorRange, text_cursor_state::cursor_rect, visuals::paint_text_selection,
|
self, CCursorRange, text_cursor_state::cursor_rect, visuals::paint_text_selection,
|
||||||
},
|
},
|
||||||
vec2,
|
vec2,
|
||||||
|
widget_style::{Classes, HasClasses, READ_ONLY_CLASS, TextEditStyle},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{TextEditOutput, TextEditState};
|
use super::{TextEditOutput, TextEditState};
|
||||||
@@ -79,7 +80,7 @@ pub struct TextEdit<'t> {
|
|||||||
layouter: Option<LayouterFn<'t>>,
|
layouter: Option<LayouterFn<'t>>,
|
||||||
password: bool,
|
password: bool,
|
||||||
frame: Option<Frame>,
|
frame: Option<Frame>,
|
||||||
margin: Margin,
|
margin: Option<Margin>,
|
||||||
multiline: bool,
|
multiline: bool,
|
||||||
interactive: bool,
|
interactive: bool,
|
||||||
desired_width: Option<f32>,
|
desired_width: Option<f32>,
|
||||||
@@ -92,6 +93,7 @@ pub struct TextEdit<'t> {
|
|||||||
char_limit: usize,
|
char_limit: usize,
|
||||||
return_key: Option<KeyboardShortcut>,
|
return_key: Option<KeyboardShortcut>,
|
||||||
background_color: Option<Color32>,
|
background_color: Option<Color32>,
|
||||||
|
classes: Classes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WidgetWithState for TextEdit<'_> {
|
impl WidgetWithState for TextEdit<'_> {
|
||||||
@@ -133,7 +135,7 @@ impl<'t> TextEdit<'t> {
|
|||||||
layouter: None,
|
layouter: None,
|
||||||
password: false,
|
password: false,
|
||||||
frame: None,
|
frame: None,
|
||||||
margin: Margin::symmetric(4, 2),
|
margin: None,
|
||||||
multiline: true,
|
multiline: true,
|
||||||
interactive: true,
|
interactive: true,
|
||||||
desired_width: None,
|
desired_width: None,
|
||||||
@@ -152,6 +154,7 @@ impl<'t> TextEdit<'t> {
|
|||||||
char_limit: usize::MAX,
|
char_limit: usize::MAX,
|
||||||
return_key: Some(KeyboardShortcut::new(Modifiers::NONE, Key::Enter)),
|
return_key: Some(KeyboardShortcut::new(Modifiers::NONE, Key::Enter)),
|
||||||
background_color: None,
|
background_color: None,
|
||||||
|
classes: Classes::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,10 +311,10 @@ impl<'t> TextEdit<'t> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set margin of text. Default is `Margin::symmetric(4.0, 2.0)`
|
/// Override the padding around the text, which otherwise comes from the theme.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn margin(mut self, margin: impl Into<Margin>) -> Self {
|
pub fn margin(mut self, margin: impl Into<Margin>) -> Self {
|
||||||
self.margin = margin.into();
|
self.margin = Some(margin.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,6 +420,16 @@ impl Widget for TextEdit<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl HasClasses for TextEdit<'_> {
|
||||||
|
fn classes(&self) -> &Classes {
|
||||||
|
&self.classes
|
||||||
|
}
|
||||||
|
|
||||||
|
fn classes_mut(&mut self) -> &mut Classes {
|
||||||
|
&mut self.classes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TextEdit<'_> {
|
impl TextEdit<'_> {
|
||||||
/// Show the [`TextEdit`], returning a rich [`TextEditOutput`].
|
/// Show the [`TextEdit`], returning a rich [`TextEditOutput`].
|
||||||
///
|
///
|
||||||
@@ -459,17 +472,38 @@ impl TextEdit<'_> {
|
|||||||
char_limit,
|
char_limit,
|
||||||
return_key,
|
return_key,
|
||||||
background_color,
|
background_color,
|
||||||
|
mut classes,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
|
let id = id.unwrap_or_else(|| {
|
||||||
|
if let Some(id_salt) = id_salt {
|
||||||
|
ui.make_persistent_id(id_salt)
|
||||||
|
} else {
|
||||||
|
// Since we are only storing the cursor a persistent Id is not super important
|
||||||
|
let id = ui.next_auto_id();
|
||||||
|
ui.skip_ahead_auto_ids(1);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
classes.add_class_if(READ_ONLY_CLASS, !text.is_mutable());
|
||||||
|
let TextEditStyle {
|
||||||
|
frame: styled_frame,
|
||||||
|
text: text_visuals,
|
||||||
|
hint_text_color,
|
||||||
|
} = ui.widget_style(id, &classes);
|
||||||
|
|
||||||
let text_color = text_color
|
let text_color = text_color
|
||||||
.or_else(|| ui.visuals().override_text_color)
|
.or_else(|| ui.visuals().override_text_color)
|
||||||
// .unwrap_or_else(|| ui.style().interact(&response).text_color()); // too bright
|
.unwrap_or(text_visuals.color);
|
||||||
.unwrap_or_else(|| ui.visuals().widgets.inactive.text_color());
|
|
||||||
|
|
||||||
let prev_text = text.as_str().to_owned();
|
let prev_text = text.as_str().to_owned();
|
||||||
let hint_text_str = hint_text.text().unwrap_or_default().to_string();
|
let hint_text_str = hint_text.text().unwrap_or_default().to_string();
|
||||||
|
|
||||||
let font_id = font_selection.resolve(ui.style());
|
let font_id = match font_selection {
|
||||||
|
FontSelection::Default => text_visuals.font_id.clone(),
|
||||||
|
font_selection => font_selection.resolve(ui.style()),
|
||||||
|
};
|
||||||
let row_height = ui.fonts_mut(|f| f.row_height(&font_id));
|
let row_height = ui.fonts_mut(|f| f.row_height(&font_id));
|
||||||
let line_height = row_height + ui.spacing().extra_text_line_spacing;
|
let line_height = row_height + ui.spacing().extra_text_line_spacing;
|
||||||
|
|
||||||
@@ -503,17 +537,6 @@ impl TextEdit<'_> {
|
|||||||
|
|
||||||
let min_inner_height = (desired_height_rows.at_least(1) as f32) * line_height;
|
let min_inner_height = (desired_height_rows.at_least(1) as f32) * line_height;
|
||||||
|
|
||||||
let id = id.unwrap_or_else(|| {
|
|
||||||
if let Some(id_salt) = id_salt {
|
|
||||||
ui.make_persistent_id(id_salt)
|
|
||||||
} else {
|
|
||||||
// Since we are only storing the cursor a persistent Id is not super important
|
|
||||||
let id = ui.next_auto_id();
|
|
||||||
ui.skip_ahead_auto_ids(1);
|
|
||||||
id
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// On touch screens (e.g. mobile in `eframe` web), should
|
// On touch screens (e.g. mobile in `eframe` web), should
|
||||||
// dragging select text, or scroll the enclosing [`ScrollArea`] (if any)?
|
// dragging select text, or scroll the enclosing [`ScrollArea`] (if any)?
|
||||||
// Since currently copying selected text in not supported on `eframe` web,
|
// Since currently copying selected text in not supported on `eframe` web,
|
||||||
@@ -549,7 +572,6 @@ impl TextEdit<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut text_changed = false;
|
let mut text_changed = false;
|
||||||
let text_mutable = text.is_mutable();
|
|
||||||
|
|
||||||
let mut handle_events = |ui: &Ui, galley: &mut Arc<Galley>, layouter, wrap_width, text| {
|
let mut handle_events = |ui: &Ui, galley: &mut Arc<Galley>, layouter, wrap_width, text| {
|
||||||
if interactive && ui.memory(|mem| mem.has_focus(id)) {
|
if interactive && ui.memory(|mem| mem.has_focus(id)) {
|
||||||
@@ -591,6 +613,17 @@ impl TextEdit<'_> {
|
|||||||
// We need to calculate the galley within the atom closure, so we can calculate it based on
|
// We need to calculate the galley within the atom closure, so we can calculate it based on
|
||||||
// the available width (in case of wrapping multiline text edits). But we show it later,
|
// the available width (in case of wrapping multiline text edits). But we show it later,
|
||||||
// so we can clip it to the available size. Thus, extract it from the atom closure here.
|
// so we can clip it to the available size. Thus, extract it from the atom closure here.
|
||||||
|
let frame = frame.unwrap_or_else(|| {
|
||||||
|
let mut frame = styled_frame;
|
||||||
|
if let Some(margin) = margin {
|
||||||
|
frame.inner_margin = margin;
|
||||||
|
}
|
||||||
|
if let Some(background_color) = background_color {
|
||||||
|
frame.fill = background_color;
|
||||||
|
}
|
||||||
|
frame
|
||||||
|
});
|
||||||
|
|
||||||
let mut get_galley = None;
|
let mut get_galley = None;
|
||||||
let inner_rect_id = Id::new("text_edit_rect");
|
let inner_rect_id = Id::new("text_edit_rect");
|
||||||
let mut response = {
|
let mut response = {
|
||||||
@@ -612,7 +645,7 @@ impl TextEdit<'_> {
|
|||||||
|
|
||||||
// Since we can't set a fallback color per atom, we have to override it here.
|
// Since we can't set a fallback color per atom, we have to override it here.
|
||||||
// Sucks, since it means users won't be able to override it.
|
// Sucks, since it means users won't be able to override it.
|
||||||
hint_text.map_texts(|t| t.color(ui.style().visuals.weak_text_color()));
|
hint_text.map_texts(|t| t.color(hint_text_color));
|
||||||
|
|
||||||
for mut atom in hint_text {
|
for mut atom in hint_text {
|
||||||
if !shrunk && matches!(atom.kind, AtomKind::Text(_)) {
|
if !shrunk && matches!(atom.kind, AtomKind::Text(_)) {
|
||||||
@@ -637,7 +670,7 @@ impl TextEdit<'_> {
|
|||||||
|
|
||||||
// Calculate the empty galley, so it can be read later. The available width is
|
// Calculate the empty galley, so it can be read later. The available width is
|
||||||
// technically wrong, but doesn't matter since the galley is empty
|
// technically wrong, but doesn't matter since the galley is empty
|
||||||
let available_width = allocate_width - margin.sum().x;
|
let available_width = allocate_width - frame.total_margin().sum().x;
|
||||||
let galley = layouter(ui, text, available_width);
|
let galley = layouter(ui, text, available_width);
|
||||||
|
|
||||||
// We can't update the galley immediately here, since it would show both hint text
|
// We can't update the galley immediately here, since it would show both hint text
|
||||||
@@ -692,9 +725,6 @@ impl TextEdit<'_> {
|
|||||||
atoms.push_right(atom);
|
atoms.push_right(atom);
|
||||||
}
|
}
|
||||||
|
|
||||||
let custom_frame = frame.is_some();
|
|
||||||
let frame = frame.unwrap_or_else(|| Frame::new().inner_margin(margin));
|
|
||||||
|
|
||||||
let min_height = min_inner_height + frame.total_margin().sum().y;
|
let min_height = min_inner_height + frame.total_margin().sum().y;
|
||||||
|
|
||||||
// This wrap mode only affects the hint_text
|
// This wrap mode only affects the hint_text
|
||||||
@@ -704,7 +734,7 @@ impl TextEdit<'_> {
|
|||||||
TextWrapMode::Truncate
|
TextWrapMode::Truncate
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut allocated = AtomLayout::new(atoms)
|
let allocated = AtomLayout::new(atoms)
|
||||||
.id(id)
|
.id(id)
|
||||||
.min_size(Vec2::new(allocate_width, min_height))
|
.min_size(Vec2::new(allocate_width, min_height))
|
||||||
.max_width(allocate_width)
|
.max_width(allocate_width)
|
||||||
@@ -714,43 +744,6 @@ impl TextEdit<'_> {
|
|||||||
.wrap_mode(wrap_mode)
|
.wrap_mode(wrap_mode)
|
||||||
.allocate(ui);
|
.allocate(ui);
|
||||||
|
|
||||||
allocated.frame = if custom_frame {
|
|
||||||
allocated.frame
|
|
||||||
} else {
|
|
||||||
let visuals = ui.style().interact(&allocated.response);
|
|
||||||
let background_color =
|
|
||||||
background_color.unwrap_or_else(|| ui.visuals().text_edit_bg_color());
|
|
||||||
|
|
||||||
let (corner_radius, background_color, stroke) = if text_mutable {
|
|
||||||
if allocated.response.has_focus() {
|
|
||||||
(
|
|
||||||
visuals.corner_radius,
|
|
||||||
background_color,
|
|
||||||
ui.visuals().selection.stroke,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(visuals.corner_radius, background_color, visuals.bg_stroke)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let visuals = &ui.style().visuals.widgets.inactive;
|
|
||||||
(
|
|
||||||
visuals.corner_radius,
|
|
||||||
Color32::TRANSPARENT,
|
|
||||||
visuals.bg_stroke,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
allocated
|
|
||||||
.frame
|
|
||||||
.fill(background_color)
|
|
||||||
.corner_radius(corner_radius)
|
|
||||||
.inner_margin(
|
|
||||||
allocated.frame.inner_margin
|
|
||||||
+ Margin::same((visuals.expansion - stroke.width).round() as i8),
|
|
||||||
)
|
|
||||||
.outer_margin(Margin::same(-(visuals.expansion as i8)))
|
|
||||||
.stroke(stroke)
|
|
||||||
};
|
|
||||||
|
|
||||||
allocated.paint(ui)
|
allocated.paint(ui)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user