Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/interface/interface_handlers.c
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
| Show First 20 Lines • Show All 549 Lines • ▼ Show 20 Lines | |||||
| * \{ */ | * \{ */ | ||||
| bool ui_but_is_editing(const uiBut *but) | bool ui_but_is_editing(const uiBut *but) | ||||
| { | { | ||||
| uiHandleButtonData *data = but->active; | uiHandleButtonData *data = but->active; | ||||
| return (data && ELEM(data->state, BUTTON_STATE_TEXT_EDITING, BUTTON_STATE_NUM_EDITING)); | return (data && ELEM(data->state, BUTTON_STATE_TEXT_EDITING, BUTTON_STATE_NUM_EDITING)); | ||||
| } | } | ||||
| /* assumes event type is MOUSEPAN */ | |||||
| void ui_pan_to_scroll(const wmEvent *event, int *type, int *val) | void ui_pan_to_scroll(const wmEvent *event, int *type, int *val) | ||||
| { | { | ||||
| static int lastdy = 0; | static int lastdy = 0; | ||||
| const int dy = WM_event_absolute_delta_y(event); | const int dy = WM_event_absolute_delta_y(event); | ||||
| /* This event should be originally from event->type, | /* This event should be originally from event->type, | ||||
| * converting wrong event into wheel is bad, see T33803. */ | * converting wrong event into wheel is bad, see T33803. */ | ||||
| BLI_assert(*type == MOUSEPAN); | BLI_assert(*type == MOUSEPAN); | ||||
| Show All 22 Lines | |||||
| static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but_b) | static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but_b) | ||||
| { | { | ||||
| return ((but_a->type == but_b->type) && (but_a->alignnr == but_b->alignnr) && | return ((but_a->type == but_b->type) && (but_a->alignnr == but_b->alignnr) && | ||||
| (but_a->poin == but_b->poin) && (but_a->rnapoin.type == but_b->rnapoin.type) && | (but_a->poin == but_b->poin) && (but_a->rnapoin.type == but_b->rnapoin.type) && | ||||
| (but_a->rnaprop == but_b->rnaprop)); | (but_a->rnaprop == but_b->rnaprop)); | ||||
| } | } | ||||
| /** | |||||
| * Finds the pressed button in an aligned row (typically an expanded enum). | |||||
| * | |||||
| * \param direction: Use when there may be multiple buttons pressed. | |||||
| */ | |||||
| uiBut *ui_but_find_select_in_enum(uiBut *but, int direction) | uiBut *ui_but_find_select_in_enum(uiBut *but, int direction) | ||||
| { | { | ||||
| uiBut *but_iter = but; | uiBut *but_iter = but; | ||||
| uiBut *but_found = NULL; | uiBut *but_found = NULL; | ||||
| BLI_assert(ELEM(direction, -1, 1)); | BLI_assert(ELEM(direction, -1, 1)); | ||||
| while ((but_iter->prev) && ui_but_find_select_in_enum__cmp(but_iter->prev, but)) { | while ((but_iter->prev) && ui_but_find_select_in_enum__cmp(but_iter->prev, but)) { | ||||
| but_iter = but_iter->prev; | but_iter = but_iter->prev; | ||||
| ▲ Show 20 Lines • Show All 2,377 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Button Text Selection/Editing | /** \name Button Text Selection/Editing | ||||
| * \{ */ | * \{ */ | ||||
| /** | |||||
| * Use handling code to set a string for the button. Handles the case where the string is set for a | |||||
| * search button while the search menu is open, so the results are updated accordingly. | |||||
| * This is basically the same as pasting the string into the button. | |||||
| */ | |||||
| void ui_but_set_string_interactive(bContext *C, uiBut *but, const char *value) | void ui_but_set_string_interactive(bContext *C, uiBut *but, const char *value) | ||||
| { | { | ||||
| button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); | button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); | ||||
| ui_textedit_string_set(but, but->active, value); | ui_textedit_string_set(but, but->active, value); | ||||
| if (but->type == UI_BTYPE_SEARCH_MENU && but->active) { | if (but->type == UI_BTYPE_SEARCH_MENU && but->active) { | ||||
| but->changed = true; | but->changed = true; | ||||
| ui_searchbox_update(C, but->active->searchbox, but, true); | ui_searchbox_update(C, but->active->searchbox, but, true); | ||||
| ▲ Show 20 Lines • Show All 549 Lines • ▼ Show 20 Lines | if (but) { | ||||
| if (data->searchbox) { | if (data->searchbox) { | ||||
| if (data->cancel == false) { | if (data->cancel == false) { | ||||
| BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); | BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); | ||||
| uiButSearch *but_search = (uiButSearch *)but; | uiButSearch *but_search = (uiButSearch *)but; | ||||
| if ((ui_searchbox_apply(but, data->searchbox) == false) && | if ((ui_searchbox_apply(but, data->searchbox) == false) && | ||||
| (ui_searchbox_find_index(data->searchbox, but->editstr) == -1) && | (ui_searchbox_find_index(data->searchbox, but->editstr) == -1) && | ||||
| !but_search->results_are_suggestions) { | !but_search->results_are_suggestions) { | ||||
| if (but->flag & UI_BUT_VALUE_CLEAR) { | |||||
| /* It is valid for _VALUE_CLEAR flavor to have no active element | |||||
| * (it's a valid way to unlink). */ | |||||
| but->editstr[0] = '\0'; | |||||
| } | |||||
| data->cancel = true; | data->cancel = true; | ||||
| /* ensure menu (popup) too is closed! */ | /* ensure menu (popup) too is closed! */ | ||||
| data->escapecancel = true; | data->escapecancel = true; | ||||
| WM_reportf(RPT_ERROR, "Failed to find '%s'", but->editstr); | WM_reportf(RPT_ERROR, "Failed to find '%s'", but->editstr); | ||||
| WM_report_banner_show(); | WM_report_banner_show(); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 4,613 Lines • ▼ Show 20 Lines | static void ui_blocks_set_tooltips(ARegion *region, const bool enable) | ||||
| } | } | ||||
| /* We disabled buttons when they were already shown, and re-enable them on mouse move. */ | /* We disabled buttons when they were already shown, and re-enable them on mouse move. */ | ||||
| LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | ||||
| block->tooltipdisabled = !enable; | block->tooltipdisabled = !enable; | ||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * Recreate tool-tip (use to update dynamic tips) | |||||
| */ | |||||
| void UI_but_tooltip_refresh(bContext *C, uiBut *but) | void UI_but_tooltip_refresh(bContext *C, uiBut *but) | ||||
| { | { | ||||
| uiHandleButtonData *data = but->active; | uiHandleButtonData *data = but->active; | ||||
| if (data) { | if (data) { | ||||
| bScreen *screen = WM_window_get_active_screen(data->window); | bScreen *screen = WM_window_get_active_screen(data->window); | ||||
| if (screen->tool_tip && screen->tool_tip->region) { | if (screen->tool_tip && screen->tool_tip->region) { | ||||
| WM_tooltip_refresh(C, data->window); | WM_tooltip_refresh(C, data->window); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * Removes tool-tip timer from active but | |||||
| * (meaning tool-tip is disabled until it's re-enabled again). | |||||
| */ | |||||
| void UI_but_tooltip_timer_remove(bContext *C, uiBut *but) | void UI_but_tooltip_timer_remove(bContext *C, uiBut *but) | ||||
| { | { | ||||
| uiHandleButtonData *data = but->active; | uiHandleButtonData *data = but->active; | ||||
| if (data) { | if (data) { | ||||
| if (data->autoopentimer) { | if (data->autoopentimer) { | ||||
| WM_event_remove_timer(data->wm, data->window, data->autoopentimer); | WM_event_remove_timer(data->wm, data->window, data->autoopentimer); | ||||
| data->autoopentimer = NULL; | data->autoopentimer = NULL; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 551 Lines • ▼ Show 20 Lines | static uiBut *ui_context_rna_button_active(const bContext *C) | ||||
| return ui_context_button_active(CTX_wm_region(C), ui_context_rna_button_active_test); | return ui_context_button_active(CTX_wm_region(C), ui_context_rna_button_active_test); | ||||
| } | } | ||||
| uiBut *UI_context_active_but_get(const bContext *C) | uiBut *UI_context_active_but_get(const bContext *C) | ||||
| { | { | ||||
| return ui_context_button_active(CTX_wm_region(C), NULL); | return ui_context_button_active(CTX_wm_region(C), NULL); | ||||
| } | } | ||||
| /* | |||||
| * Version of #UI_context_active_get() that uses the result of #CTX_wm_menu() | |||||
| * if set. Does not traverse into parent menus, which may be wanted in some | |||||
| * cases. | |||||
| */ | |||||
| uiBut *UI_context_active_but_get_respect_menu(const bContext *C) | uiBut *UI_context_active_but_get_respect_menu(const bContext *C) | ||||
| { | { | ||||
| ARegion *region_menu = CTX_wm_menu(C); | ARegion *region_menu = CTX_wm_menu(C); | ||||
| return ui_context_button_active(region_menu ? region_menu : CTX_wm_region(C), NULL); | return ui_context_button_active(region_menu ? region_menu : CTX_wm_region(C), NULL); | ||||
| } | } | ||||
| uiBut *UI_region_active_but_get(const ARegion *region) | uiBut *UI_region_active_but_get(const ARegion *region) | ||||
| { | { | ||||
| return ui_context_button_active(region, NULL); | return ui_context_button_active(region, NULL); | ||||
| } | } | ||||
| uiBut *UI_region_but_find_rect_over(const ARegion *region, const rcti *rect_px) | uiBut *UI_region_but_find_rect_over(const ARegion *region, const rcti *rect_px) | ||||
| { | { | ||||
| return ui_but_find_rect_over(region, rect_px); | return ui_but_find_rect_over(region, rect_px); | ||||
| } | } | ||||
| uiBlock *UI_region_block_find_mouse_over(const struct ARegion *region, | uiBlock *UI_region_block_find_mouse_over(const struct ARegion *region, | ||||
| const int xy[2], | const int xy[2], | ||||
| bool only_clip) | bool only_clip) | ||||
| { | { | ||||
| return ui_block_find_mouse_over_ex(region, xy, only_clip); | return ui_block_find_mouse_over_ex(region, xy, only_clip); | ||||
| } | } | ||||
| /** | |||||
| * Version of #UI_context_active_but_get that also returns RNA property info. | |||||
| * Helper function for insert keyframe, reset to default, etc operators. | |||||
| * | |||||
| * \return active button, NULL if none found or if it doesn't contain valid RNA data. | |||||
| */ | |||||
| uiBut *UI_context_active_but_prop_get(const bContext *C, | uiBut *UI_context_active_but_prop_get(const bContext *C, | ||||
| struct PointerRNA *r_ptr, | struct PointerRNA *r_ptr, | ||||
| struct PropertyRNA **r_prop, | struct PropertyRNA **r_prop, | ||||
| int *r_index) | int *r_index) | ||||
| { | { | ||||
| uiBut *activebut = ui_context_rna_button_active(C); | uiBut *activebut = ui_context_rna_button_active(C); | ||||
| if (activebut && activebut->rnapoin.data) { | if (activebut && activebut->rnapoin.data) { | ||||
| ▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /** | |||||
| * Try to find a search-box region opened from a button in \a button_region. | |||||
| */ | |||||
| ARegion *UI_region_searchbox_region_get(const ARegion *button_region) | ARegion *UI_region_searchbox_region_get(const ARegion *button_region) | ||||
| { | { | ||||
| uiBut *but = UI_region_active_but_get(button_region); | uiBut *but = UI_region_active_but_get(button_region); | ||||
| return (but != NULL) ? but->active->searchbox : NULL; | return (but != NULL) ? but->active->searchbox : NULL; | ||||
| } | } | ||||
| /* helper function for insert keyframe, reset to default, etc operators */ | |||||
| void UI_context_update_anim_flag(const bContext *C) | void UI_context_update_anim_flag(const bContext *C) | ||||
| { | { | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); | struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); | ||||
| const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct( | const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct( | ||||
| depsgraph, (scene) ? scene->r.cfra : 0.0f); | depsgraph, (scene) ? scene->r.cfra : 0.0f); | ||||
| Show All 32 Lines | while (region) { | ||||
| } | } | ||||
| else { | else { | ||||
| /* no active button */ | /* no active button */ | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * In some cases we may want to update the view (#View2D) in-between layout definition and drawing. | |||||
| * E.g. to make sure a button is visible while editing. | |||||
| */ | |||||
| void ui_but_update_view_for_active(const bContext *C, const uiBlock *block) | void ui_but_update_view_for_active(const bContext *C, const uiBlock *block) | ||||
| { | { | ||||
| uiBut *active_but = ui_block_active_but_get(block); | uiBut *active_but = ui_block_active_but_get(block); | ||||
| if (!active_but || !active_but->active || !active_but->changed || active_but->block != block) { | if (!active_but || !active_but->active || !active_but->changed || active_but->block != block) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* If there is a search popup attached to the button, don't change the view. The popups don't | /* If there is a search popup attached to the button, don't change the view. The popups don't | ||||
| * support updating the position to the button position nicely. */ | * support updating the position to the button position nicely. */ | ||||
| ▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | if (but) { | ||||
| button_activate_init(C, region, but, BUTTON_ACTIVATE_OVER); | button_activate_init(C, region, but, BUTTON_ACTIVATE_OVER); | ||||
| ui_do_button(C, but->block, but, event); | ui_do_button(C, but->block, but, event); | ||||
| } | } | ||||
| } | } | ||||
| return WM_UI_HANDLER_CONTINUE; | return WM_UI_HANDLER_CONTINUE; | ||||
| } | } | ||||
| /** | |||||
| * Exported to interface.c: #UI_but_active_only() | |||||
| * \note The region is only for the button. | |||||
| * The context needs to be set by the caller. | |||||
| */ | |||||
| void ui_but_activate_event(bContext *C, ARegion *region, uiBut *but) | void ui_but_activate_event(bContext *C, ARegion *region, uiBut *but) | ||||
| { | { | ||||
| wmWindow *win = CTX_wm_window(C); | wmWindow *win = CTX_wm_window(C); | ||||
| button_activate_init(C, region, but, BUTTON_ACTIVATE_OVER); | button_activate_init(C, region, but, BUTTON_ACTIVATE_OVER); | ||||
| wmEvent event; | wmEvent event; | ||||
| wm_event_init_from_window(win, &event); | wm_event_init_from_window(win, &event); | ||||
| event.type = EVT_BUT_OPEN; | event.type = EVT_BUT_OPEN; | ||||
| event.val = KM_PRESS; | event.val = KM_PRESS; | ||||
| event.is_repeat = false; | event.is_repeat = false; | ||||
| event.customdata = but; | event.customdata = but; | ||||
| event.customdata_free = false; | event.customdata_free = false; | ||||
| ui_do_button(C, but->block, but, &event); | ui_do_button(C, but->block, but, &event); | ||||
| } | } | ||||
| /** | |||||
| * Simulate moving the mouse over a button (or navigating to it with arrow keys). | |||||
| * | |||||
| * exported so menus can start with a highlighted button, | |||||
| * even if the mouse isn't over it | |||||
| */ | |||||
| void ui_but_activate_over(bContext *C, ARegion *region, uiBut *but) | void ui_but_activate_over(bContext *C, ARegion *region, uiBut *but) | ||||
| { | { | ||||
| button_activate_init(C, region, but, BUTTON_ACTIVATE_OVER); | button_activate_init(C, region, but, BUTTON_ACTIVATE_OVER); | ||||
| } | } | ||||
| void ui_but_execute_begin(struct bContext *UNUSED(C), | void ui_but_execute_begin(struct bContext *UNUSED(C), | ||||
| struct ARegion *region, | struct ARegion *region, | ||||
| uiBut *but, | uiBut *but, | ||||
| ▲ Show 20 Lines • Show All 2,223 Lines • ▼ Show 20 Lines | static int ui_handle_menus_recursive(bContext *C, | ||||
| if (do_towards_reinit) { | if (do_towards_reinit) { | ||||
| ui_mouse_motion_towards_reinit(menu, event->xy); | ui_mouse_motion_towards_reinit(menu, event->xy); | ||||
| } | } | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| /** | |||||
| * Allow setting menu return value from externals. | |||||
| * E.g. WM might need to do this for exiting files correctly. | |||||
| */ | |||||
| void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable) | void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable) | ||||
| { | { | ||||
| uiPopupBlockHandle *menu = block->handle; | uiPopupBlockHandle *menu = block->handle; | ||||
| if (menu) { | if (menu) { | ||||
| menu->menuretval = enable ? (menu->menuretval | retval) : (menu->menuretval & retval); | menu->menuretval = enable ? (menu->menuretval | retval) : (menu->menuretval & retval); | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 393 Lines • ▼ Show 20 Lines | LISTBASE_FOREACH (uiBut *, but, &block->buttons) { | ||||
| if (but->active == NULL) { | if (but->active == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| ui_but_active_free(C, but); | ui_but_active_free(C, but); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* is called by notifier */ | |||||
| void UI_screen_free_active_but_highlight(const bContext *C, bScreen *screen) | void UI_screen_free_active_but_highlight(const bContext *C, bScreen *screen) | ||||
| { | { | ||||
| wmWindow *win = CTX_wm_window(C); | wmWindow *win = CTX_wm_window(C); | ||||
| ED_screen_areas_iter (win, screen, area) { | ED_screen_areas_iter (win, screen, area) { | ||||
| LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { | LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { | ||||
| uiBut *but = ui_region_find_active_but(region); | uiBut *but = ui_region_find_active_but(region); | ||||
| if (but) { | if (but) { | ||||
| Show All 18 Lines | if (but) { | ||||
| if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) { | if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) { | ||||
| return but; | return but; | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* returns true if highlighted button allows drop of names */ | |||||
| /* called in region context */ | |||||
| bool UI_but_active_drop_name(const bContext *C) | bool UI_but_active_drop_name(const bContext *C) | ||||
| { | { | ||||
| return UI_but_active_drop_name_button(C) != NULL; | return UI_but_active_drop_name_button(C) != NULL; | ||||
| } | } | ||||
| bool UI_but_active_drop_color(bContext *C) | bool UI_but_active_drop_color(bContext *C) | ||||
| { | { | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| ▲ Show 20 Lines • Show All 110 Lines • Show Last 20 Lines | |||||