summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-07-24 14:52:01 +0200
committerLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-07-24 14:52:01 +0200
commite9e06c8fe2ef291b04f6059a841ceb999455bea8 (patch)
tree7a8d1d636d69125762045e0ca431359810064b75
parenta5b1a1df548a9bfeefc3e422defe6d67cf61c170 (diff)
downloadiced-e9e06c8fe2ef291b04f6059a841ceb999455bea8.tar.gz
iced-e9e06c8fe2ef291b04f6059a841ceb999455bea8.tar.bz2
iced-e9e06c8fe2ef291b04f6059a841ceb999455bea8.zip
Add `placeholder` support to `text_editor` widget
-rw-r--r--core/src/renderer/null.rs4
-rw-r--r--core/src/text/editor.rs3
-rw-r--r--examples/markdown/src/main.rs1
-rw-r--r--graphics/src/text/editor.rs7
-rw-r--r--widget/src/text_editor.rs62
5 files changed, 68 insertions, 9 deletions
diff --git a/core/src/renderer/null.rs b/core/src/renderer/null.rs
index 7aa3aafb..d8d3c50a 100644
--- a/core/src/renderer/null.rs
+++ b/core/src/renderer/null.rs
@@ -118,6 +118,10 @@ impl text::Editor for () {
fn with_text(_text: &str) -> Self {}
+ fn is_empty(&self) -> bool {
+ true
+ }
+
fn cursor(&self) -> text::editor::Cursor {
text::editor::Cursor::Caret(Point::ORIGIN)
}
diff --git a/core/src/text/editor.rs b/core/src/text/editor.rs
index aea00921..135707d1 100644
--- a/core/src/text/editor.rs
+++ b/core/src/text/editor.rs
@@ -13,6 +13,9 @@ pub trait Editor: Sized + Default {
/// Creates a new [`Editor`] laid out with the given text.
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`].
fn cursor(&self) -> Cursor;
diff --git a/examples/markdown/src/main.rs b/examples/markdown/src/main.rs
index 163dab66..173cb389 100644
--- a/examples/markdown/src/main.rs
+++ b/examples/markdown/src/main.rs
@@ -59,6 +59,7 @@ impl Markdown {
fn view(&self) -> Element<Message> {
let editor = text_editor(&self.content)
+ .placeholder("Type your Markdown here...")
.on_action(Message::Edit)
.height(Fill)
.padding(10)
diff --git a/graphics/src/text/editor.rs b/graphics/src/text/editor.rs
index 3e6ef70c..80733bbb 100644
--- a/graphics/src/text/editor.rs
+++ b/graphics/src/text/editor.rs
@@ -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> {
self.buffer()
.lines
diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs
index e494a3b0..0bfc8500 100644
--- a/widget/src/text_editor.rs
+++ b/widget/src/text_editor.rs
@@ -1,4 +1,5 @@
//! Display a multi-line text input for text editing.
+use crate::core::alignment;
use crate::core::clipboard::{self, Clipboard};
use crate::core::event::{self, Event};
use crate::core::keyboard;
@@ -8,7 +9,7 @@ use crate::core::mouse;
use crate::core::renderer;
use crate::core::text::editor::{Cursor, Editor as _};
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::{self, Widget};
use crate::core::{
@@ -37,6 +38,7 @@ pub struct TextEditor<
Renderer: text::Renderer,
{
content: &'a Content<Renderer>,
+ placeholder: Option<text::Fragment<'a>>,
font: Option<Renderer::Font>,
text_size: Option<Pixels>,
line_height: LineHeight,
@@ -62,6 +64,7 @@ where
pub fn new(content: &'a Content<Renderer>) -> Self {
Self {
content,
+ placeholder: None,
font: None,
text_size: None,
line_height: LineHeight::default(),
@@ -85,6 +88,15 @@ where
Theme: Catalog,
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`].
pub fn height(mut self, height: impl Into<Length>) -> Self {
self.height = height.into();
@@ -144,6 +156,7 @@ where
) -> TextEditor<'a, H, Message, Theme, Renderer> {
TextEditor {
content: self.content,
+ placeholder: self.placeholder,
font: self.font,
text_size: self.text_size,
line_height: self.line_height,
@@ -546,8 +559,10 @@ where
let mut internal = self.content.0.borrow_mut();
let state = tree.state.downcast_ref::<State<Highlighter>>();
+ let font = self.font.unwrap_or_else(|| renderer.default_font());
+
internal.editor.highlight(
- self.font.unwrap_or_else(|| renderer.default_font()),
+ font,
state.highlighter.borrow_mut().deref_mut(),
|highlight| (self.highlighter_format)(highlight, theme),
);
@@ -576,13 +591,42 @@ where
style.background,
);
- renderer.fill_editor(
- &internal.editor,
- bounds.position()
- + Vector::new(self.padding.left, self.padding.top),
- defaults.text_color,
- *viewport,
- );
+ let position = bounds.position()
+ + Vector::new(self.padding.left, self.padding.top);
+
+ if internal.editor.is_empty() {
+ if let Some(placeholder) = self.placeholder.clone() {
+ 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(
bounds.x + self.padding.left,