Add placeholder support to text_editor widget
This commit is contained in:
parent
a5b1a1df54
commit
e9e06c8fe2
5 changed files with 68 additions and 9 deletions
|
|
@ -118,6 +118,10 @@ impl text::Editor for () {
|
||||||
|
|
||||||
fn with_text(_text: &str) -> Self {}
|
fn with_text(_text: &str) -> Self {}
|
||||||
|
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn cursor(&self) -> text::editor::Cursor {
|
fn cursor(&self) -> text::editor::Cursor {
|
||||||
text::editor::Cursor::Caret(Point::ORIGIN)
|
text::editor::Cursor::Caret(Point::ORIGIN)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,9 @@ pub trait Editor: Sized + Default {
|
||||||
/// Creates a new [`Editor`] laid out with the given text.
|
/// Creates a new [`Editor`] laid out with the given text.
|
||||||
fn with_text(text: &str) -> Self;
|
fn with_text(text: &str) -> Self;
|
||||||
|
|
||||||
|
/// Returns true if the [`Editor`] has no contents.
|
||||||
|
fn is_empty(&self) -> bool;
|
||||||
|
|
||||||
/// Returns the current [`Cursor`] of the [`Editor`].
|
/// Returns the current [`Cursor`] of the [`Editor`].
|
||||||
fn cursor(&self) -> Cursor;
|
fn cursor(&self) -> Cursor;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ impl Markdown {
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<Message> {
|
||||||
let editor = text_editor(&self.content)
|
let editor = text_editor(&self.content)
|
||||||
|
.placeholder("Type your Markdown here...")
|
||||||
.on_action(Message::Edit)
|
.on_action(Message::Edit)
|
||||||
.height(Fill)
|
.height(Fill)
|
||||||
.padding(10)
|
.padding(10)
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,13 @@ impl editor::Editor for Editor {
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
let buffer = self.buffer();
|
||||||
|
|
||||||
|
buffer.lines.is_empty()
|
||||||
|
|| (buffer.lines.len() == 1 && buffer.lines[0].text().is_empty())
|
||||||
|
}
|
||||||
|
|
||||||
fn line(&self, index: usize) -> Option<&str> {
|
fn line(&self, index: usize) -> Option<&str> {
|
||||||
self.buffer()
|
self.buffer()
|
||||||
.lines
|
.lines
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
//! Display a multi-line text input for text editing.
|
//! Display a multi-line text input for text editing.
|
||||||
|
use crate::core::alignment;
|
||||||
use crate::core::clipboard::{self, Clipboard};
|
use crate::core::clipboard::{self, Clipboard};
|
||||||
use crate::core::event::{self, Event};
|
use crate::core::event::{self, Event};
|
||||||
use crate::core::keyboard;
|
use crate::core::keyboard;
|
||||||
|
|
@ -8,7 +9,7 @@ use crate::core::mouse;
|
||||||
use crate::core::renderer;
|
use crate::core::renderer;
|
||||||
use crate::core::text::editor::{Cursor, Editor as _};
|
use crate::core::text::editor::{Cursor, Editor as _};
|
||||||
use crate::core::text::highlighter::{self, Highlighter};
|
use crate::core::text::highlighter::{self, Highlighter};
|
||||||
use crate::core::text::{self, LineHeight};
|
use crate::core::text::{self, LineHeight, Text};
|
||||||
use crate::core::widget::operation;
|
use crate::core::widget::operation;
|
||||||
use crate::core::widget::{self, Widget};
|
use crate::core::widget::{self, Widget};
|
||||||
use crate::core::{
|
use crate::core::{
|
||||||
|
|
@ -37,6 +38,7 @@ pub struct TextEditor<
|
||||||
Renderer: text::Renderer,
|
Renderer: text::Renderer,
|
||||||
{
|
{
|
||||||
content: &'a Content<Renderer>,
|
content: &'a Content<Renderer>,
|
||||||
|
placeholder: Option<text::Fragment<'a>>,
|
||||||
font: Option<Renderer::Font>,
|
font: Option<Renderer::Font>,
|
||||||
text_size: Option<Pixels>,
|
text_size: Option<Pixels>,
|
||||||
line_height: LineHeight,
|
line_height: LineHeight,
|
||||||
|
|
@ -62,6 +64,7 @@ where
|
||||||
pub fn new(content: &'a Content<Renderer>) -> Self {
|
pub fn new(content: &'a Content<Renderer>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
content,
|
content,
|
||||||
|
placeholder: None,
|
||||||
font: None,
|
font: None,
|
||||||
text_size: None,
|
text_size: None,
|
||||||
line_height: LineHeight::default(),
|
line_height: LineHeight::default(),
|
||||||
|
|
@ -85,6 +88,15 @@ where
|
||||||
Theme: Catalog,
|
Theme: Catalog,
|
||||||
Renderer: text::Renderer,
|
Renderer: text::Renderer,
|
||||||
{
|
{
|
||||||
|
/// Sets the placeholder of the [`PickList`].
|
||||||
|
pub fn placeholder(
|
||||||
|
mut self,
|
||||||
|
placeholder: impl text::IntoFragment<'a>,
|
||||||
|
) -> Self {
|
||||||
|
self.placeholder = Some(placeholder.into_fragment());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the height of the [`TextEditor`].
|
/// Sets the height of the [`TextEditor`].
|
||||||
pub fn height(mut self, height: impl Into<Length>) -> Self {
|
pub fn height(mut self, height: impl Into<Length>) -> Self {
|
||||||
self.height = height.into();
|
self.height = height.into();
|
||||||
|
|
@ -144,6 +156,7 @@ where
|
||||||
) -> TextEditor<'a, H, Message, Theme, Renderer> {
|
) -> TextEditor<'a, H, Message, Theme, Renderer> {
|
||||||
TextEditor {
|
TextEditor {
|
||||||
content: self.content,
|
content: self.content,
|
||||||
|
placeholder: self.placeholder,
|
||||||
font: self.font,
|
font: self.font,
|
||||||
text_size: self.text_size,
|
text_size: self.text_size,
|
||||||
line_height: self.line_height,
|
line_height: self.line_height,
|
||||||
|
|
@ -546,8 +559,10 @@ where
|
||||||
let mut internal = self.content.0.borrow_mut();
|
let mut internal = self.content.0.borrow_mut();
|
||||||
let state = tree.state.downcast_ref::<State<Highlighter>>();
|
let state = tree.state.downcast_ref::<State<Highlighter>>();
|
||||||
|
|
||||||
|
let font = self.font.unwrap_or_else(|| renderer.default_font());
|
||||||
|
|
||||||
internal.editor.highlight(
|
internal.editor.highlight(
|
||||||
self.font.unwrap_or_else(|| renderer.default_font()),
|
font,
|
||||||
state.highlighter.borrow_mut().deref_mut(),
|
state.highlighter.borrow_mut().deref_mut(),
|
||||||
|highlight| (self.highlighter_format)(highlight, theme),
|
|highlight| (self.highlighter_format)(highlight, theme),
|
||||||
);
|
);
|
||||||
|
|
@ -576,13 +591,42 @@ where
|
||||||
style.background,
|
style.background,
|
||||||
);
|
);
|
||||||
|
|
||||||
renderer.fill_editor(
|
let position = bounds.position()
|
||||||
&internal.editor,
|
+ Vector::new(self.padding.left, self.padding.top);
|
||||||
bounds.position()
|
|
||||||
+ Vector::new(self.padding.left, self.padding.top),
|
if internal.editor.is_empty() {
|
||||||
defaults.text_color,
|
if let Some(placeholder) = self.placeholder.clone() {
|
||||||
*viewport,
|
renderer.fill_text(
|
||||||
);
|
Text {
|
||||||
|
content: placeholder.into_owned(),
|
||||||
|
bounds: bounds.size()
|
||||||
|
- Size::new(
|
||||||
|
self.padding.right,
|
||||||
|
self.padding.bottom,
|
||||||
|
),
|
||||||
|
|
||||||
|
size: self
|
||||||
|
.text_size
|
||||||
|
.unwrap_or_else(|| renderer.default_size()),
|
||||||
|
line_height: self.line_height,
|
||||||
|
font,
|
||||||
|
horizontal_alignment: alignment::Horizontal::Left,
|
||||||
|
vertical_alignment: alignment::Vertical::Top,
|
||||||
|
shaping: text::Shaping::Advanced,
|
||||||
|
},
|
||||||
|
position,
|
||||||
|
style.placeholder,
|
||||||
|
*viewport,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
renderer.fill_editor(
|
||||||
|
&internal.editor,
|
||||||
|
position,
|
||||||
|
defaults.text_color,
|
||||||
|
*viewport,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let translation = Vector::new(
|
let translation = Vector::new(
|
||||||
bounds.x + self.padding.left,
|
bounds.x + self.padding.left,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue