diff options
Diffstat (limited to 'source/blender/editors/interface')
18 files changed, 682 insertions, 395 deletions
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 279239fcc65..26ea5f8e24a 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -52,6 +52,7 @@ #include "BKE_context.h" #include "BKE_idprop.h" #include "BKE_main.h" +#include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_unit.h" @@ -1038,7 +1039,6 @@ static bool ui_but_is_rna_undo(const uiBut *but) if (ID_CHECK_UNDO(id) == false) { return false; } - return true; } if (but->rnapoin.type && !RNA_struct_undo_check(but->rnapoin.type)) { return false; @@ -1817,9 +1817,9 @@ static void ui_but_validate(const uiBut *but) #endif /** - * Check if the operator \a ot poll is successfull with the context given by \a but (optionally). + * Check if the operator \a ot poll is successful with the context given by \a but (optionally). * \param but: The button that might store context. Can be NULL for convenience (e.g. if there is - * no button to take context from, but we still want to poll the operator). + * no button to take context from, but we still want to poll the operator). */ bool ui_but_context_poll_operator(bContext *C, wmOperatorType *ot, const uiBut *but) { @@ -2327,6 +2327,14 @@ bool ui_but_is_float(const uiBut *but) return false; } +PropertyScaleType ui_but_scale_type(const uiBut *but) +{ + if (but->rnaprop) { + return RNA_property_ui_scale(but->rnaprop); + } + return PROP_SCALE_LINEAR; +} + bool ui_but_is_bool(const uiBut *but) { if (ELEM(but->type, @@ -2913,7 +2921,14 @@ char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size) static bool ui_number_from_string_units( bContext *C, const char *str, const int unit_type, const UnitSettings *unit, double *r_value) { - return user_string_to_number(C, str, unit, unit_type, UI_NUMBER_EVAL_ERROR_PREFIX, r_value); + char *error = NULL; + const bool ok = user_string_to_number(C, str, unit, unit_type, r_value, true, &error); + if (error) { + ReportList *reports = CTX_wm_reports(C); + BKE_reportf(reports, RPT_ERROR, "%s: %s", UI_NUMBER_EVAL_ERROR_PREFIX, error); + MEM_freeN(error); + } + return ok; } static bool ui_number_from_string_units_with_but(bContext *C, @@ -2930,7 +2945,11 @@ static bool ui_number_from_string(bContext *C, const char *str, double *r_value) { bool ok; #ifdef WITH_PYTHON - ok = BPY_run_string_as_number(C, NULL, str, UI_NUMBER_EVAL_ERROR_PREFIX, r_value); + struct BPy_RunErrInfo err_info = { + .reports = CTX_wm_reports(C), + .report_prefix = UI_NUMBER_EVAL_ERROR_PREFIX, + }; + ok = BPY_run_string_as_number(C, NULL, str, &err_info, r_value); #else UNUSED_VARS(C); *r_value = atof(str); @@ -3188,19 +3207,17 @@ void ui_but_range_set_hard(uiBut *but) const PropertyType type = RNA_property_type(but->rnaprop); - /* clamp button range to something reasonable in case - * we get -inf/inf from RNA properties */ if (type == PROP_INT) { int imin, imax; RNA_property_int_range(&but->rnapoin, but->rnaprop, &imin, &imax); - but->hardmin = (imin == INT_MIN) ? -1e4 : imin; - but->hardmax = (imin == INT_MAX) ? 1e4 : imax; + but->hardmin = imin; + but->hardmax = imax; } else if (type == PROP_FLOAT) { float fmin, fmax; RNA_property_float_range(&but->rnapoin, but->rnaprop, &fmin, &fmax); - but->hardmin = (fmin == -FLT_MAX) ? (float)-1e4 : fmin; - but->hardmax = (fmax == FLT_MAX) ? (float)1e4 : fmax; + but->hardmin = fmin; + but->hardmax = fmax; } } @@ -6127,6 +6144,7 @@ void UI_but_drag_set_asset(uiBut *but, const char *name, const char *path, int id_type, + int import_type, int icon, struct ImBuf *imb, float scale) @@ -6136,6 +6154,7 @@ void UI_but_drag_set_asset(uiBut *but, BLI_strncpy(asset_drag->name, name, sizeof(asset_drag->name)); asset_drag->path = path; asset_drag->id_type = id_type; + asset_drag->import_type = import_type; but->dragtype = WM_DRAG_ASSET; ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */ @@ -6591,6 +6610,8 @@ uiBut *uiDefSearchBut(uiBlock *block, * \param search_create_fn: Function to create the menu. * \param search_update_fn: Function to refresh search content after the search text has changed. * \param arg: user value. + * \param free_arg: Set to true if the argument is newly allocated memory for every redraw and + * should be freed when the button is destroyed. * \param search_arg_free_fn: When non-null, use this function to free \a arg. * \param search_exec_fn: Function that executes the action, gets \a arg as the first argument. * The second argument as the active item-pointer @@ -6601,6 +6622,7 @@ void UI_but_func_search_set(uiBut *but, uiButSearchCreateFn search_create_fn, uiButSearchUpdateFn search_update_fn, void *arg, + const bool free_arg, uiButSearchArgFreeFn search_arg_free_fn, uiButHandleFunc search_exec_fn, void *active) @@ -6636,11 +6658,17 @@ void UI_but_func_search_set(uiBut *but, } #endif /* Handling will pass the active item as arg2 later, so keep it NULL here. */ - UI_but_func_set(but, search_exec_fn, search_but->arg, NULL); + if (free_arg) { + UI_but_funcN_set(but, search_exec_fn, search_but->arg, NULL); + } + else { + UI_but_func_set(but, search_exec_fn, search_but->arg, NULL); + } } - /* search buttons show red-alert if item doesn't exist, not for menus */ - if (0 == (but->block->flag & UI_BLOCK_LOOP)) { + /* search buttons show red-alert if item doesn't exist, not for menus. Don't do this for + * buttons where any result is valid anyway, since any string will be valid anyway. */ + if (0 == (but->block->flag & UI_BLOCK_LOOP) && !search_but->results_are_suggestions) { /* skip empty buttons, not all buttons need input, we only show invalid */ if (but->drawstr[0]) { ui_but_search_refresh(search_but); @@ -6780,6 +6808,7 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block, ui_searchbox_create_generic, operator_enum_search_update_fn, but, + false, NULL, operator_enum_search_exec_fn, NULL); diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 91c19ff2850..b142e383df0 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -399,7 +399,7 @@ static void ui_but_user_menu_add(bContext *C, uiBut *but, bUserMenu *um) "'%s').label", idname); char *expr_result = NULL; - if (BPY_run_string_as_string(C, expr_imports, expr, __func__, &expr_result)) { + if (BPY_run_string_as_string(C, expr_imports, expr, NULL, &expr_result)) { STRNCPY(drawstr, expr_result); MEM_freeN(expr_result); } @@ -542,9 +542,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) const PropertyType type = RNA_property_type(prop); const PropertySubType subtype = RNA_property_subtype(prop); bool is_anim = RNA_property_animateable(ptr, prop); - const bool is_editable = RNA_property_editable(ptr, prop); const bool is_idprop = RNA_property_is_idprop(prop); - const bool is_set = RNA_property_is_set(ptr, prop); /* second slower test, * saved people finding keyframe items in menus when its not possible */ @@ -893,12 +891,6 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) "all", 1); } - if (is_editable /*&& is_idprop*/ && is_set) { - uiItemO(layout, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Unset"), - ICON_NONE, - "UI_OT_unset_property_button"); - } if (is_idprop && !is_array && ELEM(type, PROP_INT, PROP_FLOAT)) { uiItemO(layout, diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 178f663ff58..b52bfc81b7a 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -130,14 +130,19 @@ void eyedropper_draw_cursor_text_region(const struct bContext *C, const char *name) { wmWindow *win = CTX_wm_window(C); - const int x = win->eventstate->x - region->winrct.xmin; - const int y = win->eventstate->y - region->winrct.ymin; + const int x = win->eventstate->x; + const int y = win->eventstate->y; if ((name[0] == '\0') || (BLI_rcti_isect_pt(®ion->winrct, x, y) == false)) { return; } - eyedropper_draw_cursor_text_ex(x, y, name); + const int mval[2] = { + x - region->winrct.xmin, + y - region->winrct.ymin, + }; + + eyedropper_draw_cursor_text_ex(mval[0], mval[1], name); } /** diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c index 4ae6f66281f..ba72cecc514 100644 --- a/source/blender/editors/interface/interface_eyedropper_color.c +++ b/source/blender/editors/interface/interface_eyedropper_color.c @@ -116,14 +116,12 @@ static bool eyedropper_init(bContext *C, wmOperator *op) float col[4]; RNA_property_float_get_array(&eye->ptr, eye->prop, col); - if (ELEM(eye->ptr.type, &RNA_CompositorNodeCryptomatteV2, &RNA_CompositorNodeCryptomatte)) { + if (eye->ptr.type == &RNA_CompositorNodeCryptomatteV2) { eye->crypto_node = (bNode *)eye->ptr.data; - eye->cryptomatte_session = ntreeCompositCryptomatteSession(eye->crypto_node); + eye->cryptomatte_session = ntreeCompositCryptomatteSession(CTX_data_scene(C), + eye->crypto_node); eye->draw_handle_sample_text = WM_draw_cb_activate(CTX_wm_window(C), eyedropper_draw_cb, eye); } - else { - eye->crypto_node = NULL; - } if (prop_subtype != PROP_COLOR) { Scene *scene = CTX_data_scene(C); @@ -202,6 +200,57 @@ static bool eyedropper_cryptomatte_sample_renderlayer_fl(RenderLayer *render_lay return false; } +static bool eyedropper_cryptomatte_sample_render_fl(const bNode *node, + const char *prefix, + const float fpos[2], + float r_col[3]) +{ + bool success = false; + Scene *scene = (Scene *)node->id; + BLI_assert(GS(scene->id.name) == ID_SCE); + Render *re = RE_GetSceneRender(scene); + + if (re) { + RenderResult *rr = RE_AcquireResultRead(re); + if (rr) { + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { + RenderLayer *render_layer = RE_GetRenderLayer(rr, view_layer->name); + success = eyedropper_cryptomatte_sample_renderlayer_fl(render_layer, prefix, fpos, r_col); + if (success) { + break; + } + } + } + RE_ReleaseResult(re); + } + return success; +} + +static bool eyedropper_cryptomatte_sample_image_fl(const bNode *node, + NodeCryptomatte *crypto, + const char *prefix, + const float fpos[2], + float r_col[3]) +{ + bool success = false; + Image *image = (Image *)node->id; + BLI_assert((image == NULL) || (GS(image->id.name) == ID_IM)); + ImageUser *iuser = &crypto->iuser; + + if (image && image->type == IMA_TYPE_MULTILAYER) { + ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, NULL); + if (image->rr) { + LISTBASE_FOREACH (RenderLayer *, render_layer, &image->rr->layers) { + success = eyedropper_cryptomatte_sample_renderlayer_fl(render_layer, prefix, fpos, r_col); + if (success) { + break; + } + } + } + BKE_image_release_ibuf(image, ibuf, NULL); + } + return success; +} static bool eyedropper_cryptomatte_sample_fl( bContext *C, Eyedropper *eye, int mx, int my, float r_col[3]) @@ -258,53 +307,19 @@ static bool eyedropper_cryptomatte_sample_fl( return false; } - bool success = false; /* TODO(jbakker): Migrate this file to cc and use std::string as return param. */ char prefix[MAX_NAME + 1]; - ntreeCompositCryptomatteLayerPrefix(node, prefix, sizeof(prefix) - 1); + const Scene *scene = CTX_data_scene(C); + ntreeCompositCryptomatteLayerPrefix(scene, node, prefix, sizeof(prefix) - 1); prefix[MAX_NAME] = '\0'; if (node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER) { - Scene *scene = (Scene *)node->id; - BLI_assert(GS(scene->id.name) == ID_SCE); - Render *re = RE_GetSceneRender(scene); - - if (re) { - RenderResult *rr = RE_AcquireResultRead(re); - if (rr) { - LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { - RenderLayer *render_layer = RE_GetRenderLayer(rr, view_layer->name); - success = eyedropper_cryptomatte_sample_renderlayer_fl( - render_layer, prefix, fpos, r_col); - if (success) { - break; - } - } - } - RE_ReleaseResult(re); - } + return eyedropper_cryptomatte_sample_render_fl(node, prefix, fpos, r_col); } - else if (node->custom1 == CMP_CRYPTOMATTE_SRC_IMAGE) { - Image *image = (Image *)node->id; - BLI_assert(GS(image->id.name) == ID_IM); - ImageUser *iuser = &crypto->iuser; - - if (image && image->type == IMA_TYPE_MULTILAYER) { - ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, NULL); - if (image->rr) { - LISTBASE_FOREACH (RenderLayer *, render_layer, &image->rr->layers) { - success = eyedropper_cryptomatte_sample_renderlayer_fl( - render_layer, prefix, fpos, r_col); - if (success) { - break; - } - } - } - BKE_image_release_ibuf(image, ibuf, NULL); - } + if (node->custom1 == CMP_CRYPTOMATTE_SRC_IMAGE) { + return eyedropper_cryptomatte_sample_image_fl(node, crypto, prefix, fpos, r_col); } - - return success; + return false; } /** diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index a5a5a69728e..5f98a501bec 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -126,6 +126,24 @@ #define UI_MAX_PASSWORD_STR 128 /** + * This is a lower limit on the soft minimum of the range. + * Usually the derived lower limit from the visible precision is higher, + * so this number is the backup minimum. + * + * Logarithmic scale does not work with a minimum value of zero, + * but we want to support it anyway. It is set to 0.5e... for + * correct rounding since when the tweaked value is lower than + * the log minimum (lower limit), it will snap to 0. + */ +#define UI_PROP_SCALE_LOG_MIN 0.5e-8f +/** + * This constant defines an offset for the precision change in + * snap rounding, when going to higher values. It is set to + * `0.5 - log10(3) = 0.03` to make the switch at `0.3` values. + */ +#define UI_PROP_SCALE_LOG_SNAP_OFFSET 0.03f + +/** * When #USER_CONTINUOUS_MOUSE is disabled or tablet input is used, * Use this as a maximum soft range for mapping cursor motion to the value. * Otherwise min/max of #FLT_MAX, #INT_MAX cause small adjustments to jump to large numbers. @@ -477,6 +495,7 @@ static bool ui_do_but_extra_operator_icon(bContext *C, static void ui_do_but_extra_operator_icons_mousemove(uiBut *but, uiHandleButtonData *data, const wmEvent *event); +static void ui_numedit_begin_set_values(uiBut *but, uiHandleButtonData *data); #ifdef USE_DRAG_MULTINUM static void ui_multibut_restore(bContext *C, uiHandleButtonData *data, uiBlock *block); @@ -1114,6 +1133,13 @@ static void ui_apply_but_TAB(bContext *C, uiBut *but, uiHandleButtonData *data) static void ui_apply_but_NUM(bContext *C, uiBut *but, uiHandleButtonData *data) { if (data->str) { + double value; + /* Check if the string value is a number and cancel if it's equal to the startvalue. */ + if (ui_but_string_eval_number(C, but, data->str, &value) && (value == data->startvalue)) { + data->cancel = true; + return; + } + if (ui_but_string_set(C, but, data->str)) { data->value = ui_but_value_get(but); } @@ -2320,16 +2346,16 @@ static int get_but_property_array_length(uiBut *but) } static void ui_but_set_float_array( - bContext *C, uiBut *but, uiHandleButtonData *data, float *values, int array_length) + bContext *C, uiBut *but, uiHandleButtonData *data, const float *values, const int values_len) { button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); - for (int i = 0; i < array_length; i++) { + for (int i = 0; i < values_len; i++) { RNA_property_float_set_index(&but->rnapoin, but->rnaprop, i, values[i]); } if (data) { if (but->type == UI_BTYPE_UNITVEC) { - BLI_assert(array_length == 3); + BLI_assert(values_len == 3); copy_v3_v3(data->vec, values); } else { @@ -2340,56 +2366,39 @@ static void ui_but_set_float_array( button_activate_state(C, but, BUTTON_STATE_EXIT); } -static void float_array_to_string(float *values, - int array_length, +static void float_array_to_string(const float *values, + const int values_len, char *output, int output_len_max) { - /* to avoid buffer overflow attacks; numbers are quite arbitrary */ - BLI_assert(output_len_max > 15); - output_len_max -= 10; - - int current_index = 0; - output[current_index] = '['; - current_index++; - - for (int i = 0; i < array_length; i++) { - int length = BLI_snprintf( - output + current_index, output_len_max - current_index, "%f", values[i]); - current_index += length; - - if (i < array_length - 1) { - if (current_index < output_len_max) { - output[current_index + 0] = ','; - output[current_index + 1] = ' '; - current_index += 2; - } - } + const int values_end = values_len - 1; + int ofs = 0; + output[ofs++] = '['; + for (int i = 0; i < values_len; i++) { + ofs += BLI_snprintf_rlen( + output + ofs, output_len_max - ofs, (i != values_end) ? "%f, " : "%f]", values[i]); } - - output[current_index + 0] = ']'; - output[current_index + 1] = '\0'; } static void ui_but_copy_numeric_array(uiBut *but, char *output, int output_len_max) { - const int array_length = get_but_property_array_length(but); - float *values = alloca(array_length * sizeof(float)); + const int values_len = get_but_property_array_length(but); + float *values = alloca(values_len * sizeof(float)); RNA_property_float_get_array(&but->rnapoin, but->rnaprop, values); - float_array_to_string(values, array_length, output, output_len_max); + float_array_to_string(values, values_len, output, output_len_max); } -static bool parse_float_array(char *text, float *values, int expected_length) +static bool parse_float_array(char *text, float *values, int values_len_expected) { /* can parse max 4 floats for now */ - BLI_assert(0 <= expected_length && expected_length <= 4); + BLI_assert(0 <= values_len_expected && values_len_expected <= 4); float v[5]; - const int actual_length = sscanf( + const int values_len_actual = sscanf( text, "[%f, %f, %f, %f, %f]", &v[0], &v[1], &v[2], &v[3], &v[4]); - if (actual_length == expected_length) { - memcpy(values, v, sizeof(float) * expected_length); + if (values_len_actual == values_len_expected) { + memcpy(values, v, sizeof(float) * values_len_expected); return true; } return false; @@ -2400,16 +2409,16 @@ static void ui_but_paste_numeric_array(bContext *C, uiHandleButtonData *data, char *buf_paste) { - const int array_length = get_but_property_array_length(but); - if (array_length > 4) { + const int values_len = get_but_property_array_length(but); + if (values_len > 4) { /* not supported for now */ return; } - float *values = alloca(sizeof(float) * array_length); + float *values = alloca(sizeof(float) * values_len); - if (parse_float_array(buf_paste, values, array_length)) { - ui_but_set_float_array(C, but, data, values, array_length); + if (parse_float_array(buf_paste, values, values_len)) { + ui_but_set_float_array(C, but, data, values, values_len); } else { WM_report(RPT_ERROR, "Expected an array of numbers: [n, n, ...]"); @@ -3354,6 +3363,8 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) if (is_num_but) { BLI_assert(data->is_str_dynamic == false); ui_but_convert_to_unit_alt_name(but, data->str, data->maxlen); + + ui_numedit_begin_set_values(but, data); } /* won't change from now on */ @@ -3890,6 +3901,14 @@ static void ui_do_but_textedit_select( /** \name Button Number Editing (various types) * \{ */ +static void ui_numedit_begin_set_values(uiBut *but, uiHandleButtonData *data) +{ + data->startvalue = ui_but_value_get(but); + data->origvalue = data->startvalue; + data->value = data->origvalue; + but->editval = &data->value; +} + static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data) { if (but->type == UI_BTYPE_CURVE) { @@ -3915,19 +3934,21 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data) but->editvec = data->vec; } else { - float softrange, softmin, softmax; + ui_numedit_begin_set_values(but, data); - data->startvalue = ui_but_value_get(but); - data->origvalue = data->startvalue; - data->value = data->origvalue; - but->editval = &data->value; + float softmin = but->softmin; + float softmax = but->softmax; + float softrange = softmax - softmin; + const PropertyScaleType scale_type = ui_but_scale_type(but); - softmin = but->softmin; - softmax = but->softmax; - softrange = softmax - softmin; + float log_min = (scale_type == PROP_SCALE_LOG) ? max_ff(softmin, UI_PROP_SCALE_LOG_MIN) : 0.0f; if ((but->type == UI_BTYPE_NUM) && (ui_but_is_cursor_warp(but) == false)) { uiButNumber *number_but = (uiButNumber *)but; + + if (scale_type == PROP_SCALE_LOG) { + log_min = max_ff(log_min, powf(10, -number_but->precision) * 0.5f); + } /* Use a minimum so we have a predictable range, * otherwise some float buttons get a large range. */ const float value_step_float_min = 0.1f; @@ -3976,7 +3997,31 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data) } } - data->dragfstart = (softrange == 0.0f) ? 0.0f : ((float)data->value - softmin) / softrange; + if (softrange == 0.0f) { + data->dragfstart = 0.0f; + } + else { + switch (scale_type) { + case PROP_SCALE_LINEAR: { + data->dragfstart = ((float)data->value - softmin) / softrange; + break; + } + case PROP_SCALE_LOG: { + BLI_assert(log_min != 0.0f); + const float base = softmax / log_min; + data->dragfstart = logf((float)data->value / log_min) / logf(base); + break; + } + case PROP_SCALE_CUBIC: { + const float cubic_min = cube_f(softmin); + const float cubic_max = cube_f(softmax); + const float cubic_range = cubic_max - cubic_min; + const float f = ((float)data->value - softmin) * cubic_range / softrange + cubic_min; + data->dragfstart = (cbrtf(f) - softmin) / softrange; + break; + } + } + } data->dragf = data->dragfstart; data->drag_map_soft_min = softmin; @@ -4694,6 +4739,7 @@ static float ui_numedit_apply_snapf( /* pass */ } else { + const PropertyScaleType scale_type = ui_but_scale_type(but); float softrange = softmax - softmin; float fac = 1.0f; @@ -4731,31 +4777,30 @@ static float ui_numedit_apply_snapf( } } - if (snap == SNAP_ON) { - if (softrange < 2.10f) { - tempf = roundf(tempf * 10.0f) * 0.1f; - } - else if (softrange < 21.0f) { - tempf = roundf(tempf); - } - else { - tempf = roundf(tempf * 0.1f) * 10.0f; - } - } - else if (snap == SNAP_ON_SMALL) { - if (softrange < 2.10f) { - tempf = roundf(tempf * 100.0f) * 0.01f; - } - else if (softrange < 21.0f) { - tempf = roundf(tempf * 10.0f) * 0.1f; + BLI_assert(ELEM(snap, SNAP_ON, SNAP_ON_SMALL)); + switch (scale_type) { + case PROP_SCALE_LINEAR: + case PROP_SCALE_CUBIC: { + const float snap_fac = (snap == SNAP_ON_SMALL ? 0.1f : 1.0f); + if (softrange < 2.10f) { + tempf = roundf(tempf * 10.0f / snap_fac) * 0.1f * snap_fac; + } + else if (softrange < 21.0f) { + tempf = roundf(tempf / snap_fac) * snap_fac; + } + else { + tempf = roundf(tempf * 0.1f / snap_fac) * 10.0f * snap_fac; + } + break; } - else { - tempf = roundf(tempf); + case PROP_SCALE_LOG: { + const float snap_fac = powf(10.0f, + roundf(log10f(tempf) + UI_PROP_SCALE_LOG_SNAP_OFFSET) - + (snap == SNAP_ON_SMALL ? 2.0f : 1.0f)); + tempf = roundf(tempf / snap_fac) * snap_fac; + break; } } - else { - BLI_assert(0); - } if (fac != 1.0f) { tempf *= fac; @@ -4800,6 +4845,7 @@ static bool ui_numedit_but_NUM(uiButNumber *number_but, int lvalue, temp; bool changed = false; const bool is_float = ui_but_is_float(but); + const PropertyScaleType scale_type = ui_but_scale_type(but); /* prevent unwanted drag adjustments, test motion so modifier keys refresh. */ if ((is_motion || data->draglock) && (ui_but_dragedit_update_mval(data, mx) == false)) { @@ -4811,21 +4857,74 @@ static bool ui_numedit_but_NUM(uiButNumber *number_but, const float softmax = but->softmax; const float softrange = softmax - softmin; + const float log_min = (scale_type == PROP_SCALE_LOG) ? + max_ff(max_ff(softmin, UI_PROP_SCALE_LOG_MIN), + powf(10, -number_but->precision) * 0.5f) : + 0; + /* Mouse location isn't screen clamped to the screen so use a linear mapping * 2px == 1-int, or 1px == 1-ClickStep */ if (is_float) { fac *= 0.01f * number_but->step_size; - tempf = (float)data->startvalue + ((float)(mx - data->dragstartx) * fac); + switch (scale_type) { + case PROP_SCALE_LINEAR: { + tempf = (float)data->startvalue + (float)(mx - data->dragstartx) * fac; + break; + } + case PROP_SCALE_LOG: { + const float startvalue = max_ff((float)data->startvalue, log_min); + tempf = expf((float)(mx - data->dragstartx) * fac) * startvalue; + if (tempf <= log_min) { + tempf = 0.0f; + } + break; + } + case PROP_SCALE_CUBIC: { + tempf = cbrtf((float)data->startvalue) + (float)(mx - data->dragstartx) * fac; + tempf *= tempf * tempf; + break; + } + } + tempf = ui_numedit_apply_snapf(but, tempf, softmin, softmax, snap); #if 1 /* fake moving the click start, nicer for dragging back after passing the limit */ - if (tempf < softmin) { - data->dragstartx -= (softmin - tempf) / fac; - tempf = softmin; - } - else if (tempf > softmax) { - data->dragstartx += (tempf - softmax) / fac; - tempf = softmax; + switch (scale_type) { + case PROP_SCALE_LINEAR: { + if (tempf < softmin) { + data->dragstartx -= (softmin - tempf) / fac; + tempf = softmin; + } + else if (tempf > softmax) { + data->dragstartx -= (softmax - tempf) / fac; + tempf = softmax; + } + break; + } + case PROP_SCALE_LOG: { + if (tempf < log_min) { + data->dragstartx -= logf(log_min / (float)data->startvalue) / fac - + (float)(mx - data->dragstartx); + tempf = softmin; + } + else if (tempf > softmax) { + data->dragstartx -= logf(softmax / (float)data->startvalue) / fac - + (float)(mx - data->dragstartx); + tempf = softmax; + } + break; + } + case PROP_SCALE_CUBIC: { + if (tempf < softmin) { + data->dragstartx = mx - (int)((cbrtf(softmin) - cbrtf((float)data->startvalue)) / fac); + tempf = softmin; + } + else if (tempf > softmax) { + data->dragstartx = mx - (int)((cbrtf(softmax) - cbrtf((float)data->startvalue)) / fac); + tempf = softmax; + } + break; + } } #else CLAMP(tempf, softmin, softmax); @@ -4932,7 +5031,31 @@ static bool ui_numedit_but_NUM(uiButNumber *number_but, } data->draglastx = mx; - tempf = (softmin + data->dragf * softrange); + + switch (scale_type) { + case PROP_SCALE_LINEAR: { + tempf = (softmin + data->dragf * softrange); + break; + } + case PROP_SCALE_LOG: { + const float log_min = max_ff(max_ff(softmin, UI_PROP_SCALE_LOG_MIN), + powf(10.0f, -number_but->precision) * 0.5f); + const float base = softmax / log_min; + tempf = powf(base, data->dragf) * log_min; + if (tempf <= log_min) { + tempf = 0.0f; + } + break; + } + case PROP_SCALE_CUBIC: { + tempf = (softmin + data->dragf * softrange); + tempf *= tempf * tempf; + float cubic_min = softmin * softmin * softmin; + float cubic_max = softmax * softmax * softmax; + tempf = (tempf - cubic_min) / (cubic_max - cubic_min) * softrange + softmin; + break; + } + } if (!is_float) { temp = round_fl_to_int(tempf); @@ -5179,9 +5302,19 @@ static int ui_do_but_NUM( else { /* Float Value. */ if (but->drawflag & (UI_BUT_ACTIVE_LEFT | UI_BUT_ACTIVE_RIGHT)) { + const PropertyScaleType scale_type = ui_but_scale_type(but); + button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); - const double value_step = (double)number_but->step_size * UI_PRECISION_FLOAT_SCALE; + double value_step; + if (scale_type == PROP_SCALE_LOG) { + value_step = powf(10.0f, + (roundf(log10f(data->value) + UI_PROP_SCALE_LOG_SNAP_OFFSET) - 1.0f) + + log10f(number_but->step_size)); + } + else { + value_step = (double)number_but->step_size * UI_PRECISION_FLOAT_SCALE; + } BLI_assert(value_step > 0.0f); const double value_test = (but->drawflag & UI_BUT_ACTIVE_LEFT) ? (double)max_ff(but->softmin, @@ -5229,6 +5362,8 @@ static bool ui_numedit_but_SLI(uiBut *but, return changed; } + const PropertyScaleType scale_type = ui_but_scale_type(but); + softmin = but->softmin; softmax = but->softmax; softrange = softmax - softmin; @@ -5270,7 +5405,24 @@ static bool ui_numedit_but_SLI(uiBut *but, #endif /* done correcting mouse */ - tempf = softmin + f * softrange; + switch (scale_type) { + case PROP_SCALE_LINEAR: { + tempf = softmin + f * softrange; + break; + } + case PROP_SCALE_LOG: { + tempf = powf(softmax / softmin, f) * softmin; + break; + } + case PROP_SCALE_CUBIC: { + const float cubicmin = cube_f(softmin); + const float cubicmax = cube_f(softmax); + const float cubicrange = cubicmax - cubicmin; + tempf = cube_f(softmin + f * softrange); + tempf = (tempf - cubicmin) / cubicrange * softrange + softmin; + break; + } + } temp = round_fl_to_int(tempf); if (snap) { @@ -5464,6 +5616,8 @@ static int ui_do_but_SLI( if (click) { if (click == 2) { + const PropertyScaleType scale_type = ui_but_scale_type(but); + /* nudge slider to the left or right */ float f, tempf, softmin, softmax, softrange; int temp; @@ -5488,14 +5642,20 @@ static int ui_do_but_SLI( f = (float)(mx - but->rect.xmin) / (BLI_rctf_size_x(&but->rect)); } - f = softmin + f * softrange; + if (scale_type == PROP_SCALE_LOG) { + f = powf(softmax / softmin, f) * softmin; + } + else { + f = softmin + f * softrange; + } if (!ui_but_is_float(but)) { + int value_step = 1; if (f < temp) { - temp--; + temp -= value_step; } else { - temp++; + temp += value_step; } if (temp >= softmin && temp <= softmax) { @@ -5506,14 +5666,23 @@ static int ui_do_but_SLI( } } else { - if (f < tempf) { - tempf -= 0.01f; - } - else { - tempf += 0.01f; - } - if (tempf >= softmin && tempf <= softmax) { + float value_step; + if (scale_type == PROP_SCALE_LOG) { + value_step = powf(10.0f, roundf(log10f(tempf) + UI_PROP_SCALE_LOG_SNAP_OFFSET) - 1.0f); + } + else { + value_step = 0.01f; + } + + if (f < tempf) { + tempf -= value_step; + } + else { + tempf += value_step; + } + + CLAMP(tempf, softmin, softmax); data->value = tempf; } else { diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index c16c3d2c49a..4defbed940e 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -457,13 +457,15 @@ DEF_ICON_VECTOR_COLORSET_DRAW_NTH(20, 19) # undef DEF_ICON_VECTOR_COLORSET_DRAW_NTH static void vicon_collection_color_draw( - short color_tag, int x, int y, int UNUSED(w), int UNUSED(h), float UNUSED(alpha)) + short color_tag, int x, int y, int w, int UNUSED(h), float UNUSED(alpha)) { bTheme *btheme = UI_GetTheme(); const ThemeCollectionColor *collection_color = &btheme->collection_color[color_tag]; + const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w; + UI_icon_draw_ex( - x, y, ICON_OUTLINER_COLLECTION, U.inv_dpi_fac, 1.0f, 0.0f, collection_color->color, true); + x, y, ICON_OUTLINER_COLLECTION, aspect, 1.0f, 0.0f, collection_color->color, true); } # define DEF_ICON_COLLECTION_COLOR_DRAW(index, color) \ @@ -1426,13 +1428,7 @@ static void icon_set_image(const bContext *C, scene = CTX_data_scene(C); } /* Immediate version */ - ED_preview_icon_render(CTX_data_main(C), - CTX_data_ensure_evaluated_depsgraph(C), - scene, - id, - prv_img->rect[size], - prv_img->w[size], - prv_img->h[size]); + ED_preview_icon_render(C, scene, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]); } } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 4c96512b4f3..23856c41ceb 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -62,7 +62,7 @@ struct wmTimer; #define UI_MENU_PADDING (int)(0.2f * UI_UNIT_Y) #define UI_MENU_WIDTH_MIN (UI_UNIT_Y * 9) -/* some extra padding added to menus containing submenu icons */ +/** Some extra padding added to menus containing sub-menu icons. */ #define UI_MENU_SUBMENU_PADDING (6 * UI_DPI_FAC) /* menu scrolling */ @@ -74,28 +74,31 @@ struct wmTimer; #define UI_PANEL_MINX 100 #define UI_PANEL_MINY 70 -/* popover width (multiplied by 'U.widget_unit') */ +/** Popover width (multiplied by #U.widget_unit) */ #define UI_POPOVER_WIDTH_UNITS 10 -/* uiBut->flag */ +/** #uiBut.flag */ enum { - UI_SELECT = (1 << 0), /* use when the button is pressed */ - UI_SCROLLED = (1 << 1), /* temp hidden, scrolled away */ + /** Use when the button is pressed. */ + UI_SELECT = (1 << 0), + /** Temporarily hidden (scrolled out of the view). */ + UI_SCROLLED = (1 << 1), UI_ACTIVE = (1 << 2), UI_HAS_ICON = (1 << 3), UI_HIDDEN = (1 << 4), - UI_SELECT_DRAW = (1 << 5), /* Display selected, doesn't impact interaction. */ + /** Display selected, doesn't impact interaction. */ + UI_SELECT_DRAW = (1 << 5), /** Property search filter is active and the button does not match. */ - UI_SEARCH_FILTER_NO_MATCH = (1 << 12), - /* warn: rest of uiBut->flag in UI_interface.h */ + UI_SEARCH_FILTER_NO_MATCH = (1 << 6), + /* WARNING: rest of #uiBut.flag in UI_interface.h */ }; -/* uiBut->dragflag */ +/** #uiBut.dragflag */ enum { UI_BUT_DRAGPOIN_FREE = (1 << 0), }; -/* but->pie_dir */ +/** #uiBut.pie_dir */ typedef enum RadialDirection { UI_RADIAL_NONE = -1, UI_RADIAL_N = 0, @@ -126,13 +129,13 @@ extern const short ui_radial_dir_to_angle[8]; #define UI_BITBUT_ROW(min, max) \ (((max) >= 31 ? 0xFFFFFFFF : (1 << ((max) + 1)) - 1) - ((min) ? ((1 << (min)) - 1) : 0)) -/* split numbuts by ':' and align l/r */ +/** Split number-buttons by ':' and align left/right. */ #define USE_NUMBUTS_LR_ALIGN -/* Use new 'align' computation code. */ +/** Use new 'align' computation code. */ #define USE_UIBUT_SPATIAL_ALIGN -/* PieMenuData->flags */ +/** #PieMenuData.flags */ enum { /** pie menu item collision is detected at 90 degrees */ UI_PIE_DEGREES_RANGE_LARGE = (1 << 0), @@ -152,13 +155,13 @@ enum { #define PIE_CLICK_THRESHOLD_SQ 50.0f -/* max amount of items a radial menu (pie menu) can contain */ +/** The maximum number of items a radial menu (pie menu) can contain. */ #define PIE_MAX_ITEMS 8 struct uiBut { struct uiBut *next, *prev; - /* Pointer back to the layout item holding this button. */ + /** Pointer back to the layout item holding this button. */ uiLayout *layout; int flag, drawflag; eButType type; @@ -235,10 +238,10 @@ struct uiBut { short modifier_key; short iconadd; - /* UI_BTYPE_BLOCK data */ + /** #UI_BTYPE_BLOCK data */ uiBlockCreateFunc block_create_func; - /* UI_BTYPE_PULLDOWN/UI_BTYPE_MENU data */ + /** #UI_BTYPE_PULLDOWN / #UI_BTYPE_MENU data */ uiMenuCreateFunc menu_create_func; uiMenuStepFunc menu_step_func; @@ -252,9 +255,11 @@ struct uiBut { struct wmOperatorType *optype; struct PointerRNA *opptr; short opcontext; - uchar menu_key; /* 'a'-'z', always lower case */ - ListBase extra_op_icons; /* uiButExtraOpIcon */ + /** When non-zero, this is the key used to activate a menu items (`a-z` always lower case). */ + uchar menu_key; + + ListBase extra_op_icons; /** #uiButExtraOpIcon */ /* Draggable data, type is WM_DRAG_... */ char dragtype; @@ -263,10 +268,10 @@ struct uiBut { struct ImBuf *imb; float imb_scale; - /* active button data */ + /** Active button data (set when the user is hovering or interacting with a button). */ struct uiHandleButtonData *active; - /* Custom button data. */ + /** Custom button data (borrowed, not owned). */ void *custom_data; char *editstr; @@ -429,7 +434,7 @@ struct PieMenuData { float alphafac; }; -/* uiBlock.content_hints */ +/** #uiBlock.content_hints */ enum eBlockContentHints { /** In a menu block, if there is a single sub-menu button, we add some * padding to the right to put nicely aligned triangle icons there. */ @@ -463,7 +468,8 @@ struct uiBlock { struct Panel *panel; uiBlock *oldblock; - ListBase butstore; /* UI_butstore_* runtime function */ + /** Used for `UI_butstore_*` runtime function. */ + ListBase butstore; ListBase button_groups; /* #uiButtonGroup. */ @@ -479,7 +485,8 @@ struct uiBlock { rctf rect; float aspect; - uint puphash; /* popup menu hash for memory */ + /** Unique hash used to implement popup menu memory. */ + uint puphash; uiButHandleFunc func; void *func_arg1; @@ -494,10 +501,10 @@ struct uiBlock { uiBlockHandleFunc handle_func; void *handle_func_arg; - /* custom extra handling */ + /** Custom extra event handling. */ int (*block_event_func)(const struct bContext *C, struct uiBlock *, const struct wmEvent *); - /* extra draw function for custom blocks */ + /** Custom extra draw function for custom blocks. */ void (*drawextra)(const struct bContext *C, void *idv, void *arg1, void *arg2, rcti *rect); void *drawextra_arg1; void *drawextra_arg2; @@ -507,7 +514,7 @@ struct uiBlock { /** Hints about the buttons of this block. Used to avoid iterating over * buttons to find out if some criteria is met by any. Instead, check this * criteria when adding the button and set a flag here if it's met. */ - short content_hints; /* eBlockContentHints */ + short content_hints; /* #eBlockContentHints */ char direction; /** UI_BLOCK_THEME_STYLE_* */ @@ -521,11 +528,11 @@ struct uiBlock { const char *lockstr; bool lock; - /** to keep blocks while drawing and free them afterwards */ + /** To keep blocks while drawing and free them afterwards. */ bool active; - /** to avoid tooltip after click */ + /** To avoid tool-tip after click. */ bool tooltipdisabled; - /** UI_block_end done? */ + /** True when #UI_block_end has been called. */ bool endblock; /** for doing delayed */ @@ -535,12 +542,12 @@ struct uiBlock { /** for doing delayed */ int bounds, minbounds; - /** pull-downs, to detect outside, can differ per case how it is created. */ + /** Pull-downs, to detect outside, can differ per case how it is created. */ rctf safety; - /** uiSafetyRct list */ + /** #uiSafetyRct list */ ListBase saferct; - uiPopupBlockHandle *handle; /* handle */ + uiPopupBlockHandle *handle; /** use so presets can find the operator, * across menus and from nested popups which fail for operator context. */ @@ -555,10 +562,12 @@ struct uiBlock { /** \note only accessed by color picker templates. */ ColorPickerData color_pickers; - bool is_color_gamma_picker; /* Block for color picker with gamma baked in. */ + /** Block for color picker with gamma baked in. */ + bool is_color_gamma_picker; - /** display device name used to display this block, - * used by color widgets to transform colors from/to scene linear + /** + * Display device name used to display this block, + * used by color widgets to transform colors from/to scene linear. */ char display_device[64]; @@ -651,6 +660,7 @@ bool ui_but_context_poll_operator(struct bContext *C, struct wmOperatorType *ot, extern void ui_but_update(uiBut *but); extern void ui_but_update_edited(uiBut *but); +extern PropertyScaleType ui_but_scale_type(const uiBut *but) ATTR_WARN_UNUSED_RESULT; extern bool ui_but_is_float(const uiBut *but) ATTR_WARN_UNUSED_RESULT; extern bool ui_but_is_bool(const uiBut *but) ATTR_WARN_UNUSED_RESULT; extern bool ui_but_is_unit(const uiBut *but) ATTR_WARN_UNUSED_RESULT; @@ -671,9 +681,9 @@ void ui_block_cm_to_display_space_v3(uiBlock *block, float pixel[3]); /* interface_regions.c */ struct uiKeyNavLock { - /* Set when we're using key-input. */ + /** Set when we're using keyboard-input. */ bool is_keynav; - /* only used to check if we've moved the cursor */ + /** Only used to check if we've moved the cursor. */ int event_xy[2]; }; @@ -689,7 +699,7 @@ struct uiPopupBlockCreate { int event_xy[2]; - /* when popup is initialized from a button */ + /** Set when popup is initialized from a button. */ struct ARegion *butregion; uiBut *but; }; @@ -698,7 +708,7 @@ struct uiPopupBlockHandle { /* internal */ struct ARegion *region; - /* use only for 'UI_BLOCK_MOVEMOUSE_QUIT' popups */ + /** Use only for #UI_BLOCK_MOVEMOUSE_QUIT popups. */ float towards_xy[2]; double towardstime; bool dotowards; @@ -708,9 +718,9 @@ struct uiPopupBlockHandle { void (*cancel_func)(struct bContext *C, void *arg); void *popup_arg; - /* store data for refreshing popups */ + /** Store data for refreshing popups. */ struct uiPopupBlockCreate popup_create_vars; - /* true if we can re-create the popup using 'popup_create_vars' */ + /** True if we can re-create the popup using #uiPopupBlockHandle.popup_create_vars. */ bool can_refresh; bool refresh; @@ -730,7 +740,7 @@ struct uiPopupBlockHandle { int retvalue; float retvec[4]; - /* menu direction */ + /** Menu direction. */ int direction; /* Previous values so we don't resize or reposition on refresh. */ @@ -924,9 +934,7 @@ extern void ui_but_execute_end(struct bContext *C, void *active_back); extern void ui_but_active_free(const struct bContext *C, uiBut *but); extern int ui_but_menu_direction(uiBut *but); -extern void ui_but_text_password_hide(char password_str[UI_MAX_DRAW_STR], - uiBut *but, - const bool restore); +extern void ui_but_text_password_hide(char password_str[128], uiBut *but, const bool restore); extern uiBut *ui_but_find_select_in_enum(uiBut *but, int direction); bool ui_but_is_editing(const uiBut *but); float ui_block_calc_pie_segment(struct uiBlock *block, const float event_xy[2]); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 4430d00f2e3..c04432a2912 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -2718,6 +2718,7 @@ uiBut *ui_but_add_search( ui_searchbox_create_generic, ui_rna_collection_search_update_fn, coll_search, + false, ui_rna_collection_search_arg_free_fn, NULL, NULL); @@ -3037,7 +3038,7 @@ void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, i /* popover */ void uiItemPopoverPanel_ptr( - uiLayout *layout, bContext *C, PanelType *pt, const char *name, int icon) + uiLayout *layout, const bContext *C, PanelType *pt, const char *name, int icon) { if (!name) { name = CTX_IFACE_(pt->translation_context, pt->label); @@ -3066,7 +3067,7 @@ void uiItemPopoverPanel_ptr( } void uiItemPopoverPanel( - uiLayout *layout, bContext *C, const char *panel_type, const char *name, int icon) + uiLayout *layout, const bContext *C, const char *panel_type, const char *name, int icon) { PanelType *pt = WM_paneltype_find(panel_type, true); if (pt == NULL) { @@ -4041,12 +4042,11 @@ static void ui_litem_layout_column_flow(uiLayout *litem) int emy = 0; int miny = 0; - int w = litem->w - (flow->totcol - 1) * style->columnspace; emh = toth / flow->totcol; /* create column per column */ col = 0; - w = (litem->w - (flow->totcol - 1) * style->columnspace) / flow->totcol; + int w = (litem->w - (flow->totcol - 1) * style->columnspace) / flow->totcol; LISTBASE_FOREACH (uiItem *, item, &litem->items) { ui_item_size(item, &itemw, &itemh); diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 540e98f542e..0cf3ad59903 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -72,6 +72,7 @@ #include "BKE_main.h" #include "BLI_ghash.h" #include "ED_screen.h" +#include "ED_text.h" /* -------------------------------------------------------------------- */ /** \name Copy Data Path Operator @@ -1336,18 +1337,23 @@ static int editsource_text_edit(bContext *C, return OPERATOR_CANCELLED; } + txt_move_toline(text, line - 1, false); + /* naughty!, find text area to set, not good behavior * but since this is a dev tool lets allow it - campbell */ ScrArea *area = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TEXT, 0); if (area) { SpaceText *st = area->spacedata.first; + ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); st->text = text; + if (region) { + ED_text_scroll_to_cursor(st, region, true); + } } else { BKE_reportf(op->reports, RPT_INFO, "See '%s' in the text editor", text->id.name + 2); } - txt_move_toline(text, line - 1, false); WM_event_add_notifier(C, NC_TEXT | ND_CURSOR, text); return OPERATOR_FINISHED; @@ -1374,7 +1380,9 @@ static int editsource_exec(bContext *C, wmOperator *op) /* redraw and get active button python info */ ED_region_do_layout(C, region); + WM_draw_region_viewport_bind(region); ED_region_do_draw(C, region); + WM_draw_region_viewport_unbind(region); region->do_draw = false; for (BLI_ghashIterator_init(&ghi, ui_editsource_info->hash); @@ -1487,117 +1495,115 @@ static void edittranslation_find_po_file(const char *root, static int edittranslation_exec(bContext *C, wmOperator *op) { uiBut *but = UI_context_active_but_get(C); - int ret = OPERATOR_CANCELLED; - - if (but) { - wmOperatorType *ot; - PointerRNA ptr; - char popath[FILE_MAX]; - const char *root = U.i18ndir; - const char *uilng = BLT_lang_get(); - - uiStringInfo but_label = {BUT_GET_LABEL, NULL}; - uiStringInfo rna_label = {BUT_GET_RNA_LABEL, NULL}; - uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL}; - uiStringInfo but_tip = {BUT_GET_TIP, NULL}; - uiStringInfo rna_tip = {BUT_GET_RNA_TIP, NULL}; - uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, NULL}; - uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, NULL}; - uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, NULL}; - uiStringInfo rna_enum = {BUT_GET_RNAENUM_IDENTIFIER, NULL}; - uiStringInfo rna_ctxt = {BUT_GET_RNA_LABEL_CONTEXT, NULL}; - - if (!BLI_is_dir(root)) { - BKE_report(op->reports, - RPT_ERROR, - "Please set your Preferences' 'Translation Branches " - "Directory' path to a valid directory"); - return OPERATOR_CANCELLED; - } - ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0); - if (ot == NULL) { - BKE_reportf(op->reports, - RPT_ERROR, - "Could not find operator '%s'! Please enable ui_translate add-on " - "in the User Preferences", - EDTSRC_I18N_OP_NAME); - return OPERATOR_CANCELLED; - } - /* Try to find a valid po file for current language... */ - edittranslation_find_po_file(root, uilng, popath, FILE_MAX); - /* printf("po path: %s\n", popath); */ - if (popath[0] == '\0') { - BKE_reportf( - op->reports, RPT_ERROR, "No valid po found for language '%s' under %s", uilng, root); - return OPERATOR_CANCELLED; - } - - UI_but_string_info_get(C, - but, - &but_label, - &rna_label, - &enum_label, - &but_tip, - &rna_tip, - &enum_tip, - &rna_struct, - &rna_prop, - &rna_enum, - &rna_ctxt, - NULL); - - WM_operator_properties_create_ptr(&ptr, ot); - RNA_string_set(&ptr, "lang", uilng); - RNA_string_set(&ptr, "po_file", popath); - RNA_string_set(&ptr, "but_label", but_label.strinfo); - RNA_string_set(&ptr, "rna_label", rna_label.strinfo); - RNA_string_set(&ptr, "enum_label", enum_label.strinfo); - RNA_string_set(&ptr, "but_tip", but_tip.strinfo); - RNA_string_set(&ptr, "rna_tip", rna_tip.strinfo); - RNA_string_set(&ptr, "enum_tip", enum_tip.strinfo); - RNA_string_set(&ptr, "rna_struct", rna_struct.strinfo); - RNA_string_set(&ptr, "rna_prop", rna_prop.strinfo); - RNA_string_set(&ptr, "rna_enum", rna_enum.strinfo); - RNA_string_set(&ptr, "rna_ctxt", rna_ctxt.strinfo); - ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); - - /* Clean up */ - if (but_label.strinfo) { - MEM_freeN(but_label.strinfo); - } - if (rna_label.strinfo) { - MEM_freeN(rna_label.strinfo); - } - if (enum_label.strinfo) { - MEM_freeN(enum_label.strinfo); - } - if (but_tip.strinfo) { - MEM_freeN(but_tip.strinfo); - } - if (rna_tip.strinfo) { - MEM_freeN(rna_tip.strinfo); - } - if (enum_tip.strinfo) { - MEM_freeN(enum_tip.strinfo); - } - if (rna_struct.strinfo) { - MEM_freeN(rna_struct.strinfo); - } - if (rna_prop.strinfo) { - MEM_freeN(rna_prop.strinfo); - } - if (rna_enum.strinfo) { - MEM_freeN(rna_enum.strinfo); - } - if (rna_ctxt.strinfo) { - MEM_freeN(rna_ctxt.strinfo); - } + if (but == NULL) { + BKE_report(op->reports, RPT_ERROR, "Active button not found"); + return OPERATOR_CANCELLED; + } - return ret; + wmOperatorType *ot; + PointerRNA ptr; + char popath[FILE_MAX]; + const char *root = U.i18ndir; + const char *uilng = BLT_lang_get(); + + uiStringInfo but_label = {BUT_GET_LABEL, NULL}; + uiStringInfo rna_label = {BUT_GET_RNA_LABEL, NULL}; + uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL}; + uiStringInfo but_tip = {BUT_GET_TIP, NULL}; + uiStringInfo rna_tip = {BUT_GET_RNA_TIP, NULL}; + uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, NULL}; + uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, NULL}; + uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, NULL}; + uiStringInfo rna_enum = {BUT_GET_RNAENUM_IDENTIFIER, NULL}; + uiStringInfo rna_ctxt = {BUT_GET_RNA_LABEL_CONTEXT, NULL}; + + if (!BLI_is_dir(root)) { + BKE_report(op->reports, + RPT_ERROR, + "Please set your Preferences' 'Translation Branches " + "Directory' path to a valid directory"); + return OPERATOR_CANCELLED; + } + ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0); + if (ot == NULL) { + BKE_reportf(op->reports, + RPT_ERROR, + "Could not find operator '%s'! Please enable ui_translate add-on " + "in the User Preferences", + EDTSRC_I18N_OP_NAME); + return OPERATOR_CANCELLED; + } + /* Try to find a valid po file for current language... */ + edittranslation_find_po_file(root, uilng, popath, FILE_MAX); + /* printf("po path: %s\n", popath); */ + if (popath[0] == '\0') { + BKE_reportf( + op->reports, RPT_ERROR, "No valid po found for language '%s' under %s", uilng, root); + return OPERATOR_CANCELLED; } - BKE_report(op->reports, RPT_ERROR, "Active button not found"); - return OPERATOR_CANCELLED; + UI_but_string_info_get(C, + but, + &but_label, + &rna_label, + &enum_label, + &but_tip, + &rna_tip, + &enum_tip, + &rna_struct, + &rna_prop, + &rna_enum, + &rna_ctxt, + NULL); + + WM_operator_properties_create_ptr(&ptr, ot); + RNA_string_set(&ptr, "lang", uilng); + RNA_string_set(&ptr, "po_file", popath); + RNA_string_set(&ptr, "but_label", but_label.strinfo); + RNA_string_set(&ptr, "rna_label", rna_label.strinfo); + RNA_string_set(&ptr, "enum_label", enum_label.strinfo); + RNA_string_set(&ptr, "but_tip", but_tip.strinfo); + RNA_string_set(&ptr, "rna_tip", rna_tip.strinfo); + RNA_string_set(&ptr, "enum_tip", enum_tip.strinfo); + RNA_string_set(&ptr, "rna_struct", rna_struct.strinfo); + RNA_string_set(&ptr, "rna_prop", rna_prop.strinfo); + RNA_string_set(&ptr, "rna_enum", rna_enum.strinfo); + RNA_string_set(&ptr, "rna_ctxt", rna_ctxt.strinfo); + const int ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); + + /* Clean up */ + if (but_label.strinfo) { + MEM_freeN(but_label.strinfo); + } + if (rna_label.strinfo) { + MEM_freeN(rna_label.strinfo); + } + if (enum_label.strinfo) { + MEM_freeN(enum_label.strinfo); + } + if (but_tip.strinfo) { + MEM_freeN(but_tip.strinfo); + } + if (rna_tip.strinfo) { + MEM_freeN(rna_tip.strinfo); + } + if (enum_tip.strinfo) { + MEM_freeN(enum_tip.strinfo); + } + if (rna_struct.strinfo) { + MEM_freeN(rna_struct.strinfo); + } + if (rna_prop.strinfo) { + MEM_freeN(rna_prop.strinfo); + } + if (rna_enum.strinfo) { + MEM_freeN(rna_enum.strinfo); + } + if (rna_ctxt.strinfo) { + MEM_freeN(rna_ctxt.strinfo); + } + + return ret; } static void UI_OT_edittranslation_init(wmOperatorType *ot) diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 7343417137a..6505a7cd76a 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -437,15 +437,21 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr /* Find how many instanced panels with this context string. */ int list_panels_len = 0; + int start_index = -1; LISTBASE_FOREACH (const Panel *, panel, ®ion->panels) { if (panel->type) { if (panel->type->flag & PANEL_TYPE_INSTANCED) { if (panel_type_context_poll(region, panel->type, context)) { + if (panel == drag_panel) { + BLI_assert(start_index == -1); /* This panel should only appear once. */ + start_index = list_panels_len; + } list_panels_len++; } } } } + BLI_assert(start_index != -1); /* The drag panel should definitely be in the list. */ /* Sort the matching instanced panels by their display order. */ PanelSort *panel_sort = MEM_callocN(list_panels_len * sizeof(*panel_sort), __func__); @@ -472,6 +478,11 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr MEM_freeN(panel_sort); + if (move_to_index == start_index) { + /* In this case, the reorder was not changed, so don't do any updates or call the callback. */ + return; + } + /* Set the bit to tell the interface to instanced the list. */ drag_panel->flag |= PNL_INSTANCED_LIST_ORDER_CHANGED; @@ -2529,9 +2540,8 @@ PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wm { ARegion *region = CTX_wm_region(C); - Panel *panel = NULL; LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { - panel = block->panel; + Panel *panel = block->panel; if (panel == NULL) { continue; } @@ -2541,15 +2551,11 @@ PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wm ui_window_to_block(region, block, &mx, &my); const int mouse_state = ui_panel_mouse_state_get(block, panel, mx, my); if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) { - break; + return UI_panel_custom_data_get(panel); } } - if (panel == NULL) { - return NULL; - } - - return UI_panel_custom_data_get(panel); + return NULL; } /** \} */ diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c index f234f0fbbf5..58a74a3473e 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.c +++ b/source/blender/editors/interface/interface_region_menu_popup.c @@ -86,6 +86,17 @@ int ui_but_menu_step(uiBut *but, int direction) return 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Popup Menu Memory + * + * Support menu-memory, a feature that positions the cursor + * over the previously used menu item. + * + * \note This is stored for each unique menu title. + * \{ */ + static uint ui_popup_string_hash(const char *str, const bool use_sep) { /* sometimes button contains hotkey, sometimes not, strip for proper compare */ @@ -392,7 +403,7 @@ uiPopupMenu *UI_popup_menu_begin_ex(bContext *C, pup->layout = UI_block_layout( pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style); - /* note, this intentionally differs from the menu & submenu default because many operators + /* note, this intentionally differs from the menu & sub-menu default because many operators * use popups like this to select one of their options - * where having invoke doesn't make sense */ uiLayoutSetOperatorContext(pup->layout, WM_OP_EXEC_REGION_WIN); diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c index 12044863b8c..987cde61f97 100644 --- a/source/blender/editors/interface/interface_region_search.c +++ b/source/blender/editors/interface/interface_region_search.c @@ -677,8 +677,7 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region) } /* The previous menu item draws the active selection. */ - ui_draw_menu_item( - &data->fstyle, &rect, name_sep, icon, state & ~UI_ACTIVE, separator_type, NULL); + ui_draw_menu_item(&data->fstyle, &rect, name_sep, icon, state, separator_type, NULL); } } /* indicate more */ diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index 244cf7622e0..accfb78ab94 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -428,7 +428,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is if (has_valid_context == false) { expr_result = BLI_strdup(has_valid_context_error); } - else if (BPY_run_string_as_string(C, expr_imports, expr, __func__, &expr_result)) { + else if (BPY_run_string_as_string(C, expr_imports, expr, NULL, &expr_result)) { if (STREQ(expr_result, "")) { MEM_freeN(expr_result); expr_result = NULL; @@ -485,7 +485,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is if (has_valid_context == false) { expr_result = BLI_strdup(has_valid_context_error); } - else if (BPY_run_string_as_string(C, expr_imports, expr, __func__, &expr_result)) { + else if (BPY_run_string_as_string(C, expr_imports, expr, NULL, &expr_result)) { if (STREQ(expr_result, ".")) { MEM_freeN(expr_result); expr_result = NULL; @@ -589,7 +589,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is if (has_valid_context == false) { shortcut = BLI_strdup(has_valid_context_error); } - else if (BPY_run_string_as_intptr(C, expr_imports, expr, __func__, &expr_result)) { + else if (BPY_run_string_as_intptr(C, expr_imports, expr, NULL, &expr_result)) { if (expr_result != 0) { wmKeyMap *keymap = (wmKeyMap *)expr_result; LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { @@ -654,7 +654,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is /* pass */ } else if (BPY_run_string_as_string_and_size( - C, expr_imports, expr, __func__, &expr_result, &expr_result_len)) { + C, expr_imports, expr, NULL, &expr_result, &expr_result_len)) { /* pass. */ } } @@ -731,7 +731,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is if (has_valid_context == false) { /* pass */ } - else if (BPY_run_string_as_intptr(C, expr_imports, expr, __func__, &expr_result)) { + else if (BPY_run_string_as_intptr(C, expr_imports, expr, NULL, &expr_result)) { if (expr_result != 0) { { uiTooltipField *field = text_field_add(data, @@ -947,12 +947,13 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) /* button is disabled, we may be able to tell user why */ if (but->flag & UI_BUT_DISABLED) { const char *disabled_msg = NULL; + bool disabled_msg_free = false; /* if operator poll check failed, it can give pretty precise info why */ if (but->optype) { - CTX_wm_operator_poll_msg_set(C, NULL); + CTX_wm_operator_poll_msg_clear(C); WM_operator_poll_context(C, but->optype, but->opcontext); - disabled_msg = CTX_wm_operator_poll_msg_get(C); + disabled_msg = CTX_wm_operator_poll_msg_get(C, &disabled_msg_free); } /* alternatively, buttons can store some reasoning too */ else if (but->disabled_info) { @@ -967,6 +968,9 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) }); field->text = BLI_sprintfN(TIP_("Disabled: %s"), disabled_msg); } + if (disabled_msg_free) { + MEM_freeN((void *)disabled_msg); + } } if ((U.flag & USER_TOOLTIPS_PYTHON) && !but->optype && rna_struct.strinfo) { @@ -1469,9 +1473,10 @@ ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz) */ if (gz->type->screen_bounds_get) { rcti bounds; - gz->type->screen_bounds_get(C, gz, &bounds); - init_position[0] = bounds.xmin; - init_position[1] = bounds.ymin; + if (gz->type->screen_bounds_get(C, gz, &bounds)) { + init_position[0] = bounds.xmin; + init_position[1] = bounds.ymin; + } } return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect); diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c index ff42d434f29..91ad6619889 100644 --- a/source/blender/editors/interface/interface_template_search_menu.c +++ b/source/blender/editors/interface/interface_template_search_menu.c @@ -510,11 +510,19 @@ static struct MenuSearch_Data *menu_items_from_ui_create( const char *global_menu_prefix = NULL; if (include_all_areas) { + bScreen *screen = WM_window_get_active_screen(win); + /* First create arrays for ui_type. */ PropertyRNA *prop_ui_type = NULL; { + /* This must be a valid pointer, with only it's type checked. */ + ScrArea area_dummy = { + /* Anything besides #SPACE_EMPTY is fine, + * as this value is only included in the enum when set. */ + .spacetype = SPACE_TOPBAR, + }; PointerRNA ptr; - RNA_pointer_create(NULL, &RNA_Area, NULL, &ptr); + RNA_pointer_create(&screen->id, &RNA_Area, &area_dummy, &ptr); prop_ui_type = RNA_struct_find_property(&ptr, "ui_type"); RNA_property_enum_items(C, &ptr, @@ -529,7 +537,6 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } } - bScreen *screen = WM_window_get_active_screen(win); LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); if (region != NULL) { @@ -1141,6 +1148,7 @@ void UI_but_func_menu_search(uiBut *but) ui_searchbox_create_menu, menu_search_update_fn, data, + false, menu_search_arg_free_fn, menu_search_exec_fn, NULL); diff --git a/source/blender/editors/interface/interface_template_search_operator.c b/source/blender/editors/interface/interface_template_search_operator.c index 2c83f184ff0..2b765a1a2f5 100644 --- a/source/blender/editors/interface/interface_template_search_operator.c +++ b/source/blender/editors/interface/interface_template_search_operator.c @@ -121,6 +121,7 @@ void UI_but_func_operator_search(uiBut *but) operator_search_update_fn, NULL, false, + NULL, operator_search_exec_fn, NULL); } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 2d1663a3ecd..3990ad68c4d 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -309,6 +309,7 @@ static uiBlock *template_common_search_menu(const bContext *C, ui_searchbox_create_generic, search_update_fn, search_arg, + false, NULL, search_exec_fn, active_item); @@ -652,7 +653,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) /* Only remap that specific ID usage to overriding local data-block. */ ID *override_id = BKE_lib_override_library_create_from_id(bmain, id, false); if (override_id != NULL) { - BKE_main_id_clear_newpoins(bmain); + BKE_main_id_newptr_and_tag_clear(bmain); if (GS(override_id->name) == ID_OB) { Scene *scene = CTX_data_scene(C); @@ -671,7 +672,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) } else { if (BKE_lib_id_make_local(bmain, id, false, 0)) { - BKE_main_id_clear_newpoins(bmain); + BKE_main_id_newptr_and_tag_clear(bmain); /* reassign to get get proper updates/notifiers */ idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); @@ -1077,7 +1078,7 @@ static void template_ID(const bContext *C, char numstr[32]; short numstr_len; - numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", ID_REAL_USERS(id)); + numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", ID_REAL_USERS(id)); but = uiDefBut( block, @@ -1109,7 +1110,7 @@ static void template_ID(const bContext *C, UI_but_flag_enable(but, UI_BUT_REDALERT); } - if (id->lib == NULL && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS)) && + if (id->lib == NULL && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_OB, ID_WS)) && (hide_buttons == false)) { uiDefIconButR(block, UI_BTYPE_ICON_TOGGLE, @@ -6829,6 +6830,7 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C) uiLayout *ui_abs = uiLayoutAbsolute(layout, false); uiBlock *block = uiLayoutGetBlock(ui_abs); + eUIEmbossType previous_emboss = UI_block_emboss_get(block); UI_fontstyle_set(&style->widgetlabel); int width = BLF_width(style->widgetlabel.uifont_id, report->message, report->len); @@ -6903,6 +6905,8 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C) width + UI_UNIT_X, UI_UNIT_Y, "Show in Info Log"); + + UI_block_emboss_set(block, previous_emboss); } void uiTemplateInputStatus(uiLayout *layout, struct bContext *C) @@ -7191,7 +7195,7 @@ void uiTemplateComponentMenu(uiLayout *layout, /** \name Node Socket Icon Template * \{ */ -void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float *color) +void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float color[4]) { uiBlock *block = uiLayoutGetBlock(layout); UI_block_align_begin(block); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 0c6be7b1196..fe6a8b0d1a6 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1225,12 +1225,6 @@ static bool draw_widgetbase_batch_skip_draw_cache(void) return true; } - /* There are also reports that some AMD and Mesa driver configuration suffer from the - * same issue, T78803. */ - if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) { - return true; - } - return false; } @@ -1936,19 +1930,27 @@ static void widget_draw_text_ime_underline(const uiFontStyle *fstyle, } #endif /* WITH_INPUT_IME */ -static bool widget_draw_text_underline_calc_center_x(const char *UNUSED(str), +struct UnderlineData { + size_t str_offset; /* The string offset of the underlined character. */ + int width_px; /* The underline width in pixels. */ + int r_offset_px[2]; /* Write the X,Y offset here. */ +}; + +static bool widget_draw_text_underline_calc_position(const char *UNUSED(str), const size_t str_step_ofs, const rcti *glyph_step_bounds, const int UNUSED(glyph_advance_x), const rctf *glyph_bounds, - const int glyph_bearing[2], + const int UNUSED(glyph_bearing[2]), void *user_data) { - /* The index of the character to get, set to the x-position. */ - int *ul_data = user_data; - if (ul_data[0] == (int)str_step_ofs) { - ul_data[1] = glyph_step_bounds->xmin + glyph_bearing[0] + - (BLI_rctf_size_x(glyph_bounds) / 2.0f); + struct UnderlineData *ul_data = user_data; + if (ul_data->str_offset == str_step_ofs) { + /* Full width of this glyph including both bearings. */ + const float width = glyph_bounds->xmin + BLI_rctf_size_x(glyph_bounds) + glyph_bounds->xmin; + ul_data->r_offset_px[0] = glyph_step_bounds->xmin + ((width - ul_data->width_px) * 0.5f); + /* Two line-widths below the lower glyph bounds. */ + ul_data->r_offset_px[1] = glyph_bounds->ymin - U.pixelsize - U.pixelsize; /* Early exit. */ return false; } @@ -2204,23 +2206,30 @@ static void widget_draw_text(const uiFontStyle *fstyle, BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); } - int ul_data[2] = { - ul_index, /* Character index to test. */ - 0, /* Write the x-offset here. */ + int ul_width = round_fl_to_int(BLF_width(fstyle->uifont_id, "_", 2)); + int ul_height = max_ii(fstyle->points * U.dpi_fac * 0.1f, U.pixelsize); + + struct UnderlineData ul_data = { + .str_offset = ul_index, + .width_px = ul_width, }; + BLF_boundbox_foreach_glyph(fstyle->uifont_id, drawstr_ofs, ul_index + 1, - widget_draw_text_underline_calc_center_x, - ul_data); - ul_data[1] -= BLF_width(fstyle->uifont_id, "_", 2) / 2.0f; - - BLF_position(fstyle->uifont_id, - rect->xmin + font_xofs + ul_data[1], - rect->ymin + font_yofs, - 0.0f); - BLF_color4ubv(fstyle->uifont_id, wcol->text); - BLF_draw(fstyle->uifont_id, "_", 2); + widget_draw_text_underline_calc_position, + &ul_data); + + GPU_blend(GPU_BLEND_ALPHA); + const uint pos = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ubv(wcol->text); + const int pos_x = rect->xmin + font_xofs + ul_data.r_offset_px[0]; + const int pos_y = rect->ymin + font_yofs + ul_data.r_offset_px[1]; + immRecti(pos, pos_x, pos_y, pos_x + ul_width, pos_y - ul_height); + immUnbindProgram(); + GPU_blend(GPU_BLEND_NONE); if (fstyle->kerning == 1) { BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); @@ -2422,11 +2431,12 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle, but->block->aspect = aspect_orig; #endif - rect->xmin += icon_size + icon_padding; + rect->xmin += round_fl_to_int(icon_size + icon_padding); } if (!no_text_padding) { - const int text_padding = (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect; + const int text_padding = round_fl_to_int((UI_TEXT_MARGIN_X * U.widget_unit) / + but->block->aspect); if (but->editstr) { rect->xmin += text_padding; } @@ -3757,12 +3767,35 @@ static void widget_numslider( float factor, factor_ui; float factor_discard = 1.0f; /* No discard. */ const float value = (float)ui_but_value_get(but); - - if (but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PERCENTAGE)) { - factor = value / but->softmax; - } - else { - factor = (value - but->softmin) / (but->softmax - but->softmin); + const float softmin = but->softmin; + const float softmax = but->softmax; + const float softrange = softmax - softmin; + const PropertyScaleType scale_type = ui_but_scale_type(but); + + switch (scale_type) { + case PROP_SCALE_LINEAR: { + if (but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PERCENTAGE)) { + factor = value / softmax; + } + else { + factor = (value - softmin) / softrange; + } + break; + } + case PROP_SCALE_LOG: { + const float logmin = fmaxf(softmin, 0.5e-8f); + const float base = softmax / logmin; + factor = logf(value / logmin) / logf(base); + break; + } + case PROP_SCALE_CUBIC: { + const float cubicmin = cube_f(softmin); + const float cubicmax = cube_f(softmax); + const float cubicrange = cubicmax - cubicmin; + const float f = (value - softmin) * cubicrange / softrange + cubicmin; + factor = (cbrtf(f) - softmin) / softrange; + break; + } } const float width = (float)BLI_rcti_size_x(rect); diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 7453cd17868..40c510af7e5 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -757,7 +757,7 @@ typedef struct v2dViewZoomData { } v2dViewZoomData; /** - * Clamp by convention rather then locking flags, + * Clamp by convention rather than locking flags, * for ndof and +/- keys */ static void view_zoom_axis_lock_defaults(bContext *C, bool r_do_zoom_xy[2]) |