Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / interface / interface.c
index 8199ce038edd566ed513093139bc5bfed547dd70..f091e17139f6b1b6d18daf759a24b71df477e2b5 100644 (file)
@@ -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 its 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;
@@ -499,6 +499,7 @@ static int ui_but_calc_float_precision(uiBut *but, double value)
 static void ui_draw_linkline(uiLinkLine *line, int highlightActiveLines, int dashInactiveLines)
 {
        rcti rect;
+       float color[4] = {1.0f};
 
        if (line->from == NULL || line->to == NULL) return;
        
@@ -508,15 +509,15 @@ static void ui_draw_linkline(uiLinkLine *line, int highlightActiveLines, int das
        rect.ymax = BLI_rctf_cent_y(&line->to->rect);
        
        if (dashInactiveLines)
-               UI_ThemeColor(TH_GRID);
+               UI_GetThemeColor4fv(TH_GRID, color);
        else if (line->flag & UI_SELECT)
-               glColor3ub(100, 100, 100);
+               rgba_float_args_set_ch(color, 100, 100, 100, 255);
        else if (highlightActiveLines && ((line->from->flag & UI_ACTIVE) || (line->to->flag & UI_ACTIVE)))
-               UI_ThemeColor(TH_TEXT_HI);
+               UI_GetThemeColor4fv(TH_TEXT_HI, color);
        else
-               glColor3ub(0, 0, 0);
+               rgba_float_args_set_ch(color, 0, 0, 0, 255);
 
-       ui_draw_link_bezier(&rect);
+       ui_draw_link_bezier(&rect, color);
 }
 
 static void ui_draw_links(uiBlock *block)
@@ -735,8 +736,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);
 
@@ -1046,6 +1054,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) {
@@ -1127,7 +1139,7 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but,
  * as new items are added to the menu later on. It also optimises efficiency -
  * a radial menu is best kept symmetrical, with as large an angle between
  * items as possible, so that the gestural mouse movements can be fast and inexact.
-
+ *
  * It starts off with two opposite sides for the first two items
  * then joined by the one below for the third (this way, even with three items,
  * the menu seems to still be 'in order' reading left to right). Then the fourth is
@@ -1196,6 +1208,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);
+                       }
                }
        }
 
@@ -1231,7 +1248,6 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2])
 
                        if (ot == NULL || WM_operator_poll_context((bContext *)C, ot, but->opcontext) == 0) {
                                but->flag |= UI_BUT_DISABLED;
-                               but->lock = true;
                        }
 
                        if (but->context)
@@ -1344,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);
@@ -1367,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)
@@ -1396,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);
 }
@@ -1972,22 +1988,29 @@ uiBut *ui_but_drag_multi_edit_get(uiBut *but)
 /** \name Check to show extra icons
  *
  * Extra icons are shown on the right hand side of buttons.
+ * This could (should!) definitely become more generic, but for now this is good enough.
  * \{ */
 
+static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but)
+{
+       BLI_assert(but->type == UI_BTYPE_TEXT);
+       return ((but->flag & UI_BUT_VALUE_CLEAR) && but->drawstr[0]);
+}
+
 static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but)
 {
        BLI_assert(but->type == UI_BTYPE_SEARCH_MENU);
        return ((but->editstr == NULL) &&
                (but->drawstr[0] != '\0') &&
-               (but->flag & UI_BUT_SEARCH_UNLINK));
+               (but->flag & UI_BUT_VALUE_CLEAR));
 }
 
-static bool ui_but_icon_extra_is_visible_eyedropper(uiBut *but)
+static bool ui_but_icon_extra_is_visible_search_eyedropper(uiBut *but)
 {
        StructRNA *type;
        short idcode;
 
-       BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_SEARCH_UNLINK));
+       BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_VALUE_CLEAR));
 
        if (but->rnaprop == NULL) {
                return false;
@@ -1996,21 +2019,31 @@ static bool ui_but_icon_extra_is_visible_eyedropper(uiBut *but)
        type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop);
        idcode = RNA_type_to_ID_code(type);
 
-
        return ((but->editstr == NULL) &&
                (idcode == ID_OB || OB_DATA_SUPPORT_ID(idcode)));
 }
 
 uiButExtraIconType ui_but_icon_extra_get(uiBut *but)
 {
-       if ((but->flag & UI_BUT_SEARCH_UNLINK) == 0) {
-               /* pass */
-       }
-       else if (ui_but_icon_extra_is_visible_search_unlink(but)) {
-               return UI_BUT_ICONEXTRA_UNLINK;
-       }
-       else if (ui_but_icon_extra_is_visible_eyedropper(but)) {
-               return UI_BUT_ICONEXTRA_EYEDROPPER;
+       switch (but->type) {
+               case UI_BTYPE_TEXT:
+                       if (ui_but_icon_extra_is_visible_text_clear(but)) {
+                               return UI_BUT_ICONEXTRA_CLEAR;
+                       }
+                       break;
+               case UI_BTYPE_SEARCH_MENU:
+                       if ((but->flag & UI_BUT_VALUE_CLEAR) == 0) {
+                               /* pass */
+                       }
+                       else if (ui_but_icon_extra_is_visible_search_unlink(but)) {
+                               return UI_BUT_ICONEXTRA_CLEAR;
+                       }
+                       else if (ui_but_icon_extra_is_visible_search_eyedropper(but)) {
+                               return UI_BUT_ICONEXTRA_EYEDROPPER;
+                       }
+                       break;
+               default:
+                       break;
        }
 
        return UI_BUT_ICONEXTRA_NONE;
@@ -2268,7 +2301,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 */
@@ -2283,7 +2316,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];
@@ -2413,7 +2446,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;
                }
 
