Browse Source

Merge pull request #12662 from Paulb23/text_edit_mouse_selection

Changed line and word mouse selection
Rémi Verschelde 7 years ago
parent
commit
d4e37ef198
2 changed files with 137 additions and 59 deletions
  1. 129 58
      scene/gui/text_edit.cpp
  2. 8 1
      scene/gui/text_edit.h

+ 129 - 58
scene/gui/text_edit.cpp

@@ -376,24 +376,116 @@ void TextEdit::_update_scrollbars() {
 void TextEdit::_click_selection_held() {
 
 	if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && selection.selecting_mode != Selection::MODE_NONE) {
+		switch (selection.selecting_mode) {
+			case Selection::MODE_POINTER: {
+				_update_selection_mode_pointer();
+			} break;
+			case Selection::MODE_WORD: {
+				_update_selection_mode_word();
+			} break;
+			case Selection::MODE_LINE: {
+				_update_selection_mode_line();
+			} break;
+			default: {
+				break;
+			}
+		}
+	} else {
+		click_select_held->stop();
+	}
+}
 
-		Point2 mp = Input::get_singleton()->get_mouse_position() - get_global_position();
+void TextEdit::_update_selection_mode_pointer() {
+	Point2 mp = Input::get_singleton()->get_mouse_position() - get_global_position();
 
-		int row, col;
-		_get_mouse_pos(Point2i(mp.x, mp.y), row, col);
+	int row, col;
+	_get_mouse_pos(Point2i(mp.x, mp.y), row, col);
 
-		select(selection.selecting_line, selection.selecting_column, row, col);
+	select(selection.selecting_line, selection.selecting_column, row, col);
 
-		cursor_set_line(row);
-		cursor_set_column(col);
-		update();
+	cursor_set_line(row);
+	cursor_set_column(col);
+	update();
+
+	click_select_held->start();
+}
+
+void TextEdit::_update_selection_mode_word() {
+	Point2 mp = Input::get_singleton()->get_mouse_position() - get_global_position();
+
+	int row, col;
+	_get_mouse_pos(Point2i(mp.x, mp.y), row, col);
 
-		click_select_held->start();
+	String line = text[row];
+	int beg = CLAMP(col, 0, line.length());
+	// if its the first selection and on whitespace make sure we grab the word instead..
+	if (!selection.active) {
+		while (beg > 0 && line[beg] <= 32) {
+			beg--;
+		}
+	}
+	int end = beg;
+	bool symbol = beg < line.length() && _is_symbol(line[beg]);
+
+	// get the word end and begin points
+	while (beg > 0 && line[beg - 1] > 32 && (symbol == _is_symbol(line[beg - 1]))) {
+		beg--;
+	}
+	while (end < line.length() && line[end + 1] > 32 && (symbol == _is_symbol(line[end + 1]))) {
+		end++;
+	}
+	if (end < line.length()) {
+		end += 1;
+	}
 
+	// inital selection
+	if (!selection.active) {
+		select(row, beg, row, end);
+		selection.selecting_column = beg;
+		selection.selected_word_beg = beg;
+		selection.selected_word_end = end;
+		selection.selected_word_origin = beg;
+		cursor_set_column(selection.to_column);
 	} else {
+		if ((col <= selection.selected_word_origin && row == selection.selecting_line) || row < selection.selecting_line) {
+			selection.selecting_column = selection.selected_word_end;
+			select(row, beg, selection.selecting_line, selection.selected_word_end);
+			cursor_set_column(selection.from_column);
+		} else {
+			selection.selecting_column = selection.selected_word_beg;
+			select(selection.selecting_line, selection.selected_word_beg, row, end);
+			cursor_set_column(selection.to_column);
+		}
+	}
+	cursor_set_line(row);
 
-		click_select_held->stop();
+	update();
+	click_select_held->start();
+}
+
+void TextEdit::_update_selection_mode_line() {
+	Point2 mp = Input::get_singleton()->get_mouse_position() - get_global_position();
+
+	int row, col;
+	_get_mouse_pos(Point2i(mp.x, mp.y), row, col);
+
+	col = 0;
+	if (row < selection.selecting_line) {
+		// cursor is above us
+		cursor_set_line(row - 1);
+		selection.selecting_column = text[selection.selecting_line].length();
+	} else {
+		// cursor is below us
+		cursor_set_line(row + 1);
+		selection.selecting_column = 0;
+		col = text[row].length();
 	}
+	cursor_set_column(0);
+
+	select(selection.selecting_line, selection.selecting_column, row, col);
+	update();
+
+	click_select_held->start();
 }
 
 void TextEdit::_notification(int p_what) {
@@ -1759,36 +1851,15 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
 
 				if (!mb->is_doubleclick() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < 600 && cursor.line == prev_line) {
 					//tripleclick select line
-					select(cursor.line, 0, cursor.line, text[cursor.line].length());
-					selection.selecting_column = 0;
+					selection.selecting_mode = Selection::MODE_LINE;
+					_update_selection_mode_line();
 					last_dblclk = 0;
 
 				} else if (mb->is_doubleclick() && text[cursor.line].length()) {
 
 					//doubleclick select world
-					String s = text[cursor.line];
-					int beg = CLAMP(cursor.column, 0, s.length());
-					int end = beg;
-
-					if (s[beg] > 32 || beg == s.length()) {
-
-						bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this
-
-						while (beg > 0 && s[beg - 1] > 32 && (symbol == _is_symbol(s[beg - 1]))) {
-							beg--;
-						}
-						while (end < s.length() && s[end + 1] > 32 && (symbol == _is_symbol(s[end + 1]))) {
-							end++;
-						}
-
-						if (end < s.length())
-							end += 1;
-
-						select(cursor.line, beg, cursor.line, end);
-
-						selection.selecting_column = beg;
-					}
-
+					selection.selecting_mode = Selection::MODE_WORD;
+					_update_selection_mode_word();
 					last_dblclk = OS::get_singleton()->get_ticks_msec();
 				}
 
@@ -1833,21 +1904,21 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
 		}
 
 		if (mm->get_button_mask() & BUTTON_MASK_LEFT && get_viewport()->gui_get_drag_data() == Variant()) { //ignore if dragging
+			_reset_caret_blink_timer();
 
-			if (selection.selecting_mode != Selection::MODE_NONE) {
-
-				_reset_caret_blink_timer();
-
-				int row, col;
-				_get_mouse_pos(mm->get_position(), row, col);
-
-				select(selection.selecting_line, selection.selecting_column, row, col);
-
-				cursor_set_line(row);
-				cursor_set_column(col);
-				update();
-
-				click_select_held->start();
+			switch (selection.selecting_mode) {
+				case Selection::MODE_POINTER: {
+					_update_selection_mode_pointer();
+				} break;
+				case Selection::MODE_WORD: {
+					_update_selection_mode_word();
+				} break;
+				case Selection::MODE_LINE: {
+					_update_selection_mode_line();
+				} break;
+				default: {
+					break;
+				}
 			}
 		}
 	}
