Skip to content

Commit

Permalink
Drag selection remembers click count
Browse files Browse the repository at this point in the history
This implements the behaviour where the selection behaviour
of a drag gesture varies depending on whether the drag starts
from a single, double, or triple-click.

- closes #1570
  • Loading branch information
cmyr committed Mar 18, 2021
1 parent 076bb04 commit fd34ed6
Showing 1 changed file with 55 additions and 4 deletions.
59 changes: 55 additions & 4 deletions druid/src/text/input_component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ pub struct EditSession<T> {
alignment_offset: f64,
/// The portion of the text that is currently marked by the IME.
composition_range: Option<Range<usize>>,
drag_granularity: DragGranularity,
/// The origin of the textbox, relative to the origin of the window.
pub origin: Point,
}
Expand All @@ -123,6 +124,23 @@ struct EditSessionHandle<T> {
inner: Arc<RefCell<EditSession<T>>>,
}

/// When a drag follows a double- or triple-click, the behaviour of
/// drag changes to only select whole words or whole paragraphs.
#[derive(Debug, Clone, Copy, PartialEq)]
enum DragGranularity {
Grapheme,
/// Start and end are the start/end bounds of the initial selection.
Word {
start: usize,
end: usize,
},
/// Start and end are the start/end bounds of the initial selection.
Paragraph {
start: usize,
end: usize,
},
}

/// An informal lock.
#[derive(Debug, Clone, Copy, PartialEq)]
enum ImeLock {
Expand Down Expand Up @@ -264,6 +282,7 @@ impl<T: TextStorage + EditableText> Widget<T> for TextComponent<T> {
self.borrow_mut()
.update_pending_invalidation(ImeUpdate::SelectionChanged);
ctx.request_update();
ctx.request_paint();
}
Event::MouseMove(mouse) if self.can_write() => {
ctx.set_cursor(&Cursor::IBeam);
Expand Down Expand Up @@ -680,17 +699,48 @@ impl<T: TextStorage + EditableText> EditSession<T> {
if mods.shift() {
self.selection.end = pos;
} else {
let sel = self.sel_region_for_pos(pos, count);
self.selection.start = sel.start;
self.selection.end = sel.end;
let Range { start, end } = self.sel_region_for_pos(pos, count);
self.selection.start = start;
self.selection.end = end;
self.drag_granularity = match count {
2 => DragGranularity::Word { start, end },
3 => DragGranularity::Paragraph { start, end },
_ => DragGranularity::Grapheme,
};
}
}

fn do_drag(&mut self, point: Point) {
let point = point + Vec2::new(self.alignment_offset, 0.0);
//FIXME: this should behave differently if we were double or triple clicked
let pos = self.layout.text_position_for_point(point);
self.selection.end = pos;
let text = match self.layout.text() {
Some(text) => text,
None => return,
};

let (start, end) = match self.drag_granularity {
DragGranularity::Grapheme => (self.selection.start, pos),
DragGranularity::Word { start, end } => {
let word_range = self.word_for_pos(pos);
if pos <= start {
(end, word_range.start)
} else {
(start, word_range.end)
}
}
DragGranularity::Paragraph { start, end } => {
let par_start = text.preceding_line_break(pos);
let par_end = text.next_line_break(pos);

if pos <= start {
(end, par_start)
} else {
(start, par_end)
}
}
};
self.selection = Selection::new(start, end);
self.scroll_to_selection_end(false);
}

Expand Down Expand Up @@ -860,6 +910,7 @@ impl<T> Default for TextComponent<T> {
accepts_tabs: false,
alignment: TextAlignment::Start,
alignment_offset: 0.0,
drag_granularity: DragGranularity::Grapheme,
origin: Point::ZERO,
};

Expand Down

0 comments on commit fd34ed6

Please sign in to comment.