Compare commits
1 Commits
fc89826794
...
c24c517c60
| Author | SHA1 | Date | |
|---|---|---|---|
| c24c517c60 |
@@ -5,7 +5,10 @@ use input::Input;
|
|||||||
use iris::prelude::*;
|
use iris::prelude::*;
|
||||||
use len_fns::*;
|
use len_fns::*;
|
||||||
use render::Renderer;
|
use render::Renderer;
|
||||||
use std::sync::Arc;
|
use std::{
|
||||||
|
sync::Arc,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
use winit::{
|
use winit::{
|
||||||
dpi::{LogicalPosition, LogicalSize},
|
dpi::{LogicalPosition, LogicalSize},
|
||||||
event::{Ime, WindowEvent},
|
event::{Ime, WindowEvent},
|
||||||
@@ -30,6 +33,7 @@ pub struct Client {
|
|||||||
focus: Option<WidgetId<TextEdit>>,
|
focus: Option<WidgetId<TextEdit>>,
|
||||||
clipboard: Clipboard,
|
clipboard: Clipboard,
|
||||||
ime: usize,
|
ime: usize,
|
||||||
|
last_click: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Hash, Clone)]
|
#[derive(Eq, PartialEq, Hash, Clone)]
|
||||||
@@ -50,10 +54,15 @@ impl WidgetAttr<TextEdit> for Selectable {
|
|||||||
&id.clone(),
|
&id.clone(),
|
||||||
CursorSense::click_or_drag(),
|
CursorSense::click_or_drag(),
|
||||||
move |client: &mut Client, data| {
|
move |client: &mut Client, data| {
|
||||||
client
|
let now = Instant::now();
|
||||||
.ui
|
let recent = (now - client.last_click) < Duration::from_millis(300);
|
||||||
.text(&id)
|
client.last_click = now;
|
||||||
.select(data.cursor, data.size, data.sense.is_dragging());
|
client.ui.text(&id).select(
|
||||||
|
data.cursor,
|
||||||
|
data.size,
|
||||||
|
data.sense.is_dragging(),
|
||||||
|
recent,
|
||||||
|
);
|
||||||
if let Some(region) = client.ui.window_region(&id) {
|
if let Some(region) = client.ui.window_region(&id) {
|
||||||
client.window.set_ime_allowed(true);
|
client.window.set_ime_allowed(true);
|
||||||
client.window.set_ime_cursor_area(
|
client.window.set_ime_cursor_area(
|
||||||
@@ -249,16 +258,15 @@ impl Client {
|
|||||||
focus: None,
|
focus: None,
|
||||||
clipboard: Clipboard::new().unwrap(),
|
clipboard: Clipboard::new().unwrap(),
|
||||||
ime: 0,
|
ime: 0,
|
||||||
|
last_click: Instant::now(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop) {
|
pub fn event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop) {
|
||||||
let input_changed = self.input.event(&event);
|
let input_changed = self.input.event(&event);
|
||||||
let cursor_state = self.cursor_state().clone();
|
let cursor_state = self.cursor_state().clone();
|
||||||
if let Some(focus) = &self.focus
|
let old = self.focus.clone();
|
||||||
&& cursor_state.buttons.left.is_start()
|
if cursor_state.buttons.left.is_start() {
|
||||||
{
|
|
||||||
self.ui.text(focus).deselect();
|
|
||||||
self.focus = None;
|
self.focus = None;
|
||||||
}
|
}
|
||||||
if input_changed {
|
if input_changed {
|
||||||
@@ -266,6 +274,11 @@ impl Client {
|
|||||||
self.run_sensors(&cursor_state, window_size);
|
self.run_sensors(&cursor_state, window_size);
|
||||||
self.ui.run_sensors(&cursor_state, window_size);
|
self.ui.run_sensors(&cursor_state, window_size);
|
||||||
}
|
}
|
||||||
|
if old != self.focus
|
||||||
|
&& let Some(old) = old
|
||||||
|
{
|
||||||
|
self.ui.text(&old).deselect();
|
||||||
|
}
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::CloseRequested => event_loop.exit(),
|
WindowEvent::CloseRequested => event_loop.exit(),
|
||||||
WindowEvent::RedrawRequested => {
|
WindowEvent::RedrawRequested => {
|
||||||
|
|||||||
@@ -163,10 +163,7 @@ impl<'a> TextEditCtx<'a> {
|
|||||||
|
|
||||||
pub fn motion(&mut self, motion: Motion) {
|
pub fn motion(&mut self, motion: Motion) {
|
||||||
if let TextSelection::Pos(cursor) = self.text.selection
|
if let TextSelection::Pos(cursor) = self.text.selection
|
||||||
&& let Some((cursor, _)) =
|
&& let Some(cursor) = self.buf_motion(cursor, motion)
|
||||||
self.text
|
|
||||||
.buf
|
|
||||||
.cursor_motion(self.font_system, cursor, None, motion)
|
|
||||||
{
|
{
|
||||||
self.text.selection = TextSelection::Pos(cursor);
|
self.text.selection = TextSelection::Pos(cursor);
|
||||||
} else if let TextSelection::Span { start, end } = self.text.selection {
|
} else if let TextSelection::Span { start, end } = self.text.selection {
|
||||||
@@ -275,11 +272,7 @@ impl<'a> TextEditCtx<'a> {
|
|||||||
{
|
{
|
||||||
if word {
|
if word {
|
||||||
let start = *cursor;
|
let start = *cursor;
|
||||||
if let Some((end, _)) =
|
if let Some(end) = self.buf_motion(start, Motion::RightWord) {
|
||||||
self.text
|
|
||||||
.buf
|
|
||||||
.cursor_motion(self.font_system, start, None, Motion::RightWord)
|
|
||||||
{
|
|
||||||
self.delete_between(start, end);
|
self.delete_between(start, end);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -303,7 +296,23 @@ impl<'a> TextEditCtx<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select(&mut self, pos: Vec2, size: Vec2, drag: bool) {
|
fn buf_motion(&mut self, cursor: Cursor, motion: Motion) -> Option<Cursor> {
|
||||||
|
self.text
|
||||||
|
.buf
|
||||||
|
.cursor_motion(self.font_system, cursor, None, motion)
|
||||||
|
.map(|r| r.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_word_at(&mut self, cursor: Cursor) {
|
||||||
|
if let (Some(start), Some(end)) = (
|
||||||
|
self.buf_motion(cursor, Motion::LeftWord),
|
||||||
|
self.buf_motion(cursor, Motion::RightWord),
|
||||||
|
) {
|
||||||
|
self.text.selection = TextSelection::Span { start, end };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select(&mut self, pos: Vec2, size: Vec2, drag: bool, recent: bool) {
|
||||||
let pos = pos - self.text.region().top_left().to_abs(size);
|
let pos = pos - self.text.region().top_left().to_abs(size);
|
||||||
let hit = self.text.buf.hit(pos.x, pos.y);
|
let hit = self.text.buf.hit(pos.x, pos.y);
|
||||||
let sel = &mut self.text.selection;
|
let sel = &mut self.text.selection;
|
||||||
@@ -316,7 +325,13 @@ impl<'a> TextEditCtx<'a> {
|
|||||||
TextSelection::Pos(pos) => match (hit, drag) {
|
TextSelection::Pos(pos) => match (hit, drag) {
|
||||||
(None, false) => *sel = TextSelection::None,
|
(None, false) => *sel = TextSelection::None,
|
||||||
(None, true) => (),
|
(None, true) => (),
|
||||||
(Some(hit), false) => *pos = hit,
|
(Some(hit), false) => {
|
||||||
|
if recent && hit == *pos {
|
||||||
|
return self.select_word_at(hit);
|
||||||
|
} else {
|
||||||
|
*pos = hit
|
||||||
|
}
|
||||||
|
}
|
||||||
(Some(end), true) => *sel = TextSelection::Span { start: *pos, end },
|
(Some(end), true) => *sel = TextSelection::Span { start: *pos, end },
|
||||||
},
|
},
|
||||||
TextSelection::Span { start, end } => match (hit, drag) {
|
TextSelection::Span { start, end } => match (hit, drag) {
|
||||||
|
|||||||
@@ -33,6 +33,12 @@ pub struct WidgetId<W = AnyWidget> {
|
|||||||
_pd: PhantomData<W>,
|
_pd: PhantomData<W>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<W> PartialEq for WidgetId<W> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.ty == other.ty && self.id == other.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A WidgetId for a static widget that cannot be removed from a Ui.
|
/// A WidgetId for a static widget that cannot be removed from a Ui.
|
||||||
/// Useful because ergonomic clones don't exist yet so you can easily use these in closures.
|
/// Useful because ergonomic clones don't exist yet so you can easily use these in closures.
|
||||||
/// Do not use this if you want the widget to be freeable.
|
/// Do not use this if you want the widget to be freeable.
|
||||||
|
|||||||
Reference in New Issue
Block a user