Skip to content
This repository has been archived by the owner on Jul 23, 2019. It is now read-only.

Add mouse "click and drag" to select text #107

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions xray_core/src/buffer_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ enum BufferViewAction {
SelectDown,
SelectLeft,
SelectRight,
SelectTo {
row: u32,
column: u32,
},
SelectToBeginningOfWord,
SelectToEndOfWord,
SelectToBeginningOfLine,
Expand Down Expand Up @@ -509,6 +513,20 @@ impl BufferView {
self.autoscroll_to_cursor(false);
}

pub fn select_to(&mut self, position: Point) {
self.buffer
.borrow_mut()
.mutate_selections(self.selection_set_id, |buffer, selections| {
for selection in selections.iter_mut() {
let anchor = buffer.anchor_before_point(position).unwrap();
selection.set_head(buffer, anchor);
selection.goal_column = None;
}
})
.unwrap();
self.autoscroll_to_cursor(false);
}

pub fn move_up(&mut self) {
self.buffer
.borrow_mut()
Expand Down Expand Up @@ -1086,6 +1104,10 @@ impl View for BufferView {
Ok(BufferViewAction::SelectDown) => self.select_down(),
Ok(BufferViewAction::SelectLeft) => self.select_left(),
Ok(BufferViewAction::SelectRight) => self.select_right(),
Ok(BufferViewAction::SelectTo {
row,
column
}) => self.select_to(Point::new(row, column)),
Ok(BufferViewAction::SelectToBeginningOfWord) => self.select_to_beginning_of_word(),
Ok(BufferViewAction::SelectToEndOfWord) => self.select_to_end_of_word(),
Ok(BufferViewAction::SelectToBeginningOfLine) => self.select_to_beginning_of_line(),
Expand Down Expand Up @@ -1300,6 +1322,27 @@ mod tests {
editor.move_up();
editor.move_up();
assert_eq!(render_selections(&editor), vec![empty_selection(0, 1)]);

// Select to a direct point in front of cursor position
editor.select_to(Point::new(1, 0));
assert_eq!(render_selections(&editor), vec![selection((0, 1), (1, 0))]);
editor.move_right(); // cancel selection
assert_eq!(render_selections(&editor), vec![empty_selection(1, 0)]);
editor.move_right();
editor.move_right();
assert_eq!(render_selections(&editor), vec![empty_selection(2, 1)]);

// Selection can even go to a point before the cursor (with reverse)
editor.select_to(Point::new(0, 0));
assert_eq!(render_selections(&editor), vec![rev_selection((0, 0), (2, 1))]);

// A selection can switch to a new point and the selection will update
editor.select_to(Point::new(0, 3));
assert_eq!(render_selections(&editor), vec![rev_selection((0, 3), (2, 1))]);

// A selection can even swing around the cursor without having to unselect
editor.select_to(Point::new(2, 3));
assert_eq!(render_selections(&editor), vec![selection((2, 1), (2, 3))]);
}

#[test]
Expand Down
82 changes: 59 additions & 23 deletions xray_ui/lib/text_editor/text_editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class TextEditor extends React.Component {

constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.handleMouseUp = this.handleMouseUp.bind(this);
this.handleMouseDown = this.handleMouseDown.bind(this);
this.handleMouseWheel = this.handleMouseWheel.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
Expand All @@ -47,7 +49,7 @@ class TextEditor extends React.Component {
CURSOR_BLINK_RESUME_DELAY
);
this.paddingLeft = 5;
this.state = { scrollLeft: 0, showLocalCursors: true };
this.state = { scrollLeft: 0, showLocalCursors: true, mouseDown: false };
}

componentDidMount() {
Expand All @@ -70,6 +72,12 @@ class TextEditor extends React.Component {
}

element.addEventListener("wheel", this.handleMouseWheel, { passive: true });
element.addEventListener("mousemove", this.handleMouseMove, {
passive: true
});
element.addEventListener("mouseup", this.handleMouseUp, {
passive: true
});
element.addEventListener("mousedown", this.handleMouseDown, {
passive: true
});
Expand Down Expand Up @@ -210,21 +218,7 @@ class TextEditor extends React.Component {
);
}

handleMouseDown(event) {
if (this.canUseTextPlane()) {
this.handleClick(event);
switch (event.detail) {
case 2:
this.handleDoubleClick();
break;
case 3:
this.handleTripleClick();
break;
}
}
}

handleClick({ clientX, clientY }) {
getPositionFromMouseEvent({ clientX, clientY}) {
const { scroll_top, line_height, first_visible_row, lines } = this.props;
const { scrollLeft } = this.state;
const targetX =
Expand All @@ -245,14 +239,56 @@ class TextEditor extends React.Component {
break;
}
}
return { row, column }
} else {
return null;
}
}

this.pauseCursorBlinking();
this.props.dispatch({
type: "SetCursorPosition",
row,
column,
autoscroll: false
});
handleMouseMove(event) {
if (this.canUseTextPlane() && this.state.mouseDown) {
const pos = this.getPositionFromMouseEvent(event);
if (pos) {
this.props.dispatch(Object.assign({
type: "SelectTo",
}, pos));
}
}
}

handleMouseUp(ecent) {
this.setState({mouseDown: false})
}

handleMouseDown(event) {
this.setState({mouseDown: true})
if (this.canUseTextPlane()) {
this.handleClick(event);
switch (event.detail) {
case 2:
this.handleDoubleClick();
break;
case 3:
this.handleTripleClick();
break;
}
}
}

handleClick(event) {
this.pauseCursorBlinking();
const pos = this.getPositionFromMouseEvent(event);
if (pos) {
if (event.shiftKey) {
this.props.dispatch(Object.assign({
type: "SelectTo"
}, pos));
} else {
this.props.dispatch(Object.assign({
type: "SetCursorPosition",
autoscroll: false
}, pos));
}
}
}

Expand Down