Apply TextEdit IME on most actions
This commit is contained in:
parent
fa48a51183
commit
a6af442b05
7 changed files with 112 additions and 57 deletions
|
@ -101,6 +101,12 @@
|
|||
Adjust the viewport so the caret is visible.
|
||||
</description>
|
||||
</method>
|
||||
<method name="apply_ime">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Applies text from the [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url] (IME) to each caret and closes the IME if it is open.
|
||||
</description>
|
||||
</method>
|
||||
<method name="backspace">
|
||||
<return type="void" />
|
||||
<param index="0" name="caret_index" type="int" default="-1" />
|
||||
|
@ -114,6 +120,12 @@
|
|||
Starts a multipart edit. All edits will be treated as one action until [method end_complex_operation] is called.
|
||||
</description>
|
||||
</method>
|
||||
<method name="cancel_ime">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Closes the [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url] (IME) if it is open. Any text in the IME will be lost.
|
||||
</description>
|
||||
</method>
|
||||
<method name="center_viewport_to_caret">
|
||||
<return type="void" />
|
||||
<param index="0" name="caret_index" type="int" default="0" />
|
||||
|
@ -611,7 +623,7 @@
|
|||
<method name="has_ime_text" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns if the user has IME text.
|
||||
Returns [code]true[/code] if the user has text in the [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url] (IME).
|
||||
</description>
|
||||
</method>
|
||||
<method name="has_redo" qualifiers="const">
|
||||
|
|
|
@ -1270,6 +1270,7 @@ void ScriptTextEditor::_gutter_clicked(int p_line, int p_gutter) {
|
|||
|
||||
void ScriptTextEditor::_edit_option(int p_op) {
|
||||
CodeEdit *tx = code_editor->get_text_editor();
|
||||
tx->apply_ime();
|
||||
|
||||
switch (p_op) {
|
||||
case EDIT_UNDO: {
|
||||
|
@ -1960,6 +1961,8 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
|
|||
}
|
||||
|
||||
if (create_menu) {
|
||||
tx->apply_ime();
|
||||
|
||||
Point2i pos = tx->get_line_column_at_pos(local_pos);
|
||||
int row = pos.y;
|
||||
int col = pos.x;
|
||||
|
|
|
@ -348,6 +348,7 @@ void TextEditor::set_find_replace_bar(FindReplaceBar *p_bar) {
|
|||
|
||||
void TextEditor::_edit_option(int p_op) {
|
||||
CodeEdit *tx = code_editor->get_text_editor();
|
||||
tx->apply_ime();
|
||||
|
||||
switch (p_op) {
|
||||
case EDIT_UNDO: {
|
||||
|
@ -502,6 +503,8 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
|
|||
if (mb->get_button_index() == MouseButton::RIGHT) {
|
||||
CodeEdit *tx = code_editor->get_text_editor();
|
||||
|
||||
tx->apply_ime();
|
||||
|
||||
Point2i pos = tx->get_line_column_at_pos(mb->get_global_position() - tx->get_global_position());
|
||||
int row = pos.y;
|
||||
int col = pos.x;
|
||||
|
|
|
@ -628,6 +628,8 @@ ShaderTextEditor::ShaderTextEditor() {
|
|||
/*** SCRIPT EDITOR ******/
|
||||
|
||||
void TextShaderEditor::_menu_option(int p_option) {
|
||||
shader_editor->get_text_editor()->apply_ime();
|
||||
|
||||
switch (p_option) {
|
||||
case EDIT_UNDO: {
|
||||
shader_editor->get_text_editor()->undo();
|
||||
|
@ -978,6 +980,8 @@ void TextShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
|
|||
if (mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
|
||||
CodeEdit *tx = shader_editor->get_text_editor();
|
||||
|
||||
tx->apply_ime();
|
||||
|
||||
Point2i pos = tx->get_line_column_at_pos(mb->get_global_position() - tx->get_global_position());
|
||||
int row = pos.y;
|
||||
int col = pos.x;
|
||||
|
|
|
@ -253,8 +253,9 @@ void CodeEdit::_notification(int p_what) {
|
|||
void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
|
||||
Ref<InputEventMouseButton> mb = p_gui_input;
|
||||
if (mb.is_valid()) {
|
||||
/* Ignore mouse clicks in IME input mode. */
|
||||
// Ignore mouse clicks in IME input mode, let TextEdit handle it.
|
||||
if (has_ime_text()) {
|
||||
TextEdit::gui_input(p_gui_input);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1489,14 +1489,7 @@ void TextEdit::_notification(int p_what) {
|
|||
}
|
||||
|
||||
if (has_focus()) {
|
||||
if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
|
||||
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
|
||||
Point2 pos = get_global_position() + get_caret_draw_pos();
|
||||
if (get_window()->get_embedder()) {
|
||||
pos += get_viewport()->get_popup_base_transform().get_origin();
|
||||
}
|
||||
DisplayServer::get_singleton()->window_set_ime_position(pos, get_viewport()->get_window_id());
|
||||
}
|
||||
_update_ime_window_position();
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -1507,14 +1500,7 @@ void TextEdit::_notification(int p_what) {
|
|||
draw_caret = true;
|
||||
}
|
||||
|
||||
if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
|
||||
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
|
||||
Point2 pos = get_global_position() + get_caret_draw_pos();
|
||||
if (get_window()->get_embedder()) {
|
||||
pos += get_viewport()->get_popup_base_transform().get_origin();
|
||||
}
|
||||
DisplayServer::get_singleton()->window_set_ime_position(pos, get_viewport()->get_window_id());
|
||||
}
|
||||
_update_ime_window_position();
|
||||
|
||||
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
|
||||
int caret_start = -1;
|
||||
|
@ -1541,17 +1527,7 @@ void TextEdit::_notification(int p_what) {
|
|||
caret_blink_timer->stop();
|
||||
}
|
||||
|
||||
if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
|
||||
DisplayServer::get_singleton()->window_set_ime_position(Point2(), get_viewport()->get_window_id());
|
||||
DisplayServer::get_singleton()->window_set_ime_active(false, get_viewport()->get_window_id());
|
||||
}
|
||||
if (!ime_text.is_empty()) {
|
||||
ime_text = "";
|
||||
ime_selection = Point2();
|
||||
for (int i = 0; i < carets.size(); i++) {
|
||||
text.invalidate_cache(get_caret_line(i), get_caret_column(i), true, ime_text);
|
||||
}
|
||||
}
|
||||
apply_ime();
|
||||
|
||||
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
|
||||
DisplayServer::get_singleton()->virtual_keyboard_hide();
|
||||
|
@ -1571,15 +1547,8 @@ void TextEdit::_notification(int p_what) {
|
|||
delete_selection();
|
||||
}
|
||||
|
||||
for (int i = 0; i < carets.size(); i++) {
|
||||
String t;
|
||||
if (get_caret_column(i) >= 0) {
|
||||
t = text[get_caret_line(i)].substr(0, get_caret_column(i)) + ime_text + text[get_caret_line(i)].substr(get_caret_column(i), text[get_caret_line(i)].length());
|
||||
} else {
|
||||
t = ime_text;
|
||||
}
|
||||
text.invalidate_cache(get_caret_line(i), get_caret_column(i), true, t, structured_text_parser(st_parser, st_args, t));
|
||||
}
|
||||
_update_ime_text();
|
||||
adjust_viewport_to_caret(0);
|
||||
queue_redraw();
|
||||
}
|
||||
} break;
|
||||
|
@ -1681,10 +1650,6 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
|
|||
if (is_layout_rtl()) {
|
||||
mpos.x = get_size().x - mpos.x;
|
||||
}
|
||||
if (ime_text.length() != 0) {
|
||||
// Ignore mouse clicks in IME input mode.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mb->is_pressed()) {
|
||||
if (mb->get_button_index() == MouseButton::WHEEL_UP && !mb->is_command_or_control_pressed()) {
|
||||
|
@ -1718,6 +1683,8 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
|
|||
if (mb->get_button_index() == MouseButton::LEFT) {
|
||||
_reset_caret_blink_timer();
|
||||
|
||||
apply_ime();
|
||||
|
||||
Point2i pos = get_line_column_at_pos(mpos);
|
||||
int row = pos.y;
|
||||
int col = pos.x;
|
||||
|
@ -1865,11 +1832,13 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
|
|||
}
|
||||
|
||||
if (is_middle_mouse_paste_enabled() && mb->get_button_index() == MouseButton::MIDDLE && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) {
|
||||
apply_ime();
|
||||
paste_primary_clipboard();
|
||||
}
|
||||
|
||||
if (mb->get_button_index() == MouseButton::RIGHT && (context_menu_enabled || is_move_caret_on_right_click_enabled())) {
|
||||
_reset_caret_blink_timer();
|
||||
apply_ime();
|
||||
|
||||
Point2i pos = get_line_column_at_pos(mpos);
|
||||
int row = pos.y;
|
||||
|
@ -1909,6 +1878,11 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if (has_ime_text()) {
|
||||
// Ignore mouse up in IME input mode.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mb->get_button_index() == MouseButton::LEFT) {
|
||||
if (selection_drag_attempt && is_mouse_over_selection()) {
|
||||
remove_secondary_carets();
|
||||
|
@ -1967,7 +1941,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
|
|||
_update_minimap_drag();
|
||||
}
|
||||
|
||||
if (!dragging_minimap) {
|
||||
if (!dragging_minimap && !has_ime_text()) {
|
||||
switch (selecting_mode) {
|
||||
case SelectionMode::SELECTION_MODE_POINTER: {
|
||||
_update_selection_mode_pointer();
|
||||
|
@ -2012,6 +1986,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
|
|||
}
|
||||
|
||||
if (drag_action && can_drop_data(mpos, get_viewport()->gui_get_drag_data())) {
|
||||
apply_ime();
|
||||
drag_caret_force_displayed = true;
|
||||
Point2i pos = get_line_column_at_pos(get_local_mouse_pos());
|
||||
set_caret_line(pos.y, false, true, 0, 0);
|
||||
|
@ -3030,6 +3005,43 @@ void TextEdit::_update_caches() {
|
|||
}
|
||||
}
|
||||
|
||||
void TextEdit::_close_ime_window() {
|
||||
if (get_viewport()->get_window_id() == DisplayServer::INVALID_WINDOW_ID || !DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
|
||||
return;
|
||||
}
|
||||
DisplayServer::get_singleton()->window_set_ime_position(Point2(), get_viewport()->get_window_id());
|
||||
DisplayServer::get_singleton()->window_set_ime_active(false, get_viewport()->get_window_id());
|
||||
}
|
||||
|
||||
void TextEdit::_update_ime_window_position() {
|
||||
if (get_viewport()->get_window_id() == DisplayServer::INVALID_WINDOW_ID || !DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
|
||||
return;
|
||||
}
|
||||
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
|
||||
Point2 pos = get_global_position() + get_caret_draw_pos();
|
||||
if (get_window()->get_embedder()) {
|
||||
pos += get_viewport()->get_popup_base_transform().get_origin();
|
||||
}
|
||||
// The window will move to the updated position the next time the IME is updated, not immediately.
|
||||
DisplayServer::get_singleton()->window_set_ime_position(pos, get_viewport()->get_window_id());
|
||||
}
|
||||
|
||||
void TextEdit::_update_ime_text() {
|
||||
if (has_ime_text()) {
|
||||
// Update text to visually include IME text.
|
||||
for (int i = 0; i < get_caret_count(); i++) {
|
||||
String text_with_ime = text[get_caret_line(i)].substr(0, get_caret_column(i)) + ime_text + text[get_caret_line(i)].substr(get_caret_column(i), text[get_caret_line(i)].length());
|
||||
text.invalidate_cache(get_caret_line(i), get_caret_column(i), true, text_with_ime, structured_text_parser(st_parser, st_args, text_with_ime));
|
||||
}
|
||||
} else {
|
||||
// Reset text.
|
||||
for (int i = 0; i < get_caret_count(); i++) {
|
||||
text.invalidate_cache(get_caret_line(i), get_caret_column(i), true);
|
||||
}
|
||||
}
|
||||
queue_redraw();
|
||||
}
|
||||
|
||||
/* General overrides. */
|
||||
Size2 TextEdit::get_minimum_size() const {
|
||||
Size2 size = theme_cache.style_normal->get_minimum_size();
|
||||
|
@ -3189,6 +3201,26 @@ bool TextEdit::has_ime_text() const {
|
|||
return !ime_text.is_empty();
|
||||
}
|
||||
|
||||
void TextEdit::cancel_ime() {
|
||||
if (!has_ime_text()) {
|
||||
return;
|
||||
}
|
||||
ime_text = String();
|
||||
ime_selection = Point2();
|
||||
_close_ime_window();
|
||||
_update_ime_text();
|
||||
}
|
||||
|
||||
void TextEdit::apply_ime() {
|
||||
if (!has_ime_text()) {
|
||||
return;
|
||||
}
|
||||
// Force apply the current IME text.
|
||||
String insert_ime_text = ime_text;
|
||||
cancel_ime();
|
||||
insert_text_at_caret(insert_ime_text);
|
||||
}
|
||||
|
||||
void TextEdit::set_editable(const bool p_editable) {
|
||||
if (editable == p_editable) {
|
||||
return;
|
||||
|
@ -3568,16 +3600,8 @@ void TextEdit::insert_text_at_caret(const String &p_text, int p_caret) {
|
|||
adjust_carets_after_edit(i, new_line, new_column, from_line, from_col);
|
||||
}
|
||||
|
||||
if (!ime_text.is_empty()) {
|
||||
for (int i = 0; i < carets.size(); i++) {
|
||||
String t;
|
||||
if (get_caret_column(i) >= 0) {
|
||||
t = text[get_caret_line(i)].substr(0, get_caret_column(i)) + ime_text + text[get_caret_line(i)].substr(get_caret_column(i), text[get_caret_line(i)].length());
|
||||
} else {
|
||||
t = ime_text;
|
||||
}
|
||||
text.invalidate_cache(get_caret_line(i), get_caret_column(i), true, t, structured_text_parser(st_parser, st_args, t));
|
||||
}
|
||||
if (has_ime_text()) {
|
||||
_update_ime_text();
|
||||
}
|
||||
|
||||
end_complex_operation();
|
||||
|
@ -5560,14 +5584,14 @@ void TextEdit::adjust_viewport_to_caret(int p_caret) {
|
|||
Vector2i caret_pos;
|
||||
|
||||
// Get position of the start of caret.
|
||||
if (ime_text.length() != 0 && ime_selection.x != 0) {
|
||||
if (has_ime_text() && ime_selection.x != 0) {
|
||||
caret_pos.x = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x, get_caret_line(p_caret), get_caret_column(p_caret));
|
||||
} else {
|
||||
caret_pos.x = _get_column_x_offset_for_line(get_caret_column(p_caret), get_caret_line(p_caret), get_caret_column(p_caret));
|
||||
}
|
||||
|
||||
// Get position of the end of caret.
|
||||
if (ime_text.length() != 0) {
|
||||
if (has_ime_text()) {
|
||||
if (ime_selection.y != 0) {
|
||||
caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x + ime_selection.y, get_caret_line(p_caret), get_caret_column(p_caret));
|
||||
} else {
|
||||
|
@ -5612,14 +5636,14 @@ void TextEdit::center_viewport_to_caret(int p_caret) {
|
|||
Vector2i caret_pos;
|
||||
|
||||
// Get position of the start of caret.
|
||||
if (ime_text.length() != 0 && ime_selection.x != 0) {
|
||||
if (has_ime_text() && ime_selection.x != 0) {
|
||||
caret_pos.x = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x, get_caret_line(p_caret), get_caret_column(p_caret));
|
||||
} else {
|
||||
caret_pos.x = _get_column_x_offset_for_line(get_caret_column(p_caret), get_caret_line(p_caret), get_caret_column(p_caret));
|
||||
}
|
||||
|
||||
// Get position of the end of caret.
|
||||
if (ime_text.length() != 0) {
|
||||
if (has_ime_text()) {
|
||||
if (ime_selection.y != 0) {
|
||||
caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x + ime_selection.y, get_caret_line(p_caret), get_caret_column(p_caret));
|
||||
} else {
|
||||
|
@ -6029,6 +6053,8 @@ void TextEdit::_bind_methods() {
|
|||
/* Text */
|
||||
// Text properties
|
||||
ClassDB::bind_method(D_METHOD("has_ime_text"), &TextEdit::has_ime_text);
|
||||
ClassDB::bind_method(D_METHOD("cancel_ime"), &TextEdit::cancel_ime);
|
||||
ClassDB::bind_method(D_METHOD("apply_ime"), &TextEdit::apply_ime);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_editable", "enabled"), &TextEdit::set_editable);
|
||||
ClassDB::bind_method(D_METHOD("is_editable"), &TextEdit::is_editable);
|
||||
|
|
|
@ -293,6 +293,10 @@ private:
|
|||
void _clear();
|
||||
void _update_caches();
|
||||
|
||||
void _close_ime_window();
|
||||
void _update_ime_window_position();
|
||||
void _update_ime_text();
|
||||
|
||||
// User control.
|
||||
bool overtype_mode = false;
|
||||
bool context_menu_enabled = true;
|
||||
|
@ -696,6 +700,8 @@ public:
|
|||
/* Text */
|
||||
// Text properties.
|
||||
bool has_ime_text() const;
|
||||
void cancel_ime();
|
||||
void apply_ime();
|
||||
|
||||
void set_editable(const bool p_editable);
|
||||
bool is_editable() const;
|
||||
|
|
Loading…
Add table
Reference in a new issue