make dragvalue textedit style consistent with button (#2649)
* make dragvalue textedit style consistent with button * fix comments & fix wrong interactive cursor pos * * apply button_padding to textedit * support vertical align * add same min size as button to avoid unintented height shrink
This commit is contained in:
parent
b52cd2052f
commit
8bc88c9bf4
2 changed files with 62 additions and 10 deletions
|
@ -461,14 +461,18 @@ impl<'a> Widget for DragValue<'a> {
|
||||||
// some clones below are redundant if AccessKit is disabled
|
// some clones below are redundant if AccessKit is disabled
|
||||||
#[allow(clippy::redundant_clone)]
|
#[allow(clippy::redundant_clone)]
|
||||||
let mut response = if is_kb_editing {
|
let mut response = if is_kb_editing {
|
||||||
let button_width = ui.spacing().interact_size.x;
|
|
||||||
let mut value_text = ui
|
let mut value_text = ui
|
||||||
.memory_mut(|mem| mem.drag_value.edit_string.take())
|
.memory_mut(|mem| mem.drag_value.edit_string.take())
|
||||||
.unwrap_or_else(|| value_text.clone());
|
.unwrap_or_else(|| value_text.clone());
|
||||||
let response = ui.add(
|
let response = ui.add(
|
||||||
TextEdit::singleline(&mut value_text)
|
TextEdit::singleline(&mut value_text)
|
||||||
|
.clip_text(false)
|
||||||
|
.horizontal_align(ui.layout().horizontal_align())
|
||||||
|
.vertical_align(ui.layout().vertical_align())
|
||||||
|
.margin(ui.spacing().button_padding)
|
||||||
|
.min_size(ui.spacing().interact_size)
|
||||||
.id(id)
|
.id(id)
|
||||||
.desired_width(button_width)
|
.desired_width(ui.spacing().interact_size.x)
|
||||||
.font(text_style),
|
.font(text_style),
|
||||||
);
|
);
|
||||||
let parsed_value = match custom_parser {
|
let parsed_value = match custom_parser {
|
||||||
|
|
|
@ -67,6 +67,9 @@ pub struct TextEdit<'t> {
|
||||||
desired_height_rows: usize,
|
desired_height_rows: usize,
|
||||||
lock_focus: bool,
|
lock_focus: bool,
|
||||||
cursor_at_end: bool,
|
cursor_at_end: bool,
|
||||||
|
min_size: Vec2,
|
||||||
|
align: Align2,
|
||||||
|
clip_text: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t> WidgetWithState for TextEdit<'t> {
|
impl<'t> WidgetWithState for TextEdit<'t> {
|
||||||
|
@ -89,6 +92,7 @@ impl<'t> TextEdit<'t> {
|
||||||
Self {
|
Self {
|
||||||
desired_height_rows: 1,
|
desired_height_rows: 1,
|
||||||
multiline: false,
|
multiline: false,
|
||||||
|
clip_text: true,
|
||||||
..Self::multiline(text)
|
..Self::multiline(text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,6 +116,9 @@ impl<'t> TextEdit<'t> {
|
||||||
desired_height_rows: 4,
|
desired_height_rows: 4,
|
||||||
lock_focus: false,
|
lock_focus: false,
|
||||||
cursor_at_end: true,
|
cursor_at_end: true,
|
||||||
|
min_size: Vec2::ZERO,
|
||||||
|
align: Align2::LEFT_TOP,
|
||||||
|
clip_text: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,6 +276,37 @@ impl<'t> TextEdit<'t> {
|
||||||
self.cursor_at_end = b;
|
self.cursor_at_end = b;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// When `true` (default), overflowing text will be clipped.
|
||||||
|
///
|
||||||
|
/// When `false`, widget width will expand to make all text visible.
|
||||||
|
///
|
||||||
|
/// This only works for singleline [`TextEdit`].
|
||||||
|
pub fn clip_text(mut self, b: bool) -> Self {
|
||||||
|
// always show everything in multiline
|
||||||
|
if !self.multiline {
|
||||||
|
self.clip_text = b;
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the horizontal align of the inner text.
|
||||||
|
pub fn horizontal_align(mut self, align: Align) -> Self {
|
||||||
|
self.align.0[0] = align;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the vertical align of the inner text.
|
||||||
|
pub fn vertical_align(mut self, align: Align) -> Self {
|
||||||
|
self.align.0[1] = align;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the minimum size of the [`TextEdit`].
|
||||||
|
pub fn min_size(mut self, min_size: Vec2) -> Self {
|
||||||
|
self.min_size = min_size;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -364,13 +402,16 @@ impl<'t> TextEdit<'t> {
|
||||||
layouter,
|
layouter,
|
||||||
password,
|
password,
|
||||||
frame: _,
|
frame: _,
|
||||||
margin: _,
|
margin,
|
||||||
multiline,
|
multiline,
|
||||||
interactive,
|
interactive,
|
||||||
desired_width,
|
desired_width,
|
||||||
desired_height_rows,
|
desired_height_rows,
|
||||||
lock_focus,
|
lock_focus,
|
||||||
cursor_at_end,
|
cursor_at_end,
|
||||||
|
min_size,
|
||||||
|
align,
|
||||||
|
clip_text,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let text_color = text_color
|
let text_color = text_color
|
||||||
|
@ -389,7 +430,7 @@ impl<'t> TextEdit<'t> {
|
||||||
available_width
|
available_width
|
||||||
} else {
|
} else {
|
||||||
desired_width.min(available_width)
|
desired_width.min(available_width)
|
||||||
};
|
} - margin.x * 2.0;
|
||||||
|
|
||||||
let font_id_clone = font_id.clone();
|
let font_id_clone = font_id.clone();
|
||||||
let mut default_layouter = move |ui: &Ui, text: &str, wrap_width: f32| {
|
let mut default_layouter = move |ui: &Ui, text: &str, wrap_width: f32| {
|
||||||
|
@ -406,13 +447,14 @@ impl<'t> TextEdit<'t> {
|
||||||
|
|
||||||
let mut galley = layouter(ui, text.as_str(), wrap_width);
|
let mut galley = layouter(ui, text.as_str(), wrap_width);
|
||||||
|
|
||||||
let desired_width = if multiline {
|
let desired_width = if clip_text {
|
||||||
galley.size().x.max(wrap_width) // always show everything in multiline
|
wrap_width // visual clipping with scroll in singleline input.
|
||||||
} else {
|
} else {
|
||||||
wrap_width // visual clipping with scroll in singleline input. TODO(emilk): opt-in/out?
|
galley.size().x.max(wrap_width)
|
||||||
};
|
};
|
||||||
let desired_height = (desired_height_rows.at_least(1) as f32) * row_height;
|
let desired_height = (desired_height_rows.at_least(1) as f32) * row_height;
|
||||||
let desired_size = vec2(desired_width, galley.size().y.max(desired_height));
|
let desired_size = vec2(desired_width, galley.size().y.max(desired_height))
|
||||||
|
.at_least(min_size - margin * 2.0);
|
||||||
|
|
||||||
let (auto_id, rect) = ui.allocate_space(desired_size);
|
let (auto_id, rect) = ui.allocate_space(desired_size);
|
||||||
|
|
||||||
|
@ -547,10 +589,14 @@ impl<'t> TextEdit<'t> {
|
||||||
cursor_range = Some(new_cursor_range);
|
cursor_range = Some(new_cursor_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut text_draw_pos = response.rect.min;
|
let mut text_draw_pos = align
|
||||||
|
.align_size_within_rect(galley.size(), response.rect)
|
||||||
|
.intersect(response.rect) // limit pos to the response rect area
|
||||||
|
.min;
|
||||||
|
let align_offset = response.rect.left() - text_draw_pos.x;
|
||||||
|
|
||||||
// Visual clipping for singleline text editor with text larger than width
|
// Visual clipping for singleline text editor with text larger than width
|
||||||
if !multiline {
|
if clip_text && align_offset == 0.0 {
|
||||||
let cursor_pos = match (cursor_range, ui.memory(|mem| mem.has_focus(id))) {
|
let cursor_pos = match (cursor_range, ui.memory(|mem| mem.has_focus(id))) {
|
||||||
(Some(cursor_range), true) => galley.pos_from_cursor(&cursor_range.primary).min.x,
|
(Some(cursor_range), true) => galley.pos_from_cursor(&cursor_range.primary).min.x,
|
||||||
_ => 0.0,
|
_ => 0.0,
|
||||||
|
@ -573,6 +619,8 @@ impl<'t> TextEdit<'t> {
|
||||||
|
|
||||||
state.singleline_offset = offset_x;
|
state.singleline_offset = offset_x;
|
||||||
text_draw_pos -= vec2(offset_x, 0.0);
|
text_draw_pos -= vec2(offset_x, 0.0);
|
||||||
|
} else {
|
||||||
|
state.singleline_offset = align_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
let selection_changed = if let (Some(cursor_range), Some(prev_cursor_range)) =
|
let selection_changed = if let (Some(cursor_range), Some(prev_cursor_range)) =
|
||||||
|
|
Loading…
Reference in a new issue