Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/interface/interface_handlers.c
| Show First 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | |||||
| #include "WM_api.h" | #include "WM_api.h" | ||||
| #include "WM_types.h" | #include "WM_types.h" | ||||
| #include "wm_event_system.h" | #include "wm_event_system.h" | ||||
| #ifdef WITH_INPUT_IME | #ifdef WITH_INPUT_IME | ||||
| # include "BLT_lang.h" | # include "BLT_lang.h" | ||||
| # include "BLT_translation.h" | # include "BLT_translation.h" | ||||
| # include "wm_window.h" | |||||
| #endif | #endif | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Feature Defines | /** \name Feature Defines | ||||
| * | * | ||||
| * These defines allow developers to locally toggle functionality which | * These defines allow developers to locally toggle functionality which | ||||
| * may be useful for testing (especially conflicts in dragging). | * may be useful for testing (especially conflicts in dragging). | ||||
| * Ideally the code would be refactored to support this functionality in a less fragile way. | * Ideally the code would be refactored to support this functionality in a less fragile way. | ||||
| ▲ Show 20 Lines • Show All 184 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| #ifdef WITH_INPUT_IME | #ifdef WITH_INPUT_IME | ||||
| /* enable ime, and set up uibut ime data */ | void UI_region_ime_position(wmWindow *win, ARegion *region, int x, int y, int h) | ||||
| static void ui_textedit_ime_begin(wmWindow *win, uiBut *UNUSED(but)) | |||||
| { | { | ||||
| /* XXX Is this really needed? */ | ui_region_to_window(region, &x, &y); | ||||
| int x, y; | WM_window_IME_position(win, x, y, h); | ||||
| BLI_assert(win->ime_data == NULL); | |||||
| /* enable IME and position to cursor, it's a trick */ | |||||
| x = win->eventstate->x; | |||||
| /* flip y and move down a bit, prevent the IME panel cover the edit button */ | |||||
| y = win->eventstate->y - 12; | |||||
| wm_window_IME_begin(win, x, y, 0, 0, true); | |||||
| } | } | ||||
| /* disable ime, and clear uibut ime data */ | void ui_but_ime_position(uiBut *but, int x, int y, int h) | ||||
| static void ui_textedit_ime_end(wmWindow *win, uiBut *UNUSED(but)) | |||||
| { | { | ||||
| wm_window_IME_end(win); | |||||
| } | |||||
| void ui_but_ime_reposition(uiBut *but, int x, int y, bool complete) | |||||
| { | |||||
| BLI_assert(but->active); | BLI_assert(but->active); | ||||
| ui_region_to_window(but->active->region, &x, &y); | wmWindow *win = but->active->window; | ||||
| wm_window_IME_begin(but->active->window, x, y - 4, 0, 0, complete); | |||||
| UI_region_ime_position(win, but->active->region, x, y, h); | |||||
| } | } | ||||
| wmIMEData *ui_but_ime_data_get(uiBut *but) | wmIMEData *ui_but_ime_data_get(uiBut *but) | ||||
| { | { | ||||
| if (but->active && but->active->window) { | if (but->active && but->active->window) { | ||||
| return but->active->window->ime_data; | return but->active->window->ime_data; | ||||
| } | } | ||||
| else { | else { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| } | } | ||||
| static bool ui_textedit_delete_ime_composite(uiBut *but, uiHandleButtonData *data) | |||||
| { | |||||
| char *str = data->str; | |||||
| const int len = strlen(str); | |||||
| bool changed = false; | |||||
| if ((but->ime_end > but->ime_start) && (len >= but->ime_end)) { | |||||
| memmove(str + but->ime_start, str + but->ime_end, (len - but->ime_end) + 1); | |||||
| changed = true; | |||||
| } | |||||
| if (but->pos > but->ime_end) { | |||||
| but->pos += but->ime_start - but->ime_end; | |||||
| } | |||||
| else if (but->pos >= but->ime_start) { | |||||
| but->pos = but->ime_start; | |||||
| } | |||||
| but->ime_end = but->ime_start = but->pos; | |||||
| return changed; | |||||
| } | |||||
| #endif /* WITH_INPUT_IME */ | #endif /* WITH_INPUT_IME */ | ||||
| static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) | static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) | ||||
| { | { | ||||
| wmWindow *win = data->window; | wmWindow *win = data->window; | ||||
| const bool is_num_but = ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER); | const bool is_num_but = ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER); | ||||
| bool no_zero_strip = false; | bool no_zero_strip = false; | ||||
| ▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | |||||
| /* reset alert flag (avoid confusion, will refresh on exit) */ | /* reset alert flag (avoid confusion, will refresh on exit) */ | ||||
| but->flag &= ~UI_BUT_REDALERT; | but->flag &= ~UI_BUT_REDALERT; | ||||
| ui_but_update(but); | ui_but_update(but); | ||||
| WM_cursor_modal_set(win, WM_CURSOR_TEXT_EDIT); | WM_cursor_modal_set(win, WM_CURSOR_TEXT_EDIT); | ||||
| #ifdef WITH_INPUT_IME | #ifdef WITH_INPUT_IME | ||||
| if (is_num_but == false && BLT_lang_is_ime_supported()) { | if (!is_num_but) { | ||||
| ui_textedit_ime_begin(win, but); | WM_window_IME_begin(win); | ||||
| } | } | ||||
| #endif | #endif | ||||
| } | } | ||||
| static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data) | static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data) | ||||
| { | { | ||||
| wmWindow *win = data->window; | wmWindow *win = data->window; | ||||
| Show All 35 Lines | |||||
| WM_cursor_modal_restore(win); | WM_cursor_modal_restore(win); | ||||
| /* Free text undo history text blocks. */ | /* Free text undo history text blocks. */ | ||||
| ui_textedit_undo_stack_destroy(data->undo_stack_text); | ui_textedit_undo_stack_destroy(data->undo_stack_text); | ||||
| data->undo_stack_text = NULL; | data->undo_stack_text = NULL; | ||||
| #ifdef WITH_INPUT_IME | #ifdef WITH_INPUT_IME | ||||
| if (win->ime_data) { | WM_window_IME_end(win); | ||||
| ui_textedit_ime_end(win, but); | |||||
| } | |||||
| #endif | #endif | ||||
| } | } | ||||
| static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonData *data) | static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonData *data) | ||||
| { | { | ||||
| /* label and roundbox can overlap real buttons (backdrops...) */ | /* label and roundbox can overlap real buttons (backdrops...) */ | ||||
| if (ELEM(actbut->type, | if (ELEM(actbut->type, | ||||
| UI_BTYPE_LABEL, | UI_BTYPE_LABEL, | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| static void ui_do_but_textedit( | static void ui_do_but_textedit( | ||||
| bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) | bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) | ||||
| { | { | ||||
| int retval = WM_UI_HANDLER_CONTINUE; | int retval = WM_UI_HANDLER_CONTINUE; | ||||
| bool changed = false, inbox = false, update = false, skip_undo_push = false; | bool changed = false, inbox = false, update = false, skip_undo_push = false; | ||||
| #ifdef WITH_INPUT_IME | |||||
| wmWindow *win = CTX_wm_window(C); | |||||
| wmIMEData *ime_data = win->ime_data; | |||||
| const bool is_ime_composing = ime_data && ime_data->is_ime_composing; | |||||
| #else | |||||
| const bool is_ime_composing = false; | |||||
| #endif | |||||
| switch (event->type) { | switch (event->type) { | ||||
| case MOUSEMOVE: | case MOUSEMOVE: | ||||
| case MOUSEPAN: | case MOUSEPAN: | ||||
| if (data->searchbox) { | if (data->searchbox) { | ||||
| #ifdef USE_KEYNAV_LIMIT | #ifdef USE_KEYNAV_LIMIT | ||||
| if ((event->type == MOUSEMOVE) && | if ((event->type == MOUSEMOVE) && | ||||
| ui_mouse_motion_keynav_test(&data->searchbox_keynav_state, event)) { | ui_mouse_motion_keynav_test(&data->searchbox_keynav_state, event)) { | ||||
| /* pass */ | /* pass */ | ||||
| Show All 16 Lines | |||||
| if (data->searchbox) { | if (data->searchbox) { | ||||
| if (ui_searchbox_event(C, data->searchbox, but, data->region, event)) { | if (ui_searchbox_event(C, data->searchbox, but, data->region, event)) { | ||||
| /* Only break if the event was handled. */ | /* Only break if the event was handled. */ | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #ifdef WITH_INPUT_IME | |||||
| /* skips button handling since it is not wanted */ | |||||
| if (is_ime_composing) { | |||||
| break; | |||||
| } | |||||
| #endif | |||||
| data->cancel = true; | data->cancel = true; | ||||
| data->escapecancel = true; | data->escapecancel = true; | ||||
| button_activate_state(C, but, BUTTON_STATE_EXIT); | button_activate_state(C, but, BUTTON_STATE_EXIT); | ||||
| retval = WM_UI_HANDLER_BREAK; | retval = WM_UI_HANDLER_BREAK; | ||||
| } | } | ||||
| break; | break; | ||||
| case LEFTMOUSE: { | case LEFTMOUSE: { | ||||
| /* Allow clicks on extra icons while editing. */ | /* Allow clicks on extra icons while editing. */ | ||||
| ▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | |||||
| button_activate_state(C, but, BUTTON_STATE_EXIT); | button_activate_state(C, but, BUTTON_STATE_EXIT); | ||||
| retval = WM_UI_HANDLER_BREAK; | retval = WM_UI_HANDLER_BREAK; | ||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (event->val == KM_PRESS && !is_ime_composing) { | if (event->val == KM_PRESS) { | ||||
| switch (event->type) { | switch (event->type) { | ||||
| case EVT_VKEY: | case EVT_VKEY: | ||||
| case EVT_XKEY: | case EVT_XKEY: | ||||
| case EVT_CKEY: | case EVT_CKEY: | ||||
| if (IS_EVENT_MOD(event, ctrl, oskey)) { | if (IS_EVENT_MOD(event, ctrl, oskey)) { | ||||
| if (event->type == EVT_VKEY) { | if (event->type == EVT_VKEY) { | ||||
| changed = ui_textedit_copypaste(but, data, UI_TEXTEDIT_PASTE); | changed = ui_textedit_copypaste(but, data, UI_TEXTEDIT_PASTE); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 136 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| retval = WM_UI_HANDLER_BREAK; | retval = WM_UI_HANDLER_BREAK; | ||||
| skip_undo_push = true; | skip_undo_push = true; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if ((event->ascii || event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE) | if ((event->ascii || event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE)) { | ||||
| #ifdef WITH_INPUT_IME | |||||
| && !is_ime_composing && (!WM_event_is_ime_switch(event) || !BLT_lang_is_ime_supported()) | |||||
| #endif | |||||
| ) { | |||||
| char ascii = event->ascii; | char ascii = event->ascii; | ||||
| const char *utf8_buf = event->utf8_buf; | const char *utf8_buf = event->utf8_buf; | ||||
| /* exception that's useful for number buttons, some keyboard | /* exception that's useful for number buttons, some keyboard | ||||
| * numpads have a comma instead of a period */ | * numpads have a comma instead of a period */ | ||||
| if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) { /* could use data->min*/ | if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) { /* could use data->min*/ | ||||
| if (event->type == EVT_PADPERIOD && ascii == ',') { | if (event->type == EVT_PADPERIOD && ascii == ',') { | ||||
| ascii = '.'; | ascii = '.'; | ||||
| Show All 14 Lines | |||||
| } | } | ||||
| /* textbutton with this flag: do live update (e.g. for search buttons) */ | /* textbutton with this flag: do live update (e.g. for search buttons) */ | ||||
| if (but->flag & UI_BUT_TEXTEDIT_UPDATE) { | if (but->flag & UI_BUT_TEXTEDIT_UPDATE) { | ||||
| update = true; | update = true; | ||||
| } | } | ||||
| } | } | ||||
| #ifdef WITH_INPUT_IME | #ifdef WITH_INPUT_IME | ||||
| if (event->type == WM_IME_COMPOSITE_START || event->type == WM_IME_COMPOSITE_EVENT) { | if (event->type == WM_IME_COMPOSITE_EVENT) { | ||||
| wmIMEData *ime_data = CTX_wm_window(C)->ime_data; | |||||
| changed = true; | changed = true; | ||||
| skip_undo_push = true; | |||||
| if (event->type == WM_IME_COMPOSITE_START && but->selend > but->selsta) { | if ((but->selend - but->selsta) > 0) { | ||||
| ui_textedit_delete_selection(but, data); | ui_textedit_delete_selection(but, data); | ||||
| } | } | ||||
| if (event->type == WM_IME_COMPOSITE_EVENT && ime_data->result_len) { | /* delete IME composite */ | ||||
| ui_textedit_insert_buf(but, data, ime_data->str_result, ime_data->result_len); | ui_textedit_delete_ime_composite(but, data); | ||||
| /* insert IME result to buffer */ | |||||
| if (event->ime_result.len) { | |||||
| ui_textedit_insert_buf(but, data, event->ime_result.str, event->ime_result.len); | |||||
| but->ime_end = but->ime_start = but->pos; | |||||
| if (data->undo_stack_text != NULL) { | |||||
| ui_textedit_undo_push(data->undo_stack_text, data->str, but->pos); | |||||
| } | |||||
| } | |||||
| /* insert IME composite to buffer */ | |||||
| if (ime_data->len) { | |||||
| size_t editlen = (size_t)strlen(but->editstr); | |||||
| /* make IME data shorter than maxlen */ | |||||
| if (!data->is_str_dynamic && ime_data->len + (editlen + 1) > data->maxlen) { | |||||
| BLI_strnlen_utf8_ex(ime_data->str, data->maxlen - (editlen + 1), &ime_data->len); | |||||
| ime_data->cursor_pos = min_ii(ime_data->cursor_pos, ime_data->len); | |||||
| ime_data->sel_start = min_ii(ime_data->sel_start, ime_data->len); | |||||
| ime_data->sel_end = min_ii(ime_data->sel_end, ime_data->len); | |||||
| } | |||||
| ui_textedit_insert_buf(but, data, ime_data->str, ime_data->len); | |||||
hzuika: In Chinese and Japanese, the number of characters in the result string may be less than in the… | |||||
| but->pos = but->ime_start + ime_data->cursor_pos; | |||||
| but->ime_end = but->ime_start + ime_data->len; | |||||
| } | |||||
| if (but->flag & UI_BUT_TEXTEDIT_UPDATE) { | |||||
| update = true; | |||||
| } | } | ||||
| } | } | ||||
| else if (event->type == WM_IME_COMPOSITE_END) { | #endif /* WITH_INPUT_IME */ | ||||
| changed = true; | |||||
| } | |||||
| #endif | |||||
| if (changed) { | if (changed) { | ||||
| /* The undo stack may be NULL if an event exits editing. */ | /* The undo stack may be NULL if an event exits editing. */ | ||||
| if ((skip_undo_push == false) && (data->undo_stack_text != NULL)) { | if ((skip_undo_push == false) && (data->undo_stack_text != NULL)) { | ||||
| ui_textedit_undo_push(data->undo_stack_text, data->str, but->pos); | ui_textedit_undo_push(data->undo_stack_text, data->str, but->pos); | ||||
| } | } | ||||
| /* only do live update when but flag request it (UI_BUT_TEXTEDIT_UPDATE). */ | /* only do live update when but flag request it (UI_BUT_TEXTEDIT_UPDATE). */ | ||||
| ▲ Show 20 Lines • Show All 184 Lines • ▼ Show 20 Lines | |||||
| ui_textedit_begin(C, but, data); | ui_textedit_begin(C, but, data); | ||||
| } | } | ||||
| else if (data->state == BUTTON_STATE_TEXT_EDITING && state != BUTTON_STATE_TEXT_SELECTING) { | else if (data->state == BUTTON_STATE_TEXT_EDITING && state != BUTTON_STATE_TEXT_SELECTING) { | ||||
| ui_textedit_end(C, but, data); | ui_textedit_end(C, but, data); | ||||
| } | } | ||||
| else if (data->state == BUTTON_STATE_TEXT_SELECTING && state != BUTTON_STATE_TEXT_EDITING) { | else if (data->state == BUTTON_STATE_TEXT_SELECTING && state != BUTTON_STATE_TEXT_EDITING) { | ||||
| ui_textedit_end(C, but, data); | ui_textedit_end(C, but, data); | ||||
| } | } | ||||
| #ifdef WITH_INPUT_IME | |||||
| if (state == BUTTON_STATE_TEXT_SELECTING && data->state == BUTTON_STATE_TEXT_EDITING) { | |||||
| WM_window_IME_cancel(data->window); | |||||
| but->ime_end = but->ime_start = but->pos; | |||||
| } | |||||
| #endif | |||||
| /* number editing */ | /* number editing */ | ||||
| if (state == BUTTON_STATE_NUM_EDITING) { | if (state == BUTTON_STATE_NUM_EDITING) { | ||||
| if (ui_but_is_cursor_warp(but)) { | if (ui_but_is_cursor_warp(but)) { | ||||
| WM_cursor_grab_enable(CTX_wm_window(C), WM_CURSOR_WRAP_XY, true, NULL); | WM_cursor_grab_enable(CTX_wm_window(C), WM_CURSOR_WRAP_XY, true, NULL); | ||||
| } | } | ||||
| ui_numedit_begin(but, data); | ui_numedit_begin(but, data); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 92 Lines • Show Last 20 Lines | |||||
In Chinese and Japanese, the number of characters in the result string may be less than in the composition string.
For example, "さくら" -> "桜", "chang" -> "长".
Therefore, if more than maximum number of characters are entered in the composition string, it will be invisible.
However, when I pressed Enter key and converted the composition string to the result string, the result string will appear correctly.
This seems to be a bit unnatural behavior.
However, you may not be able to solve this problem, because more than the maximum number of characters are not allowed to be inserted.
Do you have a solution?