diff options
Diffstat (limited to 'source/blender/editors/interface/interface.c')
-rw-r--r-- | source/blender/editors/interface/interface.c | 421 |
1 files changed, 175 insertions, 246 deletions
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 78021612195..fac1267cc62 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -262,7 +262,7 @@ static void ui_block_bounds_calc_text(uiBlock *block, float offset) } if (bt->next && bt->rect.xmin < bt->next->rect.xmin) { - /* End of this column, and it’s not the last one. */ + /* End of this column, and it's not the last one. */ for (col_bt = init_col_bt; col_bt->prev != bt; col_bt = col_bt->next) { col_bt->rect.xmin = x1addval; col_bt->rect.xmax = x1addval + i + block->bounds; @@ -368,9 +368,11 @@ static void ui_block_bounds_calc_popup( wmWindow *window, uiBlock *block, eBlockBoundsCalc bounds_calc, const int xy[2]) { - int startx, starty, endx, endy, width, height, oldwidth, oldheight; + int width, height, oldwidth, oldheight; int oldbounds, xmax, ymax; const int margin = UI_SCREEN_MARGIN; + rcti rect, rect_bounds; + int ofs_dummy[2]; oldbounds = block->bounds; @@ -405,27 +407,18 @@ static void ui_block_bounds_calc_popup( /* offset block based on mouse position, user offset is scaled * along in case we resized the block in ui_block_bounds_calc_text */ - startx = xy[0] + block->rect.xmin + (block->mx * width) / oldwidth; - starty = xy[1] + block->rect.ymin + (block->my * height) / oldheight; + rect.xmin = xy[0] + block->rect.xmin + (block->mx * width) / oldwidth; + rect.ymin = xy[1] + block->rect.ymin + (block->my * height) / oldheight; + rect.xmax = rect.xmin + width; + rect.ymax = rect.ymin + height; - if (startx < margin) - startx = margin; - if (starty < margin) - starty = margin; + rect_bounds.xmin = margin; + rect_bounds.ymin = margin; + rect_bounds.xmax = xmax - margin; + rect_bounds.ymax = ymax - UI_POPUP_MENU_TOP; - endx = startx + width; - endy = starty + height; - - if (endx > xmax) { - endx = xmax - margin; - startx = endx - width; - } - if (endy > ymax - margin) { - endy = ymax - margin; - starty = endy - height; - } - - ui_block_translate(block, startx - block->rect.xmin, starty - block->rect.ymin); + BLI_rcti_clamp(&rect, &rect_bounds, ofs_dummy); + ui_block_translate(block, rect.xmin - block->rect.xmin, rect.ymin - block->rect.ymin); /* now recompute bounds and safety */ ui_block_bounds_calc(block); @@ -742,8 +735,15 @@ static bool ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBu /* copy hardmin for list rows to prevent 'sticking' highlight to mouse position * when scrolling without moving mouse (see [#28432]) */ - if (ELEM(oldbut->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) + if (ELEM(oldbut->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) { oldbut->hardmax = but->hardmax; + } + + /* Selectively copy a1, a2 since their use differs across all button types + * (and we'll probably split these out later) */ + if (ELEM(oldbut->type, UI_BTYPE_PROGRESS_BAR)) { + oldbut->a1 = but->a1; + } ui_but_update_linklines(block, oldbut, but); @@ -1053,6 +1053,10 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but, /* dopesheet filtering options... */ data_path = BLI_sprintfN("space_data.dopesheet.%s", RNA_property_identifier(but->rnaprop)); } + else if (RNA_struct_is_a(but->rnapoin.type, &RNA_FileSelectParams)) { + /* Filebrowser options... */ + data_path = BLI_sprintfN("space_data.params.%s", RNA_property_identifier(but->rnaprop)); + } } } else if (GS(id->name) == ID_SCE) { @@ -1100,7 +1104,6 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but, /* check each until one works... */ for (i = 0; (i < num_ops) && (ctx_toggle_opnames[i]); i++) { - //printf("\t%s\n", ctx_toggle_opnames[i]); if (WM_key_event_operator_string(C, ctx_toggle_opnames[i], WM_OP_INVOKE_REGION_WIN, prop_path, false, buf_len, buf)) { @@ -1204,6 +1207,11 @@ void UI_block_update_from_old(const bContext *C, uiBlock *block) for (but = block->buttons.first; but; but = but->next) { if (ui_but_update_from_old_block(C, block, &but, &but_old)) { ui_but_update(but); + + /* redraw dynamic tooltip if we have one open */ + if (but->tip_func) { + UI_but_tooltip_refresh((bContext *)C, but); + } } } @@ -1352,9 +1360,9 @@ void UI_block_draw(const bContext *C, uiBlock *block) UI_block_end(C, block); /* disable AA, makes widgets too blurry */ - multisample_enabled = glIsEnabled(GL_MULTISAMPLE_ARB); + multisample_enabled = glIsEnabled(GL_MULTISAMPLE); if (multisample_enabled) - glDisable(GL_MULTISAMPLE_ARB); + glDisable(GL_MULTISAMPLE); /* we set this only once */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -1375,7 +1383,7 @@ void UI_block_draw(const bContext *C, uiBlock *block) glPushMatrix(); glLoadIdentity(); - wmOrtho2_region_ui(ar); + wmOrtho2_region_pixelspace(ar); /* back */ if (block->flag & UI_BLOCK_RADIAL) @@ -1404,7 +1412,7 @@ void UI_block_draw(const bContext *C, uiBlock *block) glPopMatrix(); if (multisample_enabled) - glEnable(GL_MULTISAMPLE_ARB); + glEnable(GL_MULTISAMPLE); ui_draw_links(block); } @@ -1812,7 +1820,8 @@ bool ui_but_supports_cycling(const uiBut *but) { return ((ELEM(but->type, UI_BTYPE_ROW, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER, UI_BTYPE_LISTBOX)) || (but->type == UI_BTYPE_MENU && ui_but_menu_step_poll(but)) || - (but->type == UI_BTYPE_COLOR && but->a1 != -1)); + (but->type == UI_BTYPE_COLOR && but->a1 != -1) || + (but->menu_step_func != NULL)); } double ui_but_value_get(uiBut *but) @@ -2100,7 +2109,7 @@ static float ui_get_but_step_unit(uiBut *but, float step_default) BLI_assert(step > 0.0); - step_final = (step / scale_unit) / UI_PRECISION_FLOAT_SCALE; + step_final = (step / scale_unit) / (double)UI_PRECISION_FLOAT_SCALE; if (step == step_unit) { /* Logic here is to scale by the original 'step_orig' @@ -2204,6 +2213,63 @@ void ui_but_string_get(uiBut *but, char *str, const size_t maxlen) ui_but_string_get_ex(but, str, maxlen, -1); } +/** + * A version of #ui_but_string_get_ex for dynamic buffer sizes + * (where #ui_but_string_get_max_length returns 0). + * + * \param r_str_size: size of the returned string (including terminator). + */ +char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size) +{ + char *str = NULL; + *r_str_size = 1; + + if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) { + PropertyType type; + + type = RNA_property_type(but->rnaprop); + + if (type == PROP_STRING) { + /* RNA string */ + str = RNA_property_string_get_alloc(&but->rnapoin, but->rnaprop, NULL, 0, r_str_size); + (*r_str_size) += 1; + } + else if (type == PROP_ENUM) { + /* RNA enum */ + int value = RNA_property_enum_get(&but->rnapoin, but->rnaprop); + const char *value_id; + if (!RNA_property_enum_name(but->block->evil_C, &but->rnapoin, but->rnaprop, value, &value_id)) { + value_id = ""; + } + + *r_str_size = strlen(value_id) + 1; + str = BLI_strdupn(value_id, *r_str_size); + } + else if (type == PROP_POINTER) { + /* RNA pointer */ + PointerRNA ptr = RNA_property_pointer_get(&but->rnapoin, but->rnaprop); + str = RNA_struct_name_get_alloc(&ptr, NULL, 0, r_str_size); + (*r_str_size) += 1; + } + else { + BLI_assert(0); + } + } + else { + BLI_assert(0); + } + + if (UNLIKELY(str == NULL)) { + /* should never happen, paranoid check */ + *r_str_size = 1; + str = BLI_strdup(""); + BLI_assert(0); + + } + + return str; +} + #ifdef WITH_PYTHON static bool ui_set_but_string_eval_num_unit(bContext *C, uiBut *but, const char *str, double *value) @@ -2218,7 +2284,7 @@ static bool ui_set_but_string_eval_num_unit(bContext *C, uiBut *but, const char bUnit_ReplaceString(str_unit_convert, sizeof(str_unit_convert), but->drawstr, ui_get_but_scale_unit(but, 1.0), but->block->unit->system, RNA_SUBTYPE_UNIT_VALUE(unit_type)); - return (BPY_button_exec(C, str_unit_convert, value, true) != -1); + return BPY_execute_string_as_number(C, str_unit_convert, value, true); } #endif /* WITH_PYTHON */ @@ -2233,7 +2299,7 @@ bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double if (str[0] != '\0') { bool is_unit_but = (ui_but_is_float(but) && ui_but_is_unit(but)); /* only enable verbose if we won't run again with units */ - if (BPY_button_exec(C, str, value, is_unit_but == false) != -1) { + if (BPY_execute_string_as_number(C, str, value, is_unit_but == false)) { /* if the value parsed ok without unit conversion this button may still need a unit multiplier */ if (is_unit_but) { char str_new[128]; @@ -2363,7 +2429,7 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str) double value; if (ui_but_string_set_eval_num(C, but, str, &value) == false) { - WM_report_banner_show(C); + WM_report_banner_show(); return false; } @@ -2721,7 +2787,12 @@ void UI_block_emboss_set(uiBlock *block, char dt) block->dt = dt; } -void ui_but_update(uiBut *but) +/** + * \param but: Button to update. + * \param validate: When set, this function may change the button value. + * Otherwise treat the button value as read-only. + */ +void ui_but_update_ex(uiBut *but, const bool validate) { /* if something changed in the button */ double value = UI_BUT_VALUE_UNSET; @@ -2743,13 +2814,19 @@ void ui_but_update(uiBut *but) case UI_BTYPE_NUM: case UI_BTYPE_SCROLL: case UI_BTYPE_NUM_SLIDER: - UI_GET_BUT_VALUE_INIT(but, value); - if (value < (double)but->hardmin) ui_but_value_set(but, but->hardmin); - else if (value > (double)but->hardmax) ui_but_value_set(but, but->hardmax); + if (validate) { + UI_GET_BUT_VALUE_INIT(but, value); + if (value < (double)but->hardmin) { + ui_but_value_set(but, but->hardmin); + } + else if (value > (double)but->hardmax) { + ui_but_value_set(but, but->hardmax); + } - /* max must never be smaller than min! Both being equal is allowed though */ - BLI_assert(but->softmin <= but->softmax && - but->hardmin <= but->hardmax); + /* max must never be smaller than min! Both being equal is allowed though */ + BLI_assert(but->softmin <= but->softmax && + but->hardmin <= but->hardmax); + } break; case UI_BTYPE_ICON_TOGGLE: @@ -2777,14 +2854,17 @@ void ui_but_update(uiBut *but) /* only needed for menus in popup blocks that don't recreate buttons on redraw */ if (but->block->flag & UI_BLOCK_LOOP) { if (but->rnaprop && (RNA_property_type(but->rnaprop) == PROP_ENUM)) { - int value = RNA_property_enum_get(&but->rnapoin, but->rnaprop); - const char *buf; - if (RNA_property_enum_name_gettexted(but->block->evil_C, - &but->rnapoin, but->rnaprop, value, &buf)) + int value_enum = RNA_property_enum_get(&but->rnapoin, but->rnaprop); + + EnumPropertyItem item; + if (RNA_property_enum_item_from_value_gettexted( + but->block->evil_C, + &but->rnapoin, but->rnaprop, value_enum, &item)) { - size_t slen = strlen(buf); + size_t slen = strlen(item.name); ui_but_string_free_internal(but); - ui_but_string_set_internal(but, buf, slen); + ui_but_string_set_internal(but, item.name, slen); + but->icon = item.icon; } } } @@ -2922,6 +3002,15 @@ void ui_but_update(uiBut *but) /* text clipping moved to widget drawing code itself */ } +void ui_but_update(uiBut *but) +{ + ui_but_update_ex(but, false); +} + +void ui_but_update_edited(uiBut *but) +{ + ui_but_update_ex(but, true); +} void UI_block_align_begin(uiBlock *block) { @@ -2934,200 +3023,11 @@ void UI_block_align_begin(uiBlock *block) /* buttons declared after this call will get this align nr */ // XXX flag? } -static bool buts_are_horiz(uiBut *but1, uiBut *but2) -{ - float dx, dy; - - /* simple case which can fail if buttons shift apart - * with proportional layouts, see: [#38602] */ - if ((but1->rect.ymin == but2->rect.ymin) && - (but1->rect.xmin != but2->rect.xmin)) - { - return true; - } - - dx = fabsf(but1->rect.xmax - but2->rect.xmin); - dy = fabsf(but1->rect.ymin - but2->rect.ymax); - - return (dx <= dy); -} - void UI_block_align_end(uiBlock *block) { block->flag &= ~UI_BUT_ALIGN; /* all 4 flags */ } -bool ui_but_can_align(uiBut *but) -{ - return !ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_CHECKBOX, UI_BTYPE_CHECKBOX_N, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE); -} - -static void ui_block_align_calc_but(uiBut *first, short nr) -{ - uiBut *prev, *but = NULL, *next; - int flag = 0, cols = 0, rows = 0; - - /* auto align */ - - for (but = first; but && but->alignnr == nr; but = but->next) { - if (but->next && but->next->alignnr == nr) { - if (buts_are_horiz(but, but->next)) cols++; - else rows++; - } - } - - /* rows == 0: 1 row, cols == 0: 1 column */ - - /* note; how it uses 'flag' in loop below (either set it, or OR it) is confusing */ - for (but = first, prev = NULL; but && but->alignnr == nr; prev = but, but = but->next) { - next = but->next; - if (next && next->alignnr != nr) - next = NULL; - - /* clear old flag */ - but->drawflag &= ~UI_BUT_ALIGN; - - if (flag == 0) { /* first case */ - if (next) { - if (buts_are_horiz(but, next)) { - if (rows == 0) - flag = UI_BUT_ALIGN_RIGHT; - else - flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_RIGHT; - } - else { - flag = UI_BUT_ALIGN_DOWN; - } - } - } - else if (next == NULL) { /* last case */ - if (prev) { - if (buts_are_horiz(prev, but)) { - if (rows == 0) - flag = UI_BUT_ALIGN_LEFT; - else - flag = UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT; - } - else { - flag = UI_BUT_ALIGN_TOP; - } - } - } - else if (buts_are_horiz(but, next)) { - /* check if this is already second row */ - if (prev && buts_are_horiz(prev, but) == 0) { - flag &= ~UI_BUT_ALIGN_LEFT; - flag |= UI_BUT_ALIGN_TOP; - /* exception case: bottom row */ - if (rows > 0) { - uiBut *bt = but; - while (bt && bt->alignnr == nr) { - if (bt->next && bt->next->alignnr == nr && buts_are_horiz(bt, bt->next) == 0) { - break; - } - bt = bt->next; - } - if (bt == NULL || bt->alignnr != nr) flag = UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_RIGHT; - } - } - else { - flag |= UI_BUT_ALIGN_LEFT; - } - } - else { - if (cols == 0) { - flag |= UI_BUT_ALIGN_TOP; - } - else { /* next button switches to new row */ - - if (prev && buts_are_horiz(prev, but)) - flag |= UI_BUT_ALIGN_LEFT; - else { - flag &= ~UI_BUT_ALIGN_LEFT; - flag |= UI_BUT_ALIGN_TOP; - } - - if ((flag & UI_BUT_ALIGN_TOP) == 0) { /* stil top row */ - if (prev) { - if (next && buts_are_horiz(but, next)) - flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT | UI_BUT_ALIGN_RIGHT; - else { - /* last button in top row */ - flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT; - } - } - else - flag |= UI_BUT_ALIGN_DOWN; - } - else - flag |= UI_BUT_ALIGN_TOP; - } - } - - but->drawflag |= flag; - - /* merge coordinates */ - if (prev) { - /* simple cases */ - if (rows == 0) { - but->rect.xmin = (prev->rect.xmax + but->rect.xmin) / 2.0f; - prev->rect.xmax = but->rect.xmin; - } - else if (cols == 0) { - but->rect.ymax = (prev->rect.ymin + but->rect.ymax) / 2.0f; - prev->rect.ymin = but->rect.ymax; - } - else { - if (buts_are_horiz(prev, but)) { - but->rect.xmin = (prev->rect.xmax + but->rect.xmin) / 2.0f; - prev->rect.xmax = but->rect.xmin; - /* copy height too */ - but->rect.ymax = prev->rect.ymax; - } - else if (prev->prev && buts_are_horiz(prev->prev, prev) == 0) { - /* the previous button is a single one in its row */ - but->rect.ymax = (prev->rect.ymin + but->rect.ymax) / 2.0f; - prev->rect.ymin = but->rect.ymax; - - but->rect.xmin = prev->rect.xmin; - if (next && buts_are_horiz(but, next) == 0) - but->rect.xmax = prev->rect.xmax; - } - else { - /* the previous button is not a single one in its row */ - but->rect.ymax = prev->rect.ymin; - } - } - } - } -} - -void ui_block_align_calc(uiBlock *block) -{ - uiBut *but; - short nr; - - /* align buttons with same align nr */ - for (but = block->buttons.first; but; ) { - if (but->alignnr) { - nr = but->alignnr; - ui_block_align_calc_but(but, nr); - - /* skip with same number */ - for (; but && but->alignnr == nr; but = but->next) { - /* pass */ - } - - if (!but) { - break; - } - } - else { - but = but->next; - } - } -} - struct ColorManagedDisplay *ui_block_cm_display_get(uiBlock *block) { return IMB_colormanagement_display_get_named(block->display_device); @@ -3563,8 +3463,7 @@ static uiBut *ui_def_but_rna( else if (proptype == PROP_STRING) { min = 0; max = RNA_property_string_maxlength(prop); - if (max == 0) /* interface code should ideally support unlimited length */ - max = UI_MAX_DRAW_STR; + /* note, 'max' may be zero (code for dynamically resized array) */ } } @@ -3680,11 +3579,11 @@ static int findBitIndex(unsigned int x) else { int idx = 0; - if (x & 0xFFFF0000) idx += 16, x >>= 16; - if (x & 0xFF00) idx += 8, x >>= 8; - if (x & 0xF0) idx += 4, x >>= 4; - if (x & 0xC) idx += 2, x >>= 2; - if (x & 0x2) idx += 1; + if (x & 0xFFFF0000) { idx += 16; x >>= 16; } + if (x & 0xFF00) { idx += 8; x >>= 8; } + if (x & 0xF0) { idx += 4; x >>= 4; } + if (x & 0xC) { idx += 2; x >>= 2; } + if (x & 0x2) { idx += 1; } return idx; } @@ -4085,6 +3984,11 @@ void UI_but_flag_disable(uiBut *but, int flag) but->flag &= ~flag; } +bool UI_but_flag_is_set(uiBut *but, int flag) +{ + return (but->flag & flag) != 0; +} + void UI_but_drawflag_enable(uiBut *but, int flag) { but->drawflag |= flag; @@ -4271,6 +4175,11 @@ void UI_but_func_complete_set(uiBut *but, uiButCompleteFunc func, void *arg) but->autofunc_arg = arg; } +void UI_but_func_menu_step_set(uiBut *but, uiMenuStepFunc func) +{ + but->menu_step_func = func; +} + void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *argN) { but->tip_func = func; @@ -4418,12 +4327,30 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle * \param arg: user value, * \param active: when set, button opens with this item visible and selected. */ -void UI_but_func_search_set(uiBut *but, uiButSearchFunc sfunc, void *arg, uiButHandleFunc bfunc, void *active) +void UI_but_func_search_set( + uiBut *but, + uiButSearchCreateFunc search_create_func, + uiButSearchFunc search_func, void *arg, + uiButHandleFunc bfunc, void *active) { - but->search_func = sfunc; + /* needed since callers don't have access to internal functions (as an alternative we could expose it) */ + if (search_create_func == NULL) { + search_create_func = ui_searchbox_create_generic; + } + + but->search_create_func = search_create_func; + but->search_func = search_func; but->search_arg = arg; - UI_but_func_set(but, bfunc, arg, active); + if (bfunc) { +#ifdef DEBUG + if (but->func) { + /* watch this, can be cause of much confusion, see: T47691 */ + printf("%s: warning, overwriting button callback with search function callback!\n", __func__); + } +#endif + UI_but_func_set(but, bfunc, arg, active); + } /* search buttons show red-alert if item doesn't exist, not for menus */ if (0 == (but->block->flag & UI_BLOCK_LOOP)) { @@ -4452,7 +4379,7 @@ static void operator_enum_search_cb(const struct bContext *C, void *but, const c EnumPropertyItem *item, *item_array; bool do_free; - RNA_property_enum_items((bContext *)C, ptr, prop, &item_array, NULL, &do_free); + RNA_property_enum_items_gettexted((bContext *)C, ptr, prop, &item_array, NULL, &do_free); for (item = item_array; item->identifier; item++) { /* note: need to give the index rather than the identifier because the enum can be freed */ @@ -4498,7 +4425,9 @@ uiBut *uiDefSearchButO_ptr( uiBut *but; but = uiDefSearchBut(block, arg, retval, icon, maxlen, x, y, width, height, a1, a2, tip); - UI_but_func_search_set(but, operator_enum_search_cb, but, operator_enum_call_cb, NULL); + UI_but_func_search_set( + but, ui_searchbox_create_generic, operator_enum_search_cb, + but, operator_enum_call_cb, NULL); but->optype = ot; but->opcontext = WM_OP_EXEC_DEFAULT; |