Hello,
I'm trying to implement my own ui component of Coffee::ui. I am a beginner, so I copied existing radio component and modified. My goal is to write a text input.
There is the code:
//! Create text input.
use coffee::graphics::{
Color, HorizontalAlignment, Point, Rectangle, VerticalAlignment,
};
use coffee::input::{mouse, keyboard, ButtonState};
use coffee::ui::core::{
Align, Element, Event, Hasher, Layout, MouseCursor, Node, Widget,
};
use coffee::ui::widget::{text, Column, Row, Text};
use std::hash::Hash;
pub struct TextInput<Message> {
is_selected: bool,
on_change: Message,
label: String,
value: String,
label_color: Color,
}
impl<Message> std::fmt::Debug for TextInput<Message>
where
Message: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TextInput")
.field("is_selected", &self.is_selected)
.field("on_change", &self.on_change)
.field("label", &self.label)
.field("value", &self.value)
.field("label_color", &self.label_color)
.finish()
}
}
impl<Message> TextInput<Message> {
pub fn new<F>(label: &str, value: &str, is_selected: bool, f: F) -> Self
where
F: 'static + Fn(&str) -> Message,
{
TextInput {
is_selected,
on_change: f,
label: String::from(label),
value: String::from(value),
label_color: Color::WHITE,
}
}
pub fn label_color(mut self, color: Color) -> Self {
self.label_color = color;
self
}
}
impl<Message, Renderer> Widget<Message, Renderer> for TextInput<Message>
where
Renderer: self::Renderer + text::Renderer,
Message: Copy + std::fmt::Debug,
{
fn node(&self, renderer: &Renderer) -> Node {
Row::<(), Renderer>::new()
.spacing(15)
.align_items(Align::Center)
.push(Column::new().width(28).height(28))
.push(Text::new(format!("{}: {}", self.label, self.value).as_str()))
.node(renderer)
}
fn on_event(
&mut self,
event: Event,
layout: Layout<'_>,
cursor_position: Point,
messages: &mut Vec<Message>,
) {
match event {
Event::Mouse(mouse::Event::Input {
button: mouse::Button::Left,
state: ButtonState::Pressed,
}) => {
if layout.bounds().contains(cursor_position) {
self.is_selected = true;
} else {
self.is_selected = false;
}
}
Event::Keyboard(keyboard::Event::Input { state, key_code }) => {
// FIXME BS NOW: real input key, see example/input.rs ?
self.value = format!("{}{}", self.value, "X");
}
_ => {}
}
}
fn draw(
&self,
renderer: &mut Renderer,
layout: Layout<'_>,
cursor_position: Point,
) -> MouseCursor {
let children: Vec<_> = layout.children().collect();
let mut text_bounds = children[1].bounds();
text_bounds.y -= 2.0;
text::Renderer::draw(
renderer,
text_bounds,
format!("{}: {}", self.label, self.value).as_str(),
20.0,
self.label_color,
HorizontalAlignment::Left,
VerticalAlignment::Top,
);
self::Renderer::draw(
renderer,
cursor_position,
children[0].bounds(),
layout.bounds(),
self.is_selected,
)
}
fn hash(&self, state: &mut Hasher) {
self.label.hash(state);
}
}
pub trait Renderer {
fn draw(
&mut self,
cursor_position: Point,
bounds: Rectangle<f32>,
label_bounds: Rectangle<f32>,
is_selected: bool,
) -> MouseCursor;
}
impl<'a, Message, Renderer> From<TextInput<Message>>
for Element<'a, Message, Renderer>
where
Renderer: self::Renderer + text::Renderer,
Message: 'static + Copy + std::fmt::Debug,
{
fn from(text_input: TextInput<Message>) -> Element<'a, Message, Renderer> {
Element::new(text_input)
}
}
Error happen at compile time:
error[E0210]: type parameter `Message` must be used as the type parameter for some local type (e.g., `MyStruct<Message>`)
--> src/ui/text_input.rs:143:10
|
143 | impl<'a, Message, Renderer> From<TextInput<Message>>
| ^^^^^^^ type parameter `Message` must be used as the type parameter for some local type
|
= note: only traits defined in the current crate can be implemented for a type parameter
error: aborting due to previous error
I don't understand what i have to do. Any help ? thank you so much by advance !