|
@@ -1,17 +1,25 @@
|
|
|
use crate::{
|
|
|
- input::{MouseButton, MouseCheckStatus},
|
|
|
- layout::{LayoutNode, LayoutNodeAccess, LeafLayoutNode, SizePolicy},
|
|
|
+ input::MouseButton,
|
|
|
+ layout::{HorizontalAlignment, LayoutNode, LayoutNodeAccess, LayoutTreeNode, LeafLayoutNode, SizePolicy},
|
|
|
prelude::*,
|
|
|
render::{ColourChoice, RenderTarget, TextCache},
|
|
|
ui::UIHandle,
|
|
|
};
|
|
|
use winit::keyboard::{Key, NamedKey};
|
|
|
|
|
|
+pub enum CursorPosition {
|
|
|
+ Start,
|
|
|
+ Index(usize),
|
|
|
+ End,
|
|
|
+}
|
|
|
+
|
|
|
pub struct TextEdit<C: Component> {
|
|
|
- lnode: LeafLayoutNode,
|
|
|
+ lnode: LayoutNode,
|
|
|
+ cursor_node: LeafLayoutNode,
|
|
|
text: TextCache,
|
|
|
- cursor_pos: Option<usize>,
|
|
|
+ cursor_pos: CursorPosition,
|
|
|
onchange: Option<Box<dyn Fn(&str) -> Option<C::Msg>>>,
|
|
|
+ focused: bool,
|
|
|
}
|
|
|
|
|
|
impl<C: Component> TextEdit<C> {
|
|
@@ -22,14 +30,22 @@ impl<C: Component> TextEdit<C> {
|
|
|
.set_width_policy(SizePolicy::expanding(1))
|
|
|
.set_height_policy(SizePolicy::fixed(minheight));
|
|
|
|
|
|
+ let mut cursor_node = uih.new_layout_node();
|
|
|
+ cursor_node
|
|
|
+ .set_width_policy(SizePolicy::fixed(2))
|
|
|
+ .set_height_policy(SizePolicy::fixed(minheight))
|
|
|
+ .set_halign(HorizontalAlignment::Left);
|
|
|
+
|
|
|
Self {
|
|
|
- lnode: LeafLayoutNode::new(lnode),
|
|
|
+ lnode,
|
|
|
+ cursor_node: LeafLayoutNode::new(cursor_node),
|
|
|
text: TextCache::new_with_font_and_size(
|
|
|
uih.theme().ui_font.clone(),
|
|
|
uih.theme().ui_font_size,
|
|
|
),
|
|
|
- cursor_pos: None,
|
|
|
+ cursor_pos: CursorPosition::End,
|
|
|
onchange: None,
|
|
|
+ focused: false
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -37,20 +53,27 @@ impl<C: Component> TextEdit<C> {
|
|
|
self.text.update(to);
|
|
|
}
|
|
|
|
|
|
- /*fn update_hints(&mut self, uih: &UIHandle) {
|
|
|
- let line = uih.theme().make_line(self.text.as_str());
|
|
|
- let (rendered, offset) = line.render_line();
|
|
|
- let sz = rendered.size();
|
|
|
- *self.rendered.borrow_mut() = Some((rendered, offset));
|
|
|
- self.lnode.render_needed();
|
|
|
-
|
|
|
- let wp = self.lnode.width_policy().with_minimum(sz.width as usize);
|
|
|
- self.lnode.set_width_policy(wp);
|
|
|
- let hp = self.lnode.height_policy().with_minimum(sz.height as usize);
|
|
|
- self.lnode.set_height_policy(hp);
|
|
|
+ /*pub fn set_cursor_position(&mut self, to: CursorPosition) {
|
|
|
+
|
|
|
}*/
|
|
|
}
|
|
|
|
|
|
+impl<C: Component> LayoutTreeNode<()> for TextEdit<C> {
|
|
|
+ fn child(&self, ndx: usize) -> Option<LayoutNodeAccess<'_>> {
|
|
|
+ if ndx == 0 {
|
|
|
+ Some(self.cursor_node.access())
|
|
|
+ } else {
|
|
|
+ None
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fn child_count(&self) -> usize {
|
|
|
+ 1
|
|
|
+ }
|
|
|
+ fn current_node(&self) -> &LayoutNode {
|
|
|
+ &self.lnode
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
impl<C: Component> Widget<C> for TextEdit<C> {
|
|
|
fn poll(
|
|
|
&mut self,
|
|
@@ -67,7 +90,6 @@ impl<C: Component> Widget<C> for TextEdit<C> {
|
|
|
Key::Named(NamedKey::Backspace) => {
|
|
|
self.text.change(String::pop);
|
|
|
self.lnode.render_needed();
|
|
|
- // self.update_hints(uih);
|
|
|
}
|
|
|
Key::Named(NamedKey::Delete) => {
|
|
|
self.text.change(String::pop);
|
|
@@ -85,19 +107,32 @@ impl<C: Component> Widget<C> for TextEdit<C> {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- if istate.mouse_status_in(self.lnode.render_area().unwrap(), MouseButton::Left)
|
|
|
- == MouseCheckStatus::Click
|
|
|
+ let render_area = self.lnode.render_area().unwrap();
|
|
|
+ if istate
|
|
|
+ .mouse_status_in(render_area, MouseButton::Left)
|
|
|
+ .is_click()
|
|
|
{
|
|
|
istate.focus_on(self.lnode.id());
|
|
|
+ self.focused = true;
|
|
|
+ println!("click offset: {:?}", istate.mouse.pos - render_area.min);
|
|
|
+
|
|
|
+ let cbar_offset = self.text.size_hint().width;
|
|
|
+ self.cursor_node.margin_mut().left = cbar_offset;
|
|
|
}
|
|
|
|
|
|
- // self.update_hints(uih);
|
|
|
+ let was_focused = self.focused;
|
|
|
+ self.focused = istate.is_focused(self.lnode.id());
|
|
|
+
|
|
|
+ if self.focused != was_focused {
|
|
|
+ self.cursor_node.render_needed();
|
|
|
+ self.lnode.render_needed();
|
|
|
+ }
|
|
|
|
|
|
vec![]
|
|
|
}
|
|
|
|
|
|
fn layout_node(&self) -> LayoutNodeAccess {
|
|
|
- LayoutNodeAccess::new(&self.lnode)
|
|
|
+ LayoutNodeAccess::new(self)
|
|
|
}
|
|
|
fn layout_node_mut(&mut self) -> &mut LayoutNode {
|
|
|
&mut self.lnode
|
|
@@ -109,16 +144,9 @@ impl<C: Component> Widget<C> for TextEdit<C> {
|
|
|
.fill(ColourChoice::Background)
|
|
|
.simple_text(&self.text, ColourChoice::Foreground);
|
|
|
|
|
|
- /*if self.lnode.render_check() {
|
|
|
- let area = self.lnode.render_area().unwrap();
|
|
|
- target.fill_region(area, theme.background);
|
|
|
-
|
|
|
- let amap = self.rendered.borrow();
|
|
|
- let Some((amap, offset)) = amap.as_ref() else {
|
|
|
- return;
|
|
|
- };
|
|
|
-
|
|
|
- target.fill_region_masked(amap, PixelBox::from_size(amap.size()), area.min, theme.foreground, kahlo::colour::BlendMode::SourceAlpha);
|
|
|
- }*/
|
|
|
+ if self.focused {
|
|
|
+ target.with_node(&self.cursor_node)
|
|
|
+ .fill(ColourChoice::Foreground);
|
|
|
+ }
|
|
|
}
|
|
|
}
|