@@ -2847,19 +2918,19 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
 		if (scancode_handled)
 			accept_event();
 		/*
-    if (!scancode_handled && !k->get_command() && !k->get_alt()) {
+	if (!scancode_handled && !k->get_command() && !k->get_alt()) {
 
 	if (k->get_unicode()>=32) {
 
-	    if (readonly)
+		if (readonly)
 		break;
 
-	    accept_event();
+		accept_event();
 	} else {
 
-	    break;
+		break;
+	}
 	}
-    }
 */
 		if (k->get_scancode() == KEY_INSERT) {
 			set_insert_mode(!insert_mode);
@@ -3251,11 +3322,11 @@ void TextEdit::adjust_viewport_to_cursor() {
 
 	update();
 	/*
-    get_range()->set_max(text.size());
+	get_range()->set_max(text.size());
 
-    get_range()->set_page(get_visible_rows());
+	get_range()->set_page(get_visible_rows());
 
-    get_range()->set((int)cursor.line_ofs);
+	get_range()->set((int)cursor.line_ofs);
 */
 }
 
@@ -4815,8 +4886,8 @@ void TextEdit::_bind_methods() {
 	BIND_ENUM_CONSTANT(SEARCH_BACKWARDS);
 
 	/*
-    ClassDB::bind_method(D_METHOD("delete_char"),&TextEdit::delete_char);
-    ClassDB::bind_method(D_METHOD("delete_line"),&TextEdit::delete_line);
+	ClassDB::bind_method(D_METHOD("delete_char"),&TextEdit::delete_char);
+	ClassDB::bind_method(D_METHOD("delete_line"),&TextEdit::delete_line);
 */
 
 	ClassDB::bind_method(D_METHOD("set_text", "text"), &TextEdit::set_text);

+ 8 - 1
scene/gui/text_edit.h

@@ -51,11 +51,14 @@ class TextEdit : public Control {
 
 			MODE_NONE,
 			MODE_SHIFT,
-			MODE_POINTER
+			MODE_POINTER,
+			MODE_WORD,
+			MODE_LINE
 		};
 
 		Mode selecting_mode;
 		int selecting_line, selecting_column;
+		int selected_word_beg, selected_word_end, selected_word_origin;
 		bool selecting_text;
 
 		bool active;
@@ -305,6 +308,10 @@ class TextEdit : public Control {
 	void _v_scroll_input();
 	void _click_selection_held();
 
+	void _update_selection_mode_pointer();
+	void _update_selection_mode_word();
+	void _update_selection_mode_line();
+
 	void _pre_shift_selection();
 	void _post_shift_selection();