@@ -2560,9 +2593,11 @@ static void ui_set_but_soft_range(uiBut *but)
        }
        else if (but->poin && (but->pointype & UI_BUT_POIN_TYPES)) {
                float value = ui_but_value_get(but);
-               CLAMP(value, but->hardmin, but->hardmax);
-               but->softmin = min_ff(but->softmin, value);
-               but->softmax = max_ff(but->softmax, value);
+               if (isfinite(value)) {
+                       CLAMP(value, but->hardmin, but->hardmax);
+                       but->softmin = min_ff(but->softmin, value);
+                       but->softmax = max_ff(but->softmax, value);
+               }
        }
        else {
                BLI_assert(0);
@@ -2771,7 +2806,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;
@@ -2793,13 +2833,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:
@@ -2827,14 +2873,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;
                                                }
                                        }
                                }
@@ -2972,6 +3021,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)
 {
@@ -3081,8 +3139,7 @@ static uiBut *ui_def_but(
        but->a2 = a2;
        but->tip = tip;
 
-       but->lock = block->lock;
-       but->lockstr = block->lockstr;
+       but->disabled_info = block->lockstr;
        but->dt = block->dt;
        but->pie_dir = UI_RADIAL_NONE;
 
@@ -3130,10 +3187,8 @@ static uiBut *ui_def_but(
 
        but->drawflag |= (block->flag & UI_BUT_ALIGN);
 
-       if (but->lock == true) {
-               if (but->lockstr) {
-                       but->flag |= UI_BUT_DISABLED;
-               }
+       if (block->lock == true) {
+               but->flag |= UI_BUT_DISABLED;
        }
 
        /* keep track of UI_interface.h */
@@ -3178,11 +3233,10 @@ void ui_def_but_icon(uiBut *but, const int icon, const int flag)
        }
 }
 
-static void ui_def_but_rna__disable(uiBut *but)
+static void ui_def_but_rna__disable(uiBut *but, const char *info)
 {
        but->flag |= UI_BUT_DISABLED;
-       but->lock = true;
-       but->lockstr = "";
+       but->disabled_info = info;
 }
 
 static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *but_p)
@@ -3447,8 +3501,9 @@ static uiBut *ui_def_but_rna(
                but->flag |= UI_BUT_ICON_SUBMENU;
        }
 
-       if (!RNA_property_editable(&but->rnapoin, prop)) {
-               ui_def_but_rna__disable(but);
+       const char *info;
+       if (!RNA_property_editable_info(&but->rnapoin, prop, &info)) {
+               ui_def_but_rna__disable(but, info);
        }
 
        if (but->flag & UI_BUT_UNDO && (ui_but_is_rna_undo(but) == false)) {
@@ -3479,7 +3534,7 @@ static uiBut *ui_def_but_rna_propname(uiBlock *block, int type, int retval, cons
        else {
                but = ui_def_but(block, type, retval, propname, x, y, width, height, NULL, min, max, a1, a2, tip);
 
-               ui_def_but_rna__disable(but);
+               ui_def_but_rna__disable(but, "Unknown Property.");
        }
 
        return but;
@@ -3507,8 +3562,7 @@ static uiBut *ui_def_but_operator_ptr(uiBlock *block, int type, wmOperatorType *
 
        if (!ot) {
                but->flag |= UI_BUT_DISABLED;
-               but->lock = true;
-               but->lockstr = "";
+               but->disabled_info = "";
        }
 
        return but;
@@ -3540,11 +3594,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;
        }
@@ -3860,6 +3914,8 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block, int type, wmOperatorType *ot, int o
 uiBut *uiDefIconTextButO(uiBlock *block, int type, const char *opname, int opcontext, int icon, const char *str, int x, int y, short width, short height, const char *tip)
 {
        wmOperatorType *ot = WM_operatortype_find(opname, 0);
+       if (str[0] == '\0') 
+               return uiDefIconButO_ptr(block, type, ot, opcontext, icon, x, y, width, height, tip);
        return uiDefIconTextButO_ptr(block, type, ot, opcontext, icon, str, x, y, width, height, tip);
 }
 
@@ -3945,6 +4001,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;
@@ -4279,16 +4340,34 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle
 
 
 /**
- * \param sfunc, bfunc: both get it as \a arg.
+ * \param search_func, bfunc: both get it as \a arg.
  * \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)) {
@@ -4317,12 +4396,12 @@ 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 */
                        if (BLI_strcasestr(item->name, str)) {
-                               if (false == UI_search_item_add(items, item->name, SET_INT_IN_POINTER(item->value), 0))
+                               if (false == UI_search_item_add(items, item->name, SET_INT_IN_POINTER(item->value), item->icon))
                                        break;
                        }
                }
@@ -4363,7 +4442,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;