Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/interface')
-rw-r--r--source/blender/editors/interface/interface.c148
-rw-r--r--source/blender/editors/interface/interface_draw.c18
-rw-r--r--source/blender/editors/interface/interface_handlers.c802
-rw-r--r--source/blender/editors/interface/interface_icons.c2
-rw-r--r--source/blender/editors/interface/interface_intern.h54
-rw-r--r--source/blender/editors/interface/interface_layout.c235
-rw-r--r--source/blender/editors/interface/interface_ops.c213
-rw-r--r--source/blender/editors/interface/interface_panel.c103
-rw-r--r--source/blender/editors/interface/interface_regions.c293
-rw-r--r--source/blender/editors/interface/interface_templates.c192
-rw-r--r--source/blender/editors/interface/interface_utils.c2
-rw-r--r--source/blender/editors/interface/interface_widgets.c347
-rw-r--r--source/blender/editors/interface/resources.c84
-rw-r--r--source/blender/editors/interface/view2d.c2
-rw-r--r--source/blender/editors/interface/view2d_ops.c45
15 files changed, 2100 insertions, 440 deletions
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index c059b16f1a0..c3f63f8a7fe 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -51,6 +51,7 @@
#include "BKE_context.h"
#include "BKE_unit.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_idprop.h"
@@ -97,6 +98,11 @@ bool ui_block_is_menu(const uiBlock *block)
((block->flag & UI_BLOCK_KEEP_OPEN) == 0));
}
+bool ui_block_is_pie_menu(const uiBlock *block)
+{
+ return ((block->flag & UI_BLOCK_RADIAL) != 0);
+}
+
static bool ui_is_but_unit_radians_ex(UnitSettings *unit, const int unit_type)
{
return (unit->system_rotation == USER_UNIT_ROT_RADIANS && unit_type == PROP_UNIT_ROTATION);
@@ -321,6 +327,20 @@ static void ui_centered_bounds_block(wmWindow *window, uiBlock *block)
ui_bounds_block(block);
}
+
+static void ui_centered_pie_bounds_block(uiBlock *block)
+{
+ const int xy[2] = {
+ block->pie_data.pie_center_spawned[0],
+ block->pie_data.pie_center_spawned[1]
+ };
+
+ ui_block_translate(block, xy[0], xy[1]);
+
+ /* now recompute bounds and safety */
+ ui_bounds_block(block);
+}
+
static void ui_popup_bounds_block(wmWindow *window, uiBlock *block,
eBlockBoundsCalc bounds_calc, const int xy[2])
{
@@ -830,7 +850,7 @@ static void ui_menu_block_set_keyaccels(uiBlock *block)
* fun first pass on all buttons so first word chars always get first priority */
for (but = block->buttons.first; but; but = but->next) {
- if (!ELEM5(but->type, BUT, BUTM, MENU, BLOCK, PULLDOWN) || (but->flag & UI_HIDDEN)) {
+ if (!ELEM(but->type, BUT, BUTM, MENU, BLOCK, PULLDOWN) || (but->flag & UI_HIDDEN)) {
/* pass */
}
else if (but->menu_key == '\0') {
@@ -1062,6 +1082,41 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but,
return found;
}
+/* this goes in a seemingly weird pattern:
+ *
+ * 4
+ * 5 6
+ * 1 2
+ * 7 8
+ * 3
+ *
+ * but it's actually quite logical. It's designed to be 'upwards compatible'
+ * for muscle memory so that the menu item locations are fixed and don't move
+ * 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
+ * added to complete the compass directions. From here, it's just a matter of
+ * subdividing the rest of the angles for the last 4 items.
+ *
+ * --Matt 07/2006
+ */
+const char ui_radial_dir_order[8] = {
+ UI_RADIAL_W, UI_RADIAL_E, UI_RADIAL_S, UI_RADIAL_N,
+ UI_RADIAL_NW, UI_RADIAL_NE, UI_RADIAL_SW, UI_RADIAL_SE};
+
+const char ui_radial_dir_to_numpad[8] = {8, 9, 6, 3, 2, 1, 4, 7};
+const short ui_radial_dir_to_angle[8] = {90, 45, 0, 315, 270, 225, 180, 135};
+
+static void ui_but_pie_direction_string(uiBut *but, char *buf, int size)
+{
+ BLI_assert(but->pie_dir < ARRAY_SIZE(ui_radial_dir_to_numpad));
+ BLI_snprintf(buf, size, "%d", ui_radial_dir_to_numpad[but->pie_dir]);
+}
+
static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
{
uiBut *but;
@@ -1071,13 +1126,23 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
if (block->rect.xmin != block->rect.xmax)
return;
- for (but = block->buttons.first; but; but = but->next) {
-
- if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) {
- ui_but_add_shortcut(but, buf, false);
+ if (block->flag & UI_BLOCK_RADIAL) {
+ for (but = block->buttons.first; but; but = but->next) {
+ if (but->pie_dir != UI_RADIAL_NONE) {
+ ui_but_pie_direction_string(but, buf, sizeof(buf));
+ ui_but_add_shortcut(but, buf, false);
+ }
}
- else if (ui_but_event_property_operator_string(C, but, buf, sizeof(buf))) {
- ui_but_add_shortcut(but, buf, false);
+ }
+ else {
+ for (but = block->buttons.first; but; but = but->next) {
+
+ if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) {
+ ui_but_add_shortcut(but, buf, false);
+ }
+ else if (ui_but_event_property_operator_string(C, but, buf, sizeof(buf))) {
+ ui_but_add_shortcut(but, buf, false);
+ }
}
}
}
@@ -1173,6 +1238,9 @@ void uiEndBlock_ex(const bContext *C, uiBlock *block, const int xy[2])
case UI_BLOCK_BOUNDS_POPUP_CENTER:
ui_centered_bounds_block(window, block);
break;
+ case UI_BLOCK_BOUNDS_PIE_CENTER:
+ ui_centered_pie_bounds_block(block);
+ break;
/* fallback */
case UI_BLOCK_BOUNDS_POPUP_MOUSE:
@@ -1244,6 +1312,10 @@ void uiDrawBlock(const bContext *C, uiBlock *block)
rcti rect;
int multisample_enabled;
+ /* early exit if cancelled */
+ if ((block->flag & UI_BLOCK_RADIAL) && (block->pie_data.flags & UI_PIE_FINISHED))
+ return;
+
/* get menu region or area region */
ar = CTX_wm_menu(C);
if (!ar)
@@ -1276,7 +1348,9 @@ void uiDrawBlock(const bContext *C, uiBlock *block)
wmOrtho2(-0.01f, ar->winx - 0.01f, -0.01f, ar->winy - 0.01f);
/* back */
- if (block->flag & UI_BLOCK_LOOP)
+ if (block->flag & UI_BLOCK_RADIAL)
+ ui_draw_pie_center(block);
+ else if (block->flag & UI_BLOCK_LOOP)
ui_draw_menu_back(&style, block, &rect);
else if (block->panel)
ui_draw_aligned_panel(&style, block, &rect, UI_panel_category_is_visible(ar));
@@ -1317,7 +1391,7 @@ int ui_is_but_push_ex(uiBut *but, double *value)
int is_push = 0;
if (but->bit) {
- const bool state = ELEM3(but->type, TOGN, ICONTOGN, OPTIONN) ? false : true;
+ const bool state = ELEM(but->type, TOGN, ICONTOGN, OPTIONN) ? false : true;
int lvalue;
UI_GET_BUT_VALUE_INIT(but, *value);
lvalue = (int)*value;
@@ -1446,7 +1520,7 @@ void uiComposeLinks(uiBlock *block)
}
}
else if (link->poin) {
- bt = ui_find_inlink(block, *(link->poin) );
+ bt = ui_find_inlink(block, *link->poin);
if (bt) {
if ((but->flag & UI_BUT_SCA_LINK_GREY) || (bt->flag & UI_BUT_SCA_LINK_GREY)) {
ui_add_link_line(&link->lines, but, bt, true);
@@ -1627,7 +1701,7 @@ bool ui_is_but_float(const uiBut *but)
bool ui_is_but_bool(const uiBut *but)
{
- if (ELEM4(but->type, TOG, TOGN, ICONTOG, ICONTOGN))
+ if (ELEM(but->type, TOG, TOGN, ICONTOG, ICONTOGN))
return true;
if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_BOOLEAN)
@@ -1840,7 +1914,7 @@ void ui_set_but_val(uiBut *but, double value)
int ui_get_but_string_max_length(uiBut *but)
{
- if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK))
+ if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK))
return but->hardmax;
else
return UI_MAX_DRAW_STR;
@@ -1866,27 +1940,13 @@ static double ui_get_but_scale_unit(uiBut *but, double value)
UnitSettings *unit = but->block->unit;
int unit_type = uiButGetUnitType(but);
- if (unit_type == PROP_UNIT_LENGTH) {
- return value * (double)unit->scale_length;
- }
- else if (unit_type == PROP_UNIT_CAMERA) {
- return value * (double)unit->scale_length;
- }
- else if (unit_type == PROP_UNIT_AREA) {
- return value * pow(unit->scale_length, 2);
- }
- else if (unit_type == PROP_UNIT_VOLUME) {
- return value * pow(unit->scale_length, 3);
- }
- else if (unit_type == PROP_UNIT_MASS) {
- return value * pow(unit->scale_length, 3);
- }
- else if (unit_type == PROP_UNIT_TIME) { /* WARNING - using evil_C :| */
+ /* Time unit is a bit special, not handled by BKE_scene_unit_scale() for now. */
+ if (unit_type == PROP_UNIT_TIME) { /* WARNING - using evil_C :| */
Scene *scene = CTX_data_scene(but->block->evil_C);
return FRA2TIME(value);
}
else {
- return value;
+ return BKE_scene_unit_scale(unit, RNA_SUBTYPE_UNIT_VALUE(unit_type), value);
}
}
@@ -1955,7 +2015,7 @@ static float ui_get_but_step_unit(uiBut *but, float step_default)
*/
void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision)
{
- if (but->rnaprop && ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (but->rnaprop && ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
PropertyType type;
const char *buf = NULL;
int buf_len;
@@ -2092,7 +2152,7 @@ bool ui_set_but_string_eval_num(bContext *C, uiBut *but, const char *str, double
bool ui_set_but_string(bContext *C, uiBut *but, const char *str)
{
- if (but->rnaprop && ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (but->rnaprop && ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (RNA_property_editable(&but->rnapoin, but->rnaprop)) {
PropertyType type;
@@ -2744,7 +2804,7 @@ void uiBlockEndAlign(uiBlock *block)
bool ui_but_can_align(uiBut *but)
{
- return !ELEM5(but->type, LABEL, OPTION, OPTIONN, SEPR, SEPRLINE);
+ return !ELEM(but->type, LABEL, OPTION, OPTIONN, SEPR, SEPRLINE);
}
static void ui_block_do_align_but(uiBut *first, short nr)
@@ -2999,6 +3059,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
but->lock = block->lock;
but->lockstr = block->lockstr;
but->dt = block->dt;
+ but->pie_dir = UI_RADIAL_NONE;
but->block = block; /* pointer back, used for frontbuffer status, and picker */
@@ -3025,8 +3086,11 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
}
}
- if ((block->flag & UI_BLOCK_LOOP) ||
- ELEM8(but->type, MENU, TEX, LABEL, BLOCK, BUTM, SEARCH_MENU, PROGRESSBAR, SEARCH_MENU_UNLINK))
+ if (block->flag & UI_BLOCK_RADIAL) {
+ but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
+ }
+ else if ((block->flag & UI_BLOCK_LOOP) ||
+ ELEM(but->type, MENU, TEX, LABEL, BLOCK, BUTM, SEARCH_MENU, PROGRESSBAR, SEARCH_MENU_UNLINK))
{
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
}
@@ -3045,7 +3109,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
}
/* keep track of UI_interface.h */
- if (ELEM11(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, BUTM, SCROLL, SEPR, SEPRLINE, GRIP)) {}
+ if (ELEM(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, BUTM, SCROLL, SEPR, SEPRLINE, GRIP)) {}
else if (but->type >= SEARCH_MENU) {}
else but->flag |= UI_BUT_UNDO;
@@ -3210,12 +3274,12 @@ static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *s
int icon = 0;
uiMenuCreateFunc func = NULL;
- if (ELEM3(type, COLOR, HSVCIRCLE, HSVCUBE)) {
+ if (ELEM(type, COLOR, HSVCIRCLE, HSVCUBE)) {
BLI_assert(index == -1);
}
/* use rna values if parameters are not specified */
- if ((proptype == PROP_ENUM) && ELEM3(type, MENU, ROW, LISTROW)) {
+ if ((proptype == PROP_ENUM) && ELEM(type, MENU, ROW, LISTROW)) {
/* MENU is handled a little differently here */
EnumPropertyItem *item;
int value;
@@ -3808,9 +3872,6 @@ void uiBlockFlipOrder(uiBlock *block)
but->rect.ymax = centy - (but->rect.ymax - centy);
SWAP(float, but->rect.ymin, but->rect.ymax);
}
-
- /* also flip order in block itself, for example for arrowkey */
- BLI_listbase_reverse(&block->buttons);
}
@@ -4336,7 +4397,7 @@ void uiButGetStrInfo(bContext *C, uiBut *but, ...)
}
tmp = BLI_strdup(_tmp);
}
- else if (ELEM3(type, BUT_GET_RNAENUM_IDENTIFIER, BUT_GET_RNAENUM_LABEL, BUT_GET_RNAENUM_TIP)) {
+ else if (ELEM(type, BUT_GET_RNAENUM_IDENTIFIER, BUT_GET_RNAENUM_LABEL, BUT_GET_RNAENUM_TIP)) {
PointerRNA *ptr = NULL;
PropertyRNA *prop = NULL;
int value = 0;
@@ -4426,11 +4487,6 @@ void UI_init_userdef(void)
uiStyleInit();
}
-void UI_init_userdef_factory(void)
-{
- init_userdef_factory();
-}
-
void UI_reinit_font(void)
{
uiStyleInit();
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 29da19acf83..53827a9a7bf 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -695,11 +695,11 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
}
/* RGB / YCC (3 channels) */
- else if (ELEM4(scopes->wavefrm_mode,
- SCOPES_WAVEFRM_RGB,
- SCOPES_WAVEFRM_YCC_601,
- SCOPES_WAVEFRM_YCC_709,
- SCOPES_WAVEFRM_YCC_JPEG))
+ else if (ELEM(scopes->wavefrm_mode,
+ SCOPES_WAVEFRM_RGB,
+ SCOPES_WAVEFRM_YCC_601,
+ SCOPES_WAVEFRM_YCC_709,
+ SCOPES_WAVEFRM_YCC_JPEG))
{
int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB);
@@ -1152,9 +1152,11 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
}
/* layer: active handle */
- cbd = &coba->data[coba->cur];
- pos = x1 + cbd->pos * (sizex - 1) + 1;
- ui_draw_colorband_handle(rect, pos, &cbd->r, display, true);
+ if (coba->tot != 0) {
+ cbd = &coba->data[coba->cur];
+ pos = x1 + cbd->pos * (sizex - 1) + 1;
+ ui_draw_colorband_handle(rect, pos, &cbd->r, display, true);
+ }
}
void ui_draw_but_NORMAL(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index e04fef329b1..9818a593174 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -38,6 +38,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_brush_types.h"
#include "DNA_sensor_types.h"
#include "DNA_controller_types.h"
#include "DNA_actuator_types.h"
@@ -60,6 +61,7 @@
#include "PIL_time.h"
#include "BKE_blender.h"
+#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_idprop.h"
@@ -99,6 +101,8 @@
/* drag popups by their header */
#define USE_DRAG_POPUP
+#define UI_MAX_PASSWORD_STR 128
+
/* proto */
static void ui_add_smart_controller(bContext *C, uiBut *from, uiBut *to);
static void ui_add_link(bContext *C, uiBut *from, uiBut *to);
@@ -114,6 +118,7 @@ static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEve
#define BUTTON_TOOLTIP_DELAY 0.500
#define BUTTON_FLASH_DELAY 0.020
#define MENU_SCROLL_INTERVAL 0.1
+#define PIE_MENU_INTERVAL 0.01
#define BUTTON_AUTO_OPEN_THRESH 0.3
#define BUTTON_MOUSE_TOWARDS_THRESH 1.0
/* pixels to move the cursor to get out of keyboard navigation */
@@ -151,7 +156,7 @@ typedef enum uiHandleButtonState {
* note: half the height of a button is about right... */
#define DRAG_MULTINUM_THRESHOLD_DRAG_X (UI_UNIT_Y / 4)
-/* how far to drag horizontally before we stop checkign which buttons the gesture spans (in pixels),
+/* how far to drag horizontally before we stop checking which buttons the gesture spans (in pixels),
* locking down the buttons so we can drag freely without worrying about vertical movement. */
#define DRAG_MULTINUM_THRESHOLD_DRAG_Y (UI_UNIT_Y / 4)
@@ -383,16 +388,16 @@ void ui_pan_to_scroll(const wmEvent *event, int *type, int *val)
}
}
-static bool ui_but_editable(uiBut *but)
+bool ui_but_is_editable(const uiBut *but)
{
- return ELEM6(but->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX, PROGRESSBAR);
+ return !ELEM(but->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX, PROGRESSBAR);
}
static uiBut *ui_but_prev(uiBut *but)
{
while (but->prev) {
but = but->prev;
- if (!ui_but_editable(but)) return but;
+ if (ui_but_is_editable(but)) return but;
}
return NULL;
}
@@ -401,7 +406,7 @@ static uiBut *ui_but_next(uiBut *but)
{
while (but->next) {
but = but->next;
- if (!ui_but_editable(but)) return but;
+ if (ui_but_is_editable(but)) return but;
}
return NULL;
}
@@ -412,7 +417,7 @@ static uiBut *ui_but_first(uiBlock *block)
but = block->buttons.first;
while (but) {
- if (!ui_but_editable(but)) return but;
+ if (ui_but_is_editable(but)) return but;
but = but->next;
}
return NULL;
@@ -424,7 +429,7 @@ static uiBut *ui_but_last(uiBlock *block)
but = block->buttons.last;
while (but) {
- if (!ui_but_editable(but)) return but;
+ if (ui_but_is_editable(but)) return but;
but = but->prev;
}
return NULL;
@@ -433,7 +438,7 @@ static uiBut *ui_but_last(uiBlock *block)
static bool ui_is_a_warp_but(uiBut *but)
{
if (U.uiflag & USER_CONTINUOUS_MOUSE) {
- if (ELEM6(but->type, NUM, NUMSLI, HSVCIRCLE, TRACKPREVIEW, HSVCUBE, BUT_CURVE)) {
+ if (ELEM(but->type, NUM, NUMSLI, HSVCIRCLE, TRACKPREVIEW, HSVCUBE, BUT_CURVE)) {
return true;
}
}
@@ -463,7 +468,7 @@ bool ui_is_but_utf8(const uiBut *but)
{
if (but->rnaprop) {
const int subtype = RNA_property_subtype(but->rnaprop);
- return !(ELEM4(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME, PROP_BYTESTRING));
+ return !(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME, PROP_BYTESTRING));
}
else {
return !(but->flag & UI_BUT_NO_UTF8);
@@ -599,7 +604,13 @@ static void ui_apply_autokey(bContext *C, uiBut *but)
/* make a little report about what we've done! */
if (but->rnaprop) {
- char *buf = WM_prop_pystring_assign(C, &but->rnapoin, but->rnaprop, but->rnaindex);
+ char *buf;
+
+ if (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD) {
+ return;
+ }
+
+ buf = WM_prop_pystring_assign(C, &but->rnapoin, but->rnaprop, but->rnaindex);
if (buf) {
BKE_report(CTX_wm_reports(C), RPT_PROPERTY, buf);
MEM_freeN(buf);
@@ -633,7 +644,7 @@ static void ui_apply_but_funcs_after(bContext *C)
}
if (after.optype)
- WM_operator_name_call(C, after.optype->idname, after.opcontext, (after.opptr) ? &opptr : NULL);
+ WM_operator_name_call_ptr(C, after.optype, after.opcontext, (after.opptr) ? &opptr : NULL);
if (after.opptr)
WM_operator_properties_free(&opptr);
@@ -717,7 +728,7 @@ static void ui_apply_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data)
if (value == 0.0) push = 1;
else push = 0;
- if (ELEM3(but->type, TOGN, ICONTOGN, OPTIONN)) push = !push;
+ if (ELEM(but->type, TOGN, ICONTOGN, OPTIONN)) push = !push;
ui_set_but_val(but, (double)push);
if (but->type == ICONTOG || but->type == ICONTOGN) ui_check_but(but);
}
@@ -1189,7 +1200,7 @@ static bool ui_but_mouse_inside_icon(uiBut *but, ARegion *ar, const wmEvent *eve
BLI_rcti_rctf_copy(&rect, &but->rect);
- if (but->imb) {
+ if (but->imb || but->type == COLOR) {
/* use button size itself */
}
else if (but->drawflag & UI_BUT_ICON_LEFT) {
@@ -1236,16 +1247,48 @@ static bool ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data,
WM_event_add_ui_handler(C, &data->window->modalhandlers,
ui_handler_region_drag_toggle,
ui_handler_region_drag_toggle_remove,
- drag_info);
+ drag_info, false);
CTX_wm_region_set(C, ar_prev);
}
else
#endif
- {
+ if (but->type == COLOR) {
+ bool valid = false;
+ uiDragColorHandle *drag_info = MEM_callocN(sizeof(*drag_info), __func__);
+
+ /* TODO support more button pointer types */
+ if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, drag_info->color);
+ drag_info->gamma_corrected = true;
+ valid = true;
+ }
+ else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, drag_info->color);
+ drag_info->gamma_corrected = false;
+ valid = true;
+ }
+ else if (but->pointype == UI_BUT_POIN_FLOAT) {
+ copy_v3_v3(drag_info->color, (float *)but->poin);
+ valid = true;
+ }
+ else if (but->pointype == UI_BUT_POIN_CHAR) {
+ rgb_uchar_to_float(drag_info->color, (unsigned char *)but->poin);
+ valid = true;
+ }
+
+ if (valid) {
+ WM_event_start_drag(C, ICON_COLOR, WM_DRAG_COLOR, drag_info, 0.0, WM_DRAG_FREE_DATA);
+ }
+ else {
+ MEM_freeN(drag_info);
+ return false;
+ }
+ }
+ else {
wmDrag *drag;
- drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but));
+ drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but), WM_DRAG_NOP);
if (but->imb)
WM_event_drag_image(drag, but->imb, but->imb_scale, BLI_rctf_size_x(&but->rect), BLI_rctf_size_y(&but->rect));
}
@@ -1655,7 +1698,7 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB
for (wmd = drags->first; wmd; wmd = wmd->next) {
if (wmd->type == WM_DRAG_ID) {
/* align these types with UI_but_active_drop_name */
- if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
ID *id = (ID *)wmd->poin;
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
@@ -1802,7 +1845,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
}
/* text/string and ID data */
- else if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ else if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
uiHandleButtonData *active_data = but->active;
if (but->poin == NULL && but->rnapoin.data == NULL) {
@@ -1911,28 +1954,35 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
static int ui_text_position_from_hidden(uiBut *but, int pos)
{
- const char *strpos;
+ const char *strpos, *butstr;
int i;
- for (i = 0, strpos = but->drawstr; i < pos; i++)
+ butstr = (but->editstr) ? but->editstr : but->drawstr;
+
+ for (i = 0, strpos = butstr; i < pos; i++)
strpos = BLI_str_find_next_char_utf8(strpos, NULL);
- return (strpos - but->drawstr);
+ return (strpos - butstr);
}
static int ui_text_position_to_hidden(uiBut *but, int pos)
{
- return BLI_strnlen_utf8(but->drawstr, pos);
+ const char *butstr = butstr = (but->editstr) ? but->editstr : but->drawstr;
+ return BLI_strnlen_utf8(butstr, pos);
}
-void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore)
+void ui_button_text_password_hide(char password_str[UI_MAX_PASSWORD_STR], uiBut *but, const bool restore)
{
+ char *butstr;
+
if (!(but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_PASSWORD))
return;
+ butstr = (but->editstr) ? but->editstr : but->drawstr;
+
if (restore) {
/* restore original string */
- BLI_strncpy(but->drawstr, password_str, UI_MAX_DRAW_STR);
+ BLI_strncpy(butstr, password_str, UI_MAX_PASSWORD_STR);
/* remap cursor positions */
if (but->pos >= 0) {
@@ -1942,8 +1992,8 @@ void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but
}
}
else {
- /* convert text to hidden test using asterisks (e.g. pass -> ****) */
- const size_t len = BLI_strlen_utf8(but->drawstr);
+ /* convert text to hidden text using asterisks (e.g. pass -> ****) */
+ const size_t len = BLI_strlen_utf8(butstr);
/* remap cursor positions */
if (but->pos >= 0) {
@@ -1953,10 +2003,9 @@ void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but
}
/* save original string */
- BLI_strncpy(password_str, but->drawstr, UI_MAX_DRAW_STR);
-
- memset(but->drawstr, '*', len);
- but->drawstr[len] = '\0';
+ BLI_strncpy(password_str, butstr, UI_MAX_PASSWORD_STR);
+ memset(butstr, '*', len);
+ butstr[len] = '\0';
}
}
@@ -1992,7 +2041,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
float startx = but->rect.xmin;
float starty_dummy = 0.0f;
- char *origstr, password_str[UI_MAX_DRAW_STR];
+ char *origstr, password_str[UI_MAX_PASSWORD_STR];
ui_block_to_window_fl(data->region, but->block, &startx, &starty_dummy);
@@ -2009,7 +2058,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
BLI_strncpy(origstr, but->editstr, data->maxlen);
- if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (but->flag & UI_HAS_ICON) {
startx += UI_DPI_ICON_SIZE / aspect;
}
@@ -2461,11 +2510,11 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
uiBut *but;
/* label and roundbox can overlap real buttons (backdrops...) */
- if (ELEM5(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX))
+ if (ELEM(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX))
return;
for (but = actbut->next; but; but = but->next) {
- if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (!(but->flag & UI_BUT_DISABLED)) {
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
@@ -2474,7 +2523,7 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
}
}
for (but = block->buttons.first; but != actbut; but = but->next) {
- if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (!(but->flag & UI_BUT_DISABLED)) {
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
@@ -2489,11 +2538,11 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
uiBut *but;
/* label and roundbox can overlap real buttons (backdrops...) */
- if (ELEM5(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX))
+ if (ELEM(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX))
return;
for (but = actbut->prev; but; but = but->prev) {
- if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (!(but->flag & UI_BUT_DISABLED)) {
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
@@ -2502,7 +2551,7 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
}
}
for (but = block->buttons.last; but != actbut; but = but->prev) {
- if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (!(but->flag & UI_BUT_DISABLED)) {
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
@@ -2803,7 +2852,7 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data)
data->coba = (ColorBand *)but->poin;
but->editcoba = data->coba;
}
- else if (ELEM4(but->type, BUT_NORMAL, HSVCUBE, HSVCIRCLE, COLOR)) {
+ else if (ELEM(but->type, BUT_NORMAL, HSVCUBE, HSVCIRCLE, COLOR)) {
ui_get_but_vectorf(but, data->origvec);
copy_v3_v3(data->vec, data->origvec);
but->editvec = data->vec;
@@ -2990,7 +3039,7 @@ static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, cons
static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
but->drawstr[0] = 0;
but->modifier_key = 0;
button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT);
@@ -3053,7 +3102,7 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data
static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT);
return WM_UI_HANDLER_BREAK;
}
@@ -3078,7 +3127,7 @@ static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, c
static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM4(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) {
if (ELEM(event->type, PADENTER, RETKEY) && (!ui_is_but_utf8(but))) {
/* pass - allow filesel, enter to execute */
}
@@ -3106,7 +3155,7 @@ static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
/* unlink icon is on right */
- if (ELEM4(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS &&
+ if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS &&
ui_is_but_search_unlink_visible(but))
{
ARegion *ar = data->region;
@@ -3156,7 +3205,7 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
}
#endif
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
#if 0 /* UNUSED */
data->togdual = event->ctrl;
data->togonly = !event->shift;
@@ -3194,7 +3243,7 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
}
#endif
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
int ret = WM_UI_HANDLER_BREAK;
/* XXX (a bit ugly) Special case handling for filebrowser drag button */
if (but->dragpoin && but->imb && ui_but_mouse_inside_icon(but, data->region, event)) {
@@ -3243,7 +3292,7 @@ static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, floa
if (bUnit_IsValid(unit->system, unit_type)) {
fac = (float)bUnit_BaseScalar(unit->system, unit_type);
- if (ELEM3(unit_type, B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) {
+ if (ELEM(unit_type, B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) {
fac /= unit->scale_length;
}
}
@@ -3478,7 +3527,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
click = 1;
}
else if (event->val == KM_PRESS) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) {
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
retval = WM_UI_HANDLER_BREAK;
}
@@ -3767,7 +3816,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
click = 2;
}
else if (event->val == KM_PRESS) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) {
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
retval = WM_UI_HANDLER_BREAK;
}
@@ -4024,7 +4073,7 @@ static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data,
/* hack to pass on ctrl+click and double click to overlapping text
* editing field for editing list item names
*/
- if ((ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS && event->ctrl) ||
+ if ((ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS && event->ctrl) ||
(event->type == LEFTMOUSE && event->val == KM_DBL_CLICK))
{
uiBut *labelbut = ui_but_list_row_text_activate(C, but, data, event, BUTTON_ACTIVATE_TEXT_EDITING);
@@ -4053,7 +4102,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
}
}
#ifdef USE_DRAG_TOGGLE
- if (event->type == LEFTMOUSE && ui_is_but_drag_toggle(but)) {
+ if (event->type == LEFTMOUSE && event->val == KM_PRESS && (ui_is_but_drag_toggle(but))) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->x;
data->dragstarty = event->y;
@@ -4061,7 +4110,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
}
#endif
/* regular open menu */
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
return WM_UI_HANDLER_BREAK;
}
@@ -4206,11 +4255,29 @@ static bool ui_numedit_but_NORMAL(uiBut *but, uiHandleButtonData *data,
static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ /* first handle click on icondrag type button */
+ if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) {
+ if (ui_but_mouse_inside_icon(but, data->region, event)) {
+ button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
+ data->dragstartx = event->x;
+ data->dragstarty = event->y;
+ return WM_UI_HANDLER_BREAK;
+ }
+ }
+#ifdef USE_DRAG_TOGGLE
+ if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
+ button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
+ data->dragstartx = event->x;
+ data->dragstarty = event->y;
+ return WM_UI_HANDLER_BREAK;
+ }
+#endif
+ /* regular open menu */
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
return WM_UI_HANDLER_BREAK;
}
- else if (ELEM3(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
+ else if (ELEM(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
float *hsv = ui_block_hsv_get(but->block);
float col[3];
@@ -4233,6 +4300,84 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
ui_apply_button(C, but->block, but, data, true);
return WM_UI_HANDLER_BREAK;
}
+ else if ((int)(but->a1) == UI_PALETTE_COLOR &&
+ event->type == DELKEY && event->val == KM_PRESS)
+ {
+ Scene *scene = CTX_data_scene(C);
+ Paint *paint = BKE_paint_get_active(scene);
+ Palette *palette = BKE_paint_palette(paint);
+ PaletteColor *color = but->rnapoin.data;
+
+ BKE_palette_color_remove(palette, color);
+
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ return WM_UI_HANDLER_BREAK;
+ }
+ }
+ else if (data->state == BUTTON_STATE_WAIT_DRAG) {
+
+ /* this function also ends state */
+ if (ui_but_start_drag(C, but, data, event)) {
+ return WM_UI_HANDLER_BREAK;
+ }
+
+ /* outside icon quit, not needed if drag activated */
+ if (0 == ui_but_mouse_inside_icon(but, data->region, event)) {
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ data->cancel = true;
+ return WM_UI_HANDLER_BREAK;
+ }
+
+ if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
+ if ((int)(but->a1) == UI_PALETTE_COLOR) {
+ Palette *palette = but->rnapoin.id.data;
+ PaletteColor *color = but->rnapoin.data;
+ palette->active_color = BLI_findindex(&palette->colors, color);
+
+ /* enforce redraw, sometimes state here can already be exit */
+ ED_region_tag_redraw(data->region);
+
+ if (!event->ctrl) {
+ float color[3];
+ Scene *scene = CTX_data_scene(C);
+ Paint *paint = BKE_paint_get_active(scene);
+ Brush *brush = BKE_paint_brush(paint);
+
+ if (brush->flag & BRUSH_USE_GRADIENT) {
+ float *target = &brush->gradient->data[brush->gradient->cur].r;
+
+ if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target);
+ ui_block_to_scene_linear_v3(but->block, target);
+ }
+ else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target);
+ }
+ }
+ else {
+ if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color);
+ BKE_brush_color_set(scene, brush, color);
+ }
+ else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color);
+ ui_block_to_display_space_v3(but->block, color);
+ BKE_brush_color_set(scene, brush, color);
+ }
+ }
+
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ }
+ else {
+ button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
+ }
+ }
+ else {
+ button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
+ }
+ return WM_UI_HANDLER_BREAK;
+ }
+
}
return WM_UI_HANDLER_CONTINUE;
@@ -4412,7 +4557,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
}
if (snap != SNAP_OFF) {
- if (ELEM3((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) {
+ if (ELEM((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) {
ui_color_snap_hue(snap, &hsv[0]);
}
}
@@ -4489,7 +4634,7 @@ static void ui_ndofedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
}
if (snap != SNAP_OFF) {
- if (ELEM3((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) {
+ if (ELEM((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) {
ui_color_snap_hue(snap, &hsv[0]);
}
}
@@ -4878,6 +5023,9 @@ static bool ui_numedit_but_COLORBAND(uiBut *but, uiHandleButtonData *data, int m
if (data->draglastx == mx)
return changed;
+ if (data->coba->tot == 0)
+ return changed;
+
dx = ((float)(mx - data->draglastx)) / BLI_rctf_size_x(&but->rect);
data->dragcbd->pos += dx;
CLAMP(data->dragcbd->pos, 0.0f, 1.0f);
@@ -6012,7 +6160,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
/* handle drivers */
else if ((event->type == DKEY) &&
- !ELEM3(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) &&
+ !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) &&
(event->val == KM_PRESS))
{
if (event->alt)
@@ -6026,7 +6174,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
/* handle keyingsets */
else if ((event->type == KKEY) &&
- !ELEM3(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) &&
+ !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) &&
(event->val == KM_PRESS))
{
if (event->alt)
@@ -6250,7 +6398,34 @@ static bool ui_but_contains_pt(uiBut *but, float mx, float my)
return BLI_rctf_isect_pt(&but->rect, mx, my);
}
-static uiBut *ui_but_find_activated(ARegion *ar)
+void ui_but_pie_dir(RadialDirection dir, float vec[2])
+{
+ float angle;
+
+ BLI_assert(dir != UI_RADIAL_NONE);
+
+ angle = DEG2RADF((float)ui_radial_dir_to_angle[dir]);
+ vec[0] = cosf(angle);
+ vec[1] = sinf(angle);
+}
+
+static bool ui_but_isect_pie_seg(uiBlock *block, uiBut *but)
+{
+ const float angle_range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? M_PI_4 : M_PI_4 / 2.0;
+ float vec[2];
+
+ if (block->pie_data.flags & UI_PIE_INVALID_DIR)
+ return false;
+
+ ui_but_pie_dir(but->pie_dir, vec);
+
+ if (saacos(dot_v2v2(vec, block->pie_data.pie_dir)) < angle_range)
+ return true;
+
+ return false;
+}
+
+uiBut *ui_but_find_activated(ARegion *ar)
{
uiBlock *block;
uiBut *but;
@@ -6298,13 +6473,27 @@ bool UI_but_active_drop_name(bContext *C)
uiBut *but = ui_but_find_activated(ar);
if (but) {
- if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK))
+ if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK))
return 1;
}
return 0;
}
+bool UI_but_active_drop_color(bContext *C)
+{
+ ARegion *ar = CTX_wm_region(C);
+
+ if (ar) {
+ uiBut *but = ui_but_find_activated(ar);
+
+ if (but && but->type == COLOR)
+ return true;
+ }
+
+ return false;
+}
+
static void ui_blocks_set_tooltips(ARegion *ar, const bool enable)
{
uiBlock *block;
@@ -6354,6 +6543,7 @@ static bool ui_mouse_inside_region(ARegion *ar, int x, int y)
static bool ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y)
{
+ uiBlock *block = but->block;
float mx, my;
if (!ui_mouse_inside_region(ar, x, y))
return false;
@@ -6361,10 +6551,16 @@ static bool ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y)
mx = x;
my = y;
- ui_window_to_block_fl(ar, but->block, &mx, &my);
+ ui_window_to_block_fl(ar, block, &mx, &my);
- if (!ui_but_contains_pt(but, mx, my))
+ if (but->dt == UI_EMBOSSR) {
+ if (!ui_but_isect_pie_seg(block, but)) {
+ return false;
+ }
+ }
+ else if (!ui_but_contains_pt(but, mx, my)) {
return false;
+ }
return true;
}
@@ -6378,7 +6574,7 @@ static bool ui_is_but_interactive(const uiBut *but, const bool labeledit)
/* note, LABEL is included for highlights, this allows drags */
if ((but->type == LABEL) && but->dragpoin == NULL)
return false;
- if (ELEM4(but->type, ROUNDBOX, SEPR, SEPRLINE, LISTBOX))
+ if (ELEM(but->type, ROUNDBOX, SEPR, SEPRLINE, LISTBOX))
return false;
if (but->flag & UI_HIDDEN)
return false;
@@ -6418,7 +6614,13 @@ static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, c
for (but = block->buttons.last; but; but = but->prev) {
if (ui_is_but_interactive(but, labeledit)) {
- if (ui_but_contains_pt(but, mx, my)) {
+ if (but->pie_dir != UI_RADIAL_NONE) {
+ if (ui_but_isect_pie_seg(block, but)) {
+ butover = but;
+ break;
+ }
+ }
+ else if (ui_but_contains_pt(but, mx, my)) {
butover = but;
break;
}
@@ -6471,9 +6673,13 @@ static uiBut *ui_list_find_mouse_over(ARegion *ar, int x, int y)
static bool button_modal_state(uiHandleButtonState state)
{
- return ELEM6(state, BUTTON_STATE_WAIT_RELEASE, BUTTON_STATE_WAIT_KEY_EVENT,
- BUTTON_STATE_NUM_EDITING, BUTTON_STATE_TEXT_EDITING,
- BUTTON_STATE_TEXT_SELECTING, BUTTON_STATE_MENU_OPEN);
+ return ELEM(state,
+ BUTTON_STATE_WAIT_RELEASE,
+ BUTTON_STATE_WAIT_KEY_EVENT,
+ BUTTON_STATE_NUM_EDITING,
+ BUTTON_STATE_TEXT_EDITING,
+ BUTTON_STATE_TEXT_SELECTING,
+ BUTTON_STATE_MENU_OPEN);
}
static void button_timers_tooltip_remove(bContext *C, uiBut *but)
@@ -6511,10 +6717,13 @@ static void button_tooltip_timer_reset(bContext *C, uiBut *but)
data->tooltiptimer = NULL;
}
- if (U.flag & USER_TOOLTIPS)
- if (!but->block->tooltipdisabled)
- if (!wm->drags.first)
+ if ((U.flag & USER_TOOLTIPS) || (but->flag & UI_BUT_TIP_FORCE)) {
+ if (!but->block->tooltipdisabled) {
+ if (!wm->drags.first) {
data->tooltiptimer = WM_event_add_timer(data->wm, data->window, TIMER, BUTTON_TOOLTIP_DELAY);
+ }
+ }
+ }
}
static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState state)
@@ -6619,7 +6828,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
if (!(but->block->handle && but->block->handle->popup)) {
if (button_modal_state(state)) {
if (!button_modal_state(data->state))
- WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data);
+ WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data, false);
}
else {
if (button_modal_state(data->state)) {
@@ -6664,7 +6873,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
copy_v2_fl(data->ungrab_mval, FLT_MAX);
#endif
- if (ELEM3(but->type, BUT_CURVE, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, BUT_CURVE, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
/* XXX curve is temp */
}
else {
@@ -7023,6 +7232,13 @@ static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *ar)
if (event->type == MOUSEMOVE) {
but = ui_but_find_mouse_over(ar, event);
if (but) {
+ if (event->alt) {
+ /* display tooltips if holding alt on mouseover when tooltips are off in prefs */
+ but->flag |= UI_BUT_TIP_FORCE;
+ }
+ else {
+ but->flag &= ~UI_BUT_TIP_FORCE;
+ }
button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
}
}
@@ -7054,6 +7270,17 @@ void ui_button_activate_do(bContext *C, ARegion *ar, uiBut *but)
ui_do_button(C, but->block, but, &event);
}
+/**
+ * Simulate moving the mouse over a button (or navigating to it with arrow keys).
+ *
+ * exported so menus can start with a highlighted button,
+ * even if the mouse isnt over it
+ */
+void ui_button_activate_over(bContext *C, ARegion *ar, uiBut *but)
+{
+ button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
+}
+
void ui_button_execute_begin(struct bContext *UNUSED(C), struct ARegion *ar, uiBut *but, void **active_back)
{
/* note: ideally we would not have to change 'but->active' however
@@ -7116,12 +7343,20 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
retval = WM_UI_HANDLER_CONTINUE;
break;
case MOUSEMOVE:
- /* verify if we are still over the button, if not exit */
- if (!ui_mouse_inside_button(ar, but, event->x, event->y)) {
- data->cancel = true;
- button_activate_state(C, but, BUTTON_STATE_EXIT);
+ {
+ uiBut *but_other = ui_but_find_mouse_over(ar, event);
+ bool exit = false;
+
+ if ((!ui_block_is_menu(block) || ui_block_is_pie_menu(but->block)) &&
+ !ui_mouse_inside_button(ar, but, event->x, event->y))
+ {
+ exit = true;
+ }
+ else if (but_other && ui_but_is_editable(but_other) && (but_other != but)) {
+ exit = true;
}
- else if (ui_but_find_mouse_over(ar, event) != but) {
+
+ if (exit) {
data->cancel = true;
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
@@ -7132,6 +7367,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
}
break;
+ }
case TIMER:
{
/* handle tooltip timer */
@@ -7715,6 +7951,25 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock
int retval;
if (but) {
+ /* Its possible there is an active menu item NOT under the mouse,
+ * in this case ignore mouse clicks outside the button (but Enter etc is accepted) */
+ if (event->val == KM_RELEASE) {
+ /* pass, needed so we can exit active menu-items when click-dragging out of them */
+ }
+ else if (!ui_block_is_menu(but->block) || ui_block_is_pie_menu(but->block)) {
+ /* pass, skip for dialogs */
+ }
+ else if (!ui_mouse_inside_region(but->active->region, event->x, event->y)) {
+ /* pass, needed to click-exit outside of non-flaoting menus */
+ }
+ else if ((!ELEM(event->type, MOUSEMOVE, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN)) && ISMOUSE(event->type)) {
+ if (!ui_mouse_inside_button(but->active->region, but, event->x, event->y)) {
+ but = NULL;
+ }
+ }
+ }
+
+ if (but) {
ScrArea *ctx_area = CTX_wm_area(C);
ARegion *ctx_region = CTX_wm_region(C);
@@ -7733,6 +7988,30 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock
return retval;
}
+void ui_block_calculate_pie_segment(uiBlock *block, const float event_xy[2])
+{
+ float seg1[2];
+ float seg2[2];
+ float len;
+
+ if (block->pie_data.flags & UI_PIE_INITIAL_DIRECTION) {
+ copy_v2_v2(seg1, block->pie_data.pie_center_init);
+ }
+ else {
+ copy_v2_v2(seg1, block->pie_data.pie_center_spawned);
+ }
+
+ sub_v2_v2v2(seg2, event_xy, seg1);
+
+ len = normalize_v2_v2(block->pie_data.pie_dir, seg2);
+
+ /* ten pixels for now, a bit arbitrary */
+ if (len < U.pie_menu_threshold * U.pixelsize)
+ block->pie_data.flags |= UI_PIE_INVALID_DIR;
+ else
+ block->pie_data.flags &= ~UI_PIE_INVALID_DIR;
+}
+
static int ui_handle_menu_event(
bContext *C, const wmEvent *event, uiPopupBlockHandle *menu,
int level, const bool is_parent_inside, const bool is_parent_menu, const bool is_floating)
@@ -7764,6 +8043,7 @@ static int ui_handle_menu_event(
if (menu->is_grab) {
if (event->type == LEFTMOUSE) {
menu->is_grab = false;
+ retval = WM_UI_HANDLER_BREAK;
}
else {
if (event->type == MOUSEMOVE) {
@@ -7968,7 +8248,7 @@ static int ui_handle_menu_event(
for (but = block->buttons.first; but; but = but->next) {
bool doit = false;
- if (!ELEM3(but->type, LABEL, SEPR, SEPRLINE))
+ if (!ELEM(but->type, LABEL, SEPR, SEPRLINE))
count++;
/* exception for rna layer buts */
@@ -8079,7 +8359,7 @@ static int ui_handle_menu_event(
if (inside == 0) {
uiSafetyRct *saferct = block->saferct.first;
- if (ELEM3(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) &&
+ if (ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) &&
ELEM(event->val, KM_PRESS, KM_DBL_CLICK))
{
if ((is_parent_menu == false) && (U.uiflag & USER_MENUOPENAUTO) == 0) {
@@ -8121,9 +8401,14 @@ static int ui_handle_menu_event(
else if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) &&
(inside && is_floating && inside_title))
{
- if (!ui_but_find_activated(ar)) {
+ if (!but || !ui_mouse_inside_button(ar, but, event->x, event->y)) {
+ if (but) {
+ button_timers_tooltip_remove(C, but);
+ }
+
menu->is_grab = true;
copy_v2_v2_int(menu->grab_xy_prev, &event->x);
+ retval = WM_UI_HANDLER_BREAK;
}
}
#endif
@@ -8228,10 +8513,326 @@ static int ui_handle_menu_return_submenu(bContext *C, const wmEvent *event, uiPo
ui_mouse_motion_towards_reinit(menu, &event->x);
}
- if (menu->menuretval)
+ if (menu->menuretval) {
+ /* pie menus should not close but wait for release instead */
+ if ((block->flag & UI_BLOCK_RADIAL) &&
+ !(block->pie_data.flags & UI_PIE_CLICK_STYLE))
+ {
+ menu->menuretval = 0;
+ block->pie_data.flags |= UI_PIE_FINISHED;
+ }
+
return WM_UI_HANDLER_CONTINUE;
- else
+ }
+ else {
+ return WM_UI_HANDLER_BREAK;
+ }
+}
+
+static bool ui_but_pie_menu_supported_apply(uiBut *but)
+{
+ return (but->type != NUMSLI);
+}
+
+static int ui_but_pie_menu_apply(bContext *C, uiPopupBlockHandle *menu, uiBut *but, bool force_close, bool click_style)
+{
+ int retval = WM_UI_HANDLER_BREAK;
+
+ if (but && ui_but_pie_menu_supported_apply(but)) {
+ if (but->type == MENU) {
+ /* forcing the pie menu to close will not handle menus */
+ if (!force_close) {
+ uiBut *active_but = ui_but_find_activated(menu->region);
+
+ if (active_but) {
+ button_activate_exit(C, active_but, active_but->active, false, false);
+ }
+
+ button_activate_init(C, menu->region, but, BUTTON_ACTIVATE_OPEN);
+ return retval;
+ }
+ else {
+ menu->menuretval = UI_RETURN_CANCEL;
+ }
+ }
+ else {
+ ui_apply_button(C, but->block, but, but->active, false);
+ button_activate_exit((bContext *)C, but, but->active, false, true);
+
+ if (!(click_style || force_close)) {
+ but->block->pie_data.flags |= UI_PIE_FINISHED;
+ menu->menuretval = 0;
+ }
+ else {
+ menu->menuretval = UI_RETURN_OK;
+ }
+ }
+ }
+ else {
+ uiBlock *block = menu->region->uiblocks.first;
+
+ if (!(click_style || force_close)) {
+ block->pie_data.flags |= UI_PIE_FINISHED;
+ }
+ else {
+ menu->menuretval = UI_RETURN_CANCEL;
+ }
+
+ ED_region_tag_redraw(menu->region);
+ }
+
+ return retval;
+}
+
+static uiBut *ui_block_pie_dir_activate(uiBlock *block, const wmEvent *event, RadialDirection dir)
+{
+ uiBut *but;
+
+ if ((block->flag & UI_BLOCK_NUMSELECT) && event->val == KM_PRESS) {
+ for (but = block->buttons.first; but; but = but->next) {
+ if (but->pie_dir == dir && !ELEM(but->type, SEPR, SEPRLINE)) {
+ return but;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int ui_but_pie_button_activate(bContext *C, uiBut *but, uiPopupBlockHandle *menu, bool is_click_style)
+{
+ uiBut *active_but;
+
+ if (but == NULL)
+ return WM_UI_HANDLER_BREAK;
+
+ active_but = ui_but_find_activated(menu->region);
+
+ if (active_but)
+ button_activate_exit(C, active_but, active_but->active, false, false);
+
+ button_activate_init(C, menu->region, but, BUTTON_ACTIVATE_OVER);
+ return ui_but_pie_menu_apply(C, menu, but, false, is_click_style);
+}
+
+static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle *menu)
+{
+ ARegion *ar;
+ uiBlock *block;
+ uiBut *but;
+ float event_xy[2];
+ double duration;
+ bool is_click_style;
+
+ /* we block all events, this is modal interaction, except for drop events which is described below */
+ int retval = WM_UI_HANDLER_BREAK;
+
+ if (event->type == EVT_DROP) {
+ /* may want to leave this here for later if we support pie ovens */
+
+ retval = WM_UI_HANDLER_CONTINUE;
+ }
+
+ ar = menu->region;
+ block = ar->uiblocks.first;
+
+ is_click_style = (block->pie_data.flags & UI_PIE_CLICK_STYLE);
+
+ if (menu->scrolltimer == NULL) {
+ menu->scrolltimer =
+ WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, PIE_MENU_INTERVAL);
+ menu->scrolltimer->duration = 0.0;
+ }
+
+ duration = menu->scrolltimer->duration;
+
+ if (event->type == TIMER) {
+ if (event->customdata == menu->scrolltimer) {
+ /* deactivate initial direction after a while */
+ if (duration > 0.01 * U.pie_initial_timeout) {
+ block->pie_data.flags &= ~UI_PIE_INITIAL_DIRECTION;
+ }
+
+ /* handle animation */
+ if (!(block->pie_data.flags & UI_PIE_ANIMATION_FINISHED)) {
+ uiBut *but;
+ double final_time = 0.01 * U.pie_animation_timeout;
+ float fac = duration / final_time;
+ float pie_radius = U.pie_menu_radius * UI_DPI_FAC;
+
+ if (fac > 1.0f) {
+ fac = 1.0f;
+ block->pie_data.flags |= UI_PIE_ANIMATION_FINISHED;
+ }
+
+ for (but = block->buttons.first; but; but = but->next) {
+ if (but->pie_dir != UI_RADIAL_NONE) {
+ float vec[2];
+ float center[2];
+
+ ui_but_pie_dir(but->pie_dir, vec);
+
+ center[0] = (vec[0] > 0.01f) ? 0.5f : ((vec[0] < -0.01f) ? -0.5f : 0.0f);
+ center[1] = (vec[1] > 0.99f) ? 0.5f : ((vec[1] < -0.99f) ? -0.5f : 0.0f);
+
+ center[0] *= BLI_rctf_size_x(&but->rect);
+ center[1] *= BLI_rctf_size_y(&but->rect);
+
+ mul_v2_fl(vec, pie_radius);
+ add_v2_v2(vec, center);
+ mul_v2_fl(vec, fac);
+ add_v2_v2(vec, block->pie_data.pie_center_spawned);
+
+ BLI_rctf_recenter(&but->rect, vec[0], vec[1]);
+ }
+ }
+ block->pie_data.alphafac = fac;
+
+ ED_region_tag_redraw(ar);
+ }
+ }
+ }
+
+ event_xy[0] = event->x;
+ event_xy[1] = event->y;
+
+ ui_window_to_block_fl(ar, block, &event_xy[0], &event_xy[1]);
+
+ ui_block_calculate_pie_segment(block, event_xy);
+
+ if (block->pie_data.flags & UI_PIE_FINISHED) {
+ if ((event->type == block->pie_data.event && event->val == KM_RELEASE) ||
+ ((event->type == RIGHTMOUSE || event->type == ESCKEY) && (event->val == KM_PRESS)))
+ {
+ menu->menuretval = UI_RETURN_OK;
+ }
+
+ ED_region_tag_redraw(ar);
return WM_UI_HANDLER_BREAK;
+ }
+
+ if (event->type == block->pie_data.event) {
+ if (event->val != KM_RELEASE) {
+ ui_handle_menu_button(C, event, menu);
+
+ if (len_squared_v2v2(event_xy, block->pie_data.pie_center_init) > PIE_CLICK_THRESHOLD_SQ) {
+ block->pie_data.flags |= UI_PIE_DRAG_STYLE;
+ }
+ /* why redraw here? It's simple, we are getting many double click events here.
+ * Those operate like mouse move events almost */
+ ED_region_tag_redraw(ar);
+ }
+ else {
+ /* distance from initial point */
+ if (!(block->pie_data.flags & UI_PIE_DRAG_STYLE)) {
+ block->pie_data.flags |= UI_PIE_CLICK_STYLE;
+ }
+ else if (!is_click_style) {
+ uiBut *but = ui_but_find_activated(menu->region);
+
+ retval = ui_but_pie_menu_apply(C, menu, but, true, is_click_style);
+ }
+ }
+ }
+ else {
+ /* direction from numpad */
+ RadialDirection num_dir = UI_RADIAL_NONE;
+
+ switch (event->type) {
+ case MOUSEMOVE:
+ if (len_squared_v2v2(event_xy, block->pie_data.pie_center_init) > PIE_CLICK_THRESHOLD_SQ) {
+ block->pie_data.flags |= UI_PIE_DRAG_STYLE;
+ }
+ ui_handle_menu_button(C, event, menu);
+
+ /* mouse move should always refresh the area for pie menus */
+ ED_region_tag_redraw(ar);
+ break;
+
+ case LEFTMOUSE:
+ if (event->val == KM_PRESS) {
+ uiBut *but = ui_but_find_activated(menu->region);
+ retval = ui_but_pie_menu_apply(C, menu, but, false, is_click_style);
+ }
+ break;
+
+ case ESCKEY:
+ case RIGHTMOUSE:
+ if (!is_click_style) {
+ block->pie_data.flags |= UI_PIE_FINISHED;
+ menu->menuretval = 0;
+ ED_region_tag_redraw(ar);
+ }
+ else
+ menu->menuretval = UI_RETURN_CANCEL;
+ break;
+
+ case AKEY:
+ case BKEY:
+ case CKEY:
+ case DKEY:
+ case EKEY:
+ case FKEY:
+ case GKEY:
+ case HKEY:
+ case IKEY:
+ case JKEY:
+ case KKEY:
+ case LKEY:
+ case MKEY:
+ case NKEY:
+ case OKEY:
+ case PKEY:
+ case QKEY:
+ case RKEY:
+ case SKEY:
+ case TKEY:
+ case UKEY:
+ case VKEY:
+ case WKEY:
+ case XKEY:
+ case YKEY:
+ case ZKEY:
+ {
+ if ((event->val == KM_PRESS || event->val == KM_DBL_CLICK) &&
+ (event->shift == 0) &&
+ (event->ctrl == 0) &&
+ (event->oskey == 0))
+ {
+ for (but = block->buttons.first; but; but = but->next) {
+ if (but->menu_key == event->type) {
+ ui_but_pie_button_activate(C, but, menu, is_click_style);
+ }
+ }
+ }
+ break;
+ }
+
+#define CASE_NUM_TO_DIR(n, d) \
+ case (ZEROKEY + n): case (PAD0 + n): \
+ { if (num_dir == UI_RADIAL_NONE) num_dir = d; } (void)0
+
+ CASE_NUM_TO_DIR(1, UI_RADIAL_SW);
+ CASE_NUM_TO_DIR(2, UI_RADIAL_S);
+ CASE_NUM_TO_DIR(3, UI_RADIAL_SE);
+ CASE_NUM_TO_DIR(4, UI_RADIAL_W);
+ CASE_NUM_TO_DIR(6, UI_RADIAL_E);
+ CASE_NUM_TO_DIR(7, UI_RADIAL_NW);
+ CASE_NUM_TO_DIR(8, UI_RADIAL_N);
+ CASE_NUM_TO_DIR(9, UI_RADIAL_NE);
+ {
+ but = ui_block_pie_dir_activate(block, event, num_dir);
+ retval = ui_but_pie_button_activate(C, but, menu, is_click_style);
+ break;
+ }
+#undef CASE_NUM_TO_DIR
+ default:
+ retval = ui_handle_menu_button(C, event, menu);
+ break;
+ }
+ }
+
+ return retval;
}
static int ui_handle_menus_recursive(
@@ -8253,17 +8854,21 @@ static int ui_handle_menus_recursive(
uiBlock *block = menu->region->uiblocks.first;
const bool is_menu = ui_block_is_menu(block);
bool inside = false;
+ /* root pie menus accept the key that spawned them as double click to improve responsiveness */
+ bool do_recursion = (!(block->flag & UI_BLOCK_RADIAL) || event->type != block->pie_data.event);
- if (is_parent_inside == false) {
- int mx, my;
+ if (do_recursion) {
+ if (is_parent_inside == false) {
+ int mx, my;
- mx = event->x;
- my = event->y;
- ui_window_to_block(menu->region, block, &mx, &my);
- inside = BLI_rctf_isect_pt(&block->rect, mx, my);
- }
+ mx = event->x;
+ my = event->y;
+ ui_window_to_block(menu->region, block, &mx, &my);
+ inside = BLI_rctf_isect_pt(&block->rect, mx, my);
+ }
- retval = ui_handle_menus_recursive(C, event, submenu, level + 1, is_parent_inside || inside, is_menu, false);
+ retval = ui_handle_menus_recursive(C, event, submenu, level + 1, is_parent_inside || inside, is_menu, false);
+ }
}
/* now handle events for our own menu */
@@ -8296,7 +8901,12 @@ static int ui_handle_menus_recursive(
}
}
else {
- retval = ui_handle_menu_event(C, event, menu, level, is_parent_inside, is_parent_menu, is_floating);
+ uiBlock *block = menu->region->uiblocks.first;
+
+ if (block->flag & UI_BLOCK_RADIAL)
+ retval = ui_handler_pie(C, event, menu);
+ else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK)
+ retval = ui_handle_menu_event(C, event, menu, level, is_parent_inside, is_parent_menu, is_floating);
}
}
@@ -8458,15 +9068,15 @@ static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata)
/* free if done, does not free handle itself */
if (menu->menuretval) {
+ wmWindow *win = CTX_wm_window(C);
/* copy values, we have to free first (closes region) */
uiPopupBlockHandle temp = *menu;
ui_popup_block_free(C, menu);
- UI_remove_popup_handlers(&CTX_wm_window(C)->modalhandlers, menu);
+ UI_remove_popup_handlers(&win->modalhandlers, menu);
#ifdef USE_DRAG_TOGGLE
{
- wmWindow *win = CTX_wm_window(C);
WM_event_free_ui_handler_all(C, &win->modalhandlers,
ui_handler_region_drag_toggle, ui_handler_region_drag_toggle_remove);
}
@@ -8476,7 +9086,7 @@ static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata)
if (temp.popup_func)
temp.popup_func(C, temp.popup_arg, temp.retvalue);
if (temp.optype)
- WM_operator_name_call(C, temp.optype->idname, temp.opcontext, NULL);
+ WM_operator_name_call_ptr(C, temp.optype, temp.opcontext, NULL);
}
else if (temp.cancel_func)
temp.cancel_func(C, temp.popup_arg);
@@ -8511,12 +9121,12 @@ static void ui_handler_remove_popup(bContext *C, void *userdata)
void UI_add_region_handlers(ListBase *handlers)
{
WM_event_remove_ui_handler(handlers, ui_handler_region, ui_handler_remove_region, NULL, false);
- WM_event_add_ui_handler(NULL, handlers, ui_handler_region, ui_handler_remove_region, NULL);
+ WM_event_add_ui_handler(NULL, handlers, ui_handler_region, ui_handler_remove_region, NULL, false);
}
-void UI_add_popup_handlers(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup)
+void UI_add_popup_handlers(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup, const bool accept_dbl_click)
{
- WM_event_add_ui_handler(C, handlers, ui_handler_popup, ui_handler_remove_popup, popup);
+ WM_event_add_ui_handler(C, handlers, ui_handler_popup, ui_handler_remove_popup, popup, accept_dbl_click);
}
void UI_remove_popup_handlers(ListBase *handlers, uiPopupBlockHandle *popup)
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index be6752953d1..cc8fc941ae7 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -508,6 +508,8 @@ static void init_brush_icons(void)
INIT_BRUSH_ICON(ICON_BRUSH_SOFTEN, soften);
INIT_BRUSH_ICON(ICON_BRUSH_SUBTRACT, subtract);
INIT_BRUSH_ICON(ICON_BRUSH_TEXDRAW, texdraw);
+ INIT_BRUSH_ICON(ICON_BRUSH_TEXFILL, texfill);
+ INIT_BRUSH_ICON(ICON_BRUSH_TEXMASK, texmask);
INIT_BRUSH_ICON(ICON_BRUSH_THUMB, thumb);
INIT_BRUSH_ICON(ICON_BRUSH_ROTATE, twist);
INIT_BRUSH_ICON(ICON_BRUSH_VERTEXDRAW, vertexdraw);
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index cd3b6390184..cdc611a60f4 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -88,6 +88,7 @@ typedef enum {
UI_WTYPE_PULLDOWN,
UI_WTYPE_MENU_ITEM,
+ UI_WTYPE_MENU_ITEM_RADIAL,
UI_WTYPE_MENU_BACK,
/* specials */
@@ -121,6 +122,23 @@ enum {
/* warn: rest of uiBut->flag in UI_interface.h */
};
+/* but->pie_dir */
+typedef enum RadialDirection {
+ UI_RADIAL_NONE = -1,
+ UI_RADIAL_N = 0,
+ UI_RADIAL_NE = 1,
+ UI_RADIAL_E = 2,
+ UI_RADIAL_SE = 3,
+ UI_RADIAL_S = 4,
+ UI_RADIAL_SW = 5,
+ UI_RADIAL_W = 6,
+ UI_RADIAL_NW = 7,
+} RadialDirection;
+
+extern const char ui_radial_dir_order[8];
+extern const char ui_radial_dir_to_numpad[8];
+extern const short ui_radial_dir_to_angle[8];
+
/* internal panel drawing defines */
#define PNL_GRID (UI_UNIT_Y / 5) /* 4 default */
#define PNL_HEADER (UI_UNIT_Y + 4) /* 24 default */
@@ -144,6 +162,19 @@ enum {
/* split numbuts by ':' and align l/r */
#define USE_NUMBUTS_LR_ALIGN
+/* PieMenuData->flags */
+enum {
+ UI_PIE_DEGREES_RANGE_LARGE = (1 << 0), /* pie menu item collision is detected at 90 degrees */
+ UI_PIE_INITIAL_DIRECTION = (1 << 1), /* use initial center of pie menu to calculate direction */
+ UI_PIE_DRAG_STYLE = (1 << 2), /* pie menu is drag style */
+ UI_PIE_INVALID_DIR = (1 << 3), /* mouse not far enough from center position */
+ UI_PIE_FINISHED = (1 << 4), /* pie menu finished but we still wait for a release event */
+ UI_PIE_CLICK_STYLE = (1 << 5), /* pie menu changed to click style, click to confirm */
+ UI_PIE_ANIMATION_FINISHED = (1 << 6), /* pie animation finished, do not calculate any more motio */
+};
+
+#define PIE_CLICK_THRESHOLD_SQ 50.0f
+
typedef struct uiLinkLine { /* only for draw/edit */
struct uiLinkLine *next, *prev;
struct uiBut *from, *to;
@@ -186,6 +217,7 @@ struct uiBut {
* (type == LABEL), Use (a1 == 1.0f) to use a2 as a blending factor (wow, this is imaginative!).
* (type == SCROLL) Use as scroll size.
* (type == SEARCH_MENU) Use as number or rows.
+ * (type == COLOR) Use as indication of color palette
*/
float a1;
@@ -193,6 +225,7 @@ struct uiBut {
* (type == NUM), Use to store RNA 'precision' value, for dragging and click-step.
* (type == LABEL), If (a1 == 1.0f) use a2 as a blending factor.
* (type == SEARCH_MENU) Use as number or columns.
+ * (type == COLOR) Use as indication of active palette color
*/
float a2;
@@ -225,6 +258,7 @@ struct uiBut {
BIFIconID icon;
bool lock;
char dt; /* drawtype: UI_EMBOSS, UI_EMBOSSN ... etc, copied from the block */
+ signed char pie_dir; /* direction in a pie menu, used for collision detection (RadialDirection) */
char changed; /* could be made into a single flag */
unsigned char unit_type; /* so buttons can support unit systems which are not RNA */
short modifier_key;
@@ -272,6 +306,15 @@ struct uiBut {
uiBlock *block;
};
+struct PieMenuData {
+ float pie_dir[2];
+ float pie_center_init[2];
+ float pie_center_spawned[2];
+ int flags;
+ int event; /* initial event used to fire the pie menu, store here so we can query for release */
+ float alphafac;
+};
+
struct uiBlock {
uiBlock *next, *prev;
@@ -354,6 +397,7 @@ struct uiBlock {
char display_device[64]; /* display device name used to display this block,
* used by color widgets to transform colors from/to scene linear
*/
+ struct PieMenuData pie_data;
};
typedef struct uiSafetyRct {
@@ -369,6 +413,7 @@ extern void ui_delete_linkline(uiLinkLine *line, uiBut *but);
void ui_fontscale(short *points, float aspect);
extern bool ui_block_is_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
+extern bool ui_block_is_pie_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
extern void ui_block_to_window_fl(const struct ARegion *ar, uiBlock *block, float *x, float *y);
extern void ui_block_to_window(const struct ARegion *ar, uiBlock *block, int *x, int *y);
extern void ui_block_to_window_rctf(const struct ARegion *ar, uiBlock *block, rctf *rct_dst, const rctf *rct_src);
@@ -550,12 +595,19 @@ void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol
PointerRNA *ui_handle_afterfunc_add_operator(struct wmOperatorType *ot, int opcontext, bool create_props);
extern void ui_pan_to_scroll(const struct wmEvent *event, int *type, int *val);
extern void ui_button_activate_do(struct bContext *C, struct ARegion *ar, uiBut *but);
+extern void ui_button_activate_over(struct bContext *C, struct ARegion *ar, uiBut *but);
extern void ui_button_execute_begin(struct bContext *C, struct ARegion *ar, uiBut *but, void **active_back);
extern void ui_button_execute_end(struct bContext *C, struct ARegion *ar, uiBut *but, void *active_back);
extern void ui_button_active_free(const struct bContext *C, uiBut *but);
extern bool ui_button_is_active(struct ARegion *ar) ATTR_WARN_UNUSED_RESULT;
extern int ui_button_open_menu_direction(uiBut *but);
extern void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore);
+extern uiBut *ui_but_find_activated(struct ARegion *ar);
+bool ui_but_is_editable(const uiBut *but);
+void ui_but_pie_dir_visual(RadialDirection dir, float vec[2]);
+void ui_but_pie_dir(RadialDirection dir, float vec[2]);
+void ui_block_calculate_pie_segment(struct uiBlock *block, const float event_xy[2]);
+
void ui_button_clipboard_free(void);
void ui_panel_menu(struct bContext *C, ARegion *ar, Panel *pa);
uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new);
@@ -565,6 +617,7 @@ uiBut *ui_but_find_new(uiBlock *block_old, const uiBut *but_new);
void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3);
void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha);
void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect);
+void ui_draw_pie_center(uiBlock *block);
uiWidgetColors *ui_tooltip_get_theme(void);
void ui_draw_tooltip_background(uiStyle *UNUSED(style), uiBlock *block, rcti *rect);
void ui_draw_search_back(struct uiStyle *style, uiBlock *block, rcti *rect);
@@ -589,7 +642,6 @@ int ui_id_icon_get(struct bContext *C, struct ID *id, const bool big);
/* resources.c */
void init_userdef_do_versions(void);
-void init_userdef_factory(void);
void ui_theme_init_default(void);
void ui_style_init_default(void);
void ui_resources_init(void);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 789c10d6693..27af550b173 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -106,6 +106,7 @@ typedef enum uiItemType {
ITEM_LAYOUT_ABSOLUTE,
ITEM_LAYOUT_SPLIT,
ITEM_LAYOUT_OVERLAP,
+ ITEM_LAYOUT_RADIAL,
ITEM_LAYOUT_ROOT
#if 0
@@ -218,7 +219,9 @@ static int ui_item_fit(int item, int pos, int all, int available, int last, int
static int ui_layout_vary_direction(uiLayout *layout)
{
- return (layout->root->type == UI_LAYOUT_HEADER || layout->alignment != UI_LAYOUT_ALIGN_EXPAND) ? UI_ITEM_VARY_X : UI_ITEM_VARY_Y;
+ return ((ELEM(layout->root->type, UI_LAYOUT_HEADER, UI_LAYOUT_PIEMENU) ||
+ (layout->alignment != UI_LAYOUT_ALIGN_EXPAND)) ?
+ UI_ITEM_VARY_X : UI_ITEM_VARY_Y);
}
/* estimated size of text + icon */
@@ -553,15 +556,24 @@ static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *pt
*/
uiBut *but;
+ uiLayout *layout_radial = NULL;
EnumPropertyItem *item, *item_array;
const char *name;
int itemw, icon, value;
bool free;
+ bool radial = (layout->root->type == UI_LAYOUT_PIEMENU);
- RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item_array, NULL, &free);
+ if (radial)
+ RNA_property_enum_items_gettexted_all(block->evil_C, ptr, prop, &item_array, NULL, &free);
+ else
+ RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item_array, NULL, &free);
/* we dont want nested rows, cols in menus */
- if (layout->root->type != UI_LAYOUT_MENU) {
+ if (radial) {
+ layout_radial = uiLayoutRadial(layout);
+ uiBlockSetCurLayout(block, layout_radial);
+ }
+ else if (layout->root->type != UI_LAYOUT_MENU) {
uiBlockSetCurLayout(block, ui_item_local_sublayout(layout, layout, 1));
}
else {
@@ -569,8 +581,11 @@ static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *pt
}
for (item = item_array; item->identifier; item++) {
- if (!item->identifier[0])
+ if (!item->identifier[0]) {
+ if (radial)
+ uiItemS(layout_radial);
continue;
+ }
name = (!uiname || uiname[0]) ? item->name : "";
icon = item->icon;
@@ -869,6 +884,8 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname
PointerRNA ptr;
PropertyRNA *prop;
uiBlock *block = layout->root->block;
+ const bool radial = (layout->item.type == ITEM_LAYOUT_RADIAL) ||
+ ((layout->item.type == ITEM_LAYOUT_ROOT) && (layout->root->type == UI_LAYOUT_PIEMENU));
if (!ot || !ot->srna) {
ui_item_disabled(layout, opname);
@@ -887,10 +904,24 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname
if (prop && RNA_property_type(prop) == PROP_ENUM) {
EnumPropertyItem *item, *item_array = NULL;
bool free;
- uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
- uiLayout *column = uiLayoutColumn(split, layout->align);
+ uiLayout *split;
+ uiLayout *target;
+
+ if (radial) {
+ target = uiLayoutRadial(layout);
+ }
+ else {
+ split = uiLayoutSplit(layout, 0.0f, false);
+ target = uiLayoutColumn(split, layout->align);
+ }
+
+ if (radial) {
+ RNA_property_enum_items_gettexted_all(block->evil_C, &ptr, prop, &item_array, NULL, &free);
+ }
+ else {
+ RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, NULL, &free);
+ }
- RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, NULL, &free);
for (item = item_array; item->identifier; item++) {
if (item->identifier[0]) {
PointerRNA tptr;
@@ -905,20 +936,24 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname
}
RNA_property_enum_set(&tptr, prop, item->value);
- uiItemFullO_ptr(column, ot, item->name, item->icon, tptr.data, context, flag);
+ uiItemFullO_ptr(target, ot, item->name, item->icon, tptr.data, context, flag);
+
ui_but_tip_from_enum_item(block->buttons.last, item);
}
else {
if (item->name) {
uiBut *but;
- if (item != item_array) {
- column = uiLayoutColumn(split, layout->align);
+
+ if (item != item_array && !radial) {
+ target = uiLayoutColumn(split, layout->align);
+
/* inconsistent, but menus with labels do not look good flipped */
block->flag |= UI_BLOCK_NO_FLIP;
}
- if (item->icon) {
- uiItemL(column, item->name, item->icon);
+ if (item->icon || radial) {
+ uiItemL(target, item->name, item->icon);
+
but = block->buttons.last;
}
else {
@@ -928,8 +963,14 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname
}
ui_but_tip_from_enum_item(but, item);
}
- else { /* XXX bug here, colums draw bottom item badly */
- uiItemS(column);
+ else {
+ if (radial) {
+ uiItemS(target);
+ }
+ else {
+ /* XXX bug here, colums draw bottom item badly */
+ uiItemS(target);
+ }
}
}
}
@@ -1181,7 +1222,7 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
if (flag & UI_ITEM_R_ICON_ONLY) {
/* pass */
}
- else if (ELEM4(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER)) {
+ else if (ELEM(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER)) {
name = ui_item_name_add_colon(name, namestr);
}
else if (type == PROP_BOOLEAN && is_array && index == RNA_NO_INDEX) {
@@ -1323,9 +1364,9 @@ void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *pr
for (a = 0; item[a].identifier; a++) {
if (item[a].value == ivalue) {
- const char *item_name = CTX_IFACE_(RNA_property_translation_context(prop), item[a].name);
+ const char *item_name = name ? name : CTX_IFACE_(RNA_property_translation_context(prop), item[a].name);
- uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, item_name ? item_name : name, icon ? icon : item[a].icon);
+ uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, item_name, icon ? icon : item[a].icon);
break;
}
}
@@ -1559,7 +1600,7 @@ void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propna
}
type = RNA_property_type(prop);
- if (!ELEM3(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) {
+ if (!ELEM(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) {
RNA_warning("Property %s must be a pointer, string or enum", propname);
return;
}
@@ -2072,16 +2113,135 @@ static void ui_litem_layout_column(uiLayout *litem)
litem->y = y;
}
+/* calculates the angle of a specified button in a radial menu,
+ * stores a float vector in unit circle */
+static RadialDirection ui_get_radialbut_vec(float vec[2], short itemnum)
+{
+ RadialDirection dir;
+ BLI_assert(itemnum < 8);
+
+ dir = ui_radial_dir_order[itemnum];
+ ui_but_pie_dir(dir, vec);
+
+ return dir;
+}
+
+static bool ui_item_is_radial_displayable(uiItem *item)
+{
+
+ if ((item->type == ITEM_BUTTON) && (((uiButtonItem *)item)->but->type == LABEL))
+ return false;
+
+ return true;
+}
+
+static bool ui_item_is_radial_drawable(uiButtonItem *bitem)
+{
+
+ if (ELEM(bitem->but->type, SEPR, SEPRLINE))
+ return false;
+
+ return true;
+}
+
+static void ui_litem_layout_radial(uiLayout *litem)
+{
+ uiItem *item;
+ int itemh, itemw, x, y;
+ int itemnum = 0;
+ int totitems = 0;
+
+ int minx, miny, maxx, maxy;
+ /* For the radial layout we will use Matt Ebb's design
+ * for radiation, see http://mattebb.com/weblog/radiation/
+ * also the old code at http://developer.blender.org/T5103
+ */
+
+ int pie_radius = U.pie_menu_radius * UI_DPI_FAC;
+
+ x = litem->x;
+ y = litem->y;
+
+ minx = x, miny = y, maxx = x, maxy = y;
+
+ /* first count total items */
+ for (item = litem->items.first; item; item = item->next)
+ totitems++;
+
+ if (totitems < 5)
+ litem->root->block->pie_data.flags |= UI_PIE_DEGREES_RANGE_LARGE;
+
+ for (item = litem->items.first; item; item = item->next) {
+ /* not all button types are drawn in a radial menu, do filtering here */
+ if (ui_item_is_radial_displayable(item)) {
+ RadialDirection dir;
+ float vec[2];
+ float factor[2];
+
+ dir = ui_get_radialbut_vec(vec, itemnum);
+ factor[0] = (vec[0] > 0.01f) ? 0.0f : ((vec[0] < -0.01f) ? -1.0f : -0.5f);
+ factor[1] = (vec[1] > 0.99f) ? 0.0f : ((vec[1] < -0.99f) ? -1.0f : -0.5f);
+
+ itemnum++;
+
+ if (item->type == ITEM_BUTTON) {
+ uiButtonItem *bitem = (uiButtonItem *) item;
+
+ bitem->but->pie_dir = dir;
+ /* scale the buttons */
+ bitem->but->rect.ymax *= 1.5f;
+ /* add a little bit more here to include number */
+ bitem->but->rect.xmax += 1.5f * UI_UNIT_X;
+ /* enable drawing as pie item if supported by widget */
+ if (ui_item_is_radial_drawable(bitem))
+ bitem->but->dt = UI_EMBOSSR;
+ }
+
+ ui_item_size(item, &itemw, &itemh);
+
+ ui_item_position(item, x + vec[0] * pie_radius + factor[0] * itemw, y + vec[1] * pie_radius + factor[1] * itemh, itemw, itemh);
+
+ minx = min_ii(minx, x + vec[0] * pie_radius - itemw / 2);
+ maxx = max_ii(maxx, x + vec[0] * pie_radius + itemw / 2);
+ miny = min_ii(miny, y + vec[1] * pie_radius - itemh / 2);
+ maxy = max_ii(maxy, y + vec[1] * pie_radius + itemh / 2);
+ }
+ }
+
+ litem->x = minx;
+ litem->y = miny;
+ litem->w = maxx - minx;
+ litem->h = maxy - miny;
+}
+
/* root layout */
static void ui_litem_estimate_root(uiLayout *UNUSED(litem))
{
/* nothing to do */
}
+static void ui_litem_layout_root_radial(uiLayout *litem)
+{
+ /* first item is pie menu title, align on center of menu */
+ uiItem *item = litem->items.first;
+
+ if (item->type == ITEM_BUTTON) {
+ int itemh, itemw, x, y;
+ x = litem->x;
+ y = litem->y;
+
+ ui_item_size(item, &itemw, &itemh);
+
+ ui_item_position(item, x - itemw / 2, y + U.pixelsize * (U.pie_menu_threshold + 9.0f), itemw, itemh);
+ }
+}
+
static void ui_litem_layout_root(uiLayout *litem)
{
if (litem->root->type == UI_LAYOUT_HEADER)
ui_litem_layout_row(litem);
+ else if (litem->root->type == UI_LAYOUT_PIEMENU)
+ ui_litem_layout_root_radial(litem);
else
ui_litem_layout_column(litem);
}
@@ -2497,6 +2657,40 @@ static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type)
return box;
}
+uiLayout *uiLayoutRadial(uiLayout *layout)
+{
+ uiLayout *litem;
+ uiItem *item;
+
+ /* radial layouts are only valid for radial menus */
+ if (layout->root->type != UI_LAYOUT_PIEMENU)
+ return ui_item_local_sublayout(layout, layout, 0);
+
+ /* only one radial wheel per root layout is allowed, so check and return that, if it exists */
+ for (item = layout->root->layout->items.first; item; item = item->next) {
+ litem = (uiLayout *)item;
+ if (litem->item.type == ITEM_LAYOUT_RADIAL) {
+ uiBlockSetCurLayout(layout->root->block, litem);
+ return litem;
+ }
+ }
+
+ litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRadial");
+ litem->item.type = ITEM_LAYOUT_RADIAL;
+ litem->root = layout->root;
+ litem->active = true;
+ litem->enabled = true;
+ litem->context = layout->context;
+ litem->redalert = layout->redalert;
+ litem->w = layout->w;
+ BLI_addtail(&layout->root->layout->items, litem);
+
+ uiBlockSetCurLayout(layout->root->block, litem);
+
+ return litem;
+}
+
+
uiLayout *uiLayoutBox(uiLayout *layout)
{
return (uiLayout *)ui_layout_box(layout, ROUNDBOX);
@@ -2843,6 +3037,9 @@ static void ui_item_layout(uiItem *item)
case ITEM_LAYOUT_OVERLAP:
ui_litem_layout_overlap(litem);
break;
+ case ITEM_LAYOUT_RADIAL:
+ ui_litem_layout_radial(litem);
+ break;
default:
break;
}
@@ -2916,7 +3113,7 @@ uiLayout *uiBlockLayout(uiBlock *block, int dir, int type, int x, int y, int siz
layout->enabled = 1;
layout->context = NULL;
- if (type == UI_LAYOUT_MENU)
+ if (type == UI_LAYOUT_MENU || type == UI_LAYOUT_PIEMENU)
layout->space = 0;
if (dir == UI_LAYOUT_HORIZONTAL) {
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 316a4d34881..817445cc14e 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -35,6 +35,7 @@
#include "DNA_text_types.h" /* for UI_OT_reports_to_text */
#include "BLI_blenlib.h"
+#include "BLI_math_color.h"
#include "BLF_api.h"
#include "BLF_translation.h"
@@ -44,6 +45,7 @@
#include "BKE_global.h"
#include "BKE_text.h" /* for UI_OT_reports_to_text */
#include "BKE_report.h"
+#include "BKE_paint.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -55,6 +57,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_paint.h"
+
/* only for UI_OT_editsource */
#include "ED_screen.h"
#include "BKE_main.h"
@@ -258,28 +262,43 @@ static void UI_OT_unset_property_button(wmOperatorType *ot)
/* Copy To Selected Operator ------------------------ */
-static bool copy_to_selected_list(bContext *C, PointerRNA *ptr, ListBase *lb, bool *use_path)
+static bool copy_to_selected_list(
+ bContext *C, PointerRNA *ptr, PropertyRNA *prop,
+ ListBase *r_lb, bool *r_use_path_from_id, char **r_path)
{
- *use_path = false;
+ *r_use_path_from_id = false;
+ *r_path = NULL;
- if (RNA_struct_is_a(ptr->type, &RNA_EditBone))
- *lb = CTX_data_collection_get(C, "selected_editable_bones");
- else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone))
- *lb = CTX_data_collection_get(C, "selected_pose_bones");
- else if (RNA_struct_is_a(ptr->type, &RNA_Sequence))
- *lb = CTX_data_collection_get(C, "selected_editable_sequences");
- else {
+ if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_bones");
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
+ *r_lb = CTX_data_collection_get(C, "selected_pose_bones");
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
+ }
+ else if (ptr->id.data) {
ID *id = ptr->id.data;
- if (id && GS(id->name) == ID_OB) {
- *lb = CTX_data_collection_get(C, "selected_editable_objects");
- *use_path = true;
+ if (GS(id->name) == ID_OB) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_objects");
+ *r_use_path_from_id = true;
+ *r_path = RNA_path_from_ID_to_property(ptr, prop);
}
- else {
- return false;
+ else if (GS(id->name) == ID_SCE) {
+ /* Sequencer's ID is scene :/ */
+ /* Try to recursively find an RNA_Sequence ancestor, to handle situations like T41062... */
+ if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != NULL) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
+ }
}
+ return (*r_path != NULL);
}
-
+ else {
+ return false;
+ }
+
return true;
}
@@ -303,47 +322,54 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll)
/* if there is a valid property that is editable... */
if (ptr.data && prop) {
char *path = NULL;
- bool use_path;
+ bool use_path_from_id;
CollectionPointerLink *link;
ListBase lb;
- if (!copy_to_selected_list(C, &ptr, &lb, &use_path))
+ if (!copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path))
return success;
- if (!use_path || (path = RNA_path_from_ID_to_property(&ptr, prop))) {
- for (link = lb.first; link; link = link->next) {
- if (link->ptr.data != ptr.data) {
- if (use_path) {
- lprop = NULL;
- RNA_id_pointer_create(link->ptr.id.data, &idptr);
- RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
- }
- else {
- lptr = link->ptr;
- lprop = prop;
- }
+ for (link = lb.first; link; link = link->next) {
+ if (link->ptr.data != ptr.data) {
+ if (use_path_from_id) {
+ /* Path relative to ID. */
+ lprop = NULL;
+ RNA_id_pointer_create(link->ptr.id.data, &idptr);
+ RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
+ }
+ else if (path) {
+ /* Path relative to elements from list. */
+ lprop = NULL;
+ RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
+ }
+ else {
+ lptr = link->ptr;
+ lprop = prop;
+ }
- if (lprop == prop) {
- if (RNA_property_editable(&lptr, lprop)) {
- if (poll) {
+ if (lptr.data == ptr.data) {
+ /* lptr might not be the same as link->ptr! */
+ continue;
+ }
+
+ if (lprop == prop) {
+ if (RNA_property_editable(&lptr, lprop)) {
+ if (poll) {
+ success = true;
+ break;
+ }
+ else {
+ if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) {
+ RNA_property_update(C, &lptr, prop);
success = true;
- break;
- }
- else {
- if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) {
- RNA_property_update(C, &lptr, prop);
- success = true;
- }
}
}
}
}
}
-
- if (path)
- MEM_freeN(path);
}
+ MEM_SAFE_FREE(path);
BLI_freelistN(&lb);
}
@@ -693,6 +719,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
int ret = OPERATOR_CANCELLED;
if (but) {
+ wmOperatorType *ot;
PointerRNA ptr;
char popath[FILE_MAX];
const char *root = U.i18ndir;
@@ -714,7 +741,8 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
"Directory' path to a valid directory");
return OPERATOR_CANCELLED;
}
- if (!WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0)) {
+ 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 addon "
"in the User Preferences", EDTSRC_I18N_OP_NAME);
return OPERATOR_CANCELLED;
@@ -730,7 +758,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
uiButGetStrInfo(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, EDTSRC_I18N_OP_NAME);
+ 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);
@@ -743,7 +771,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
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(C, EDTSRC_I18N_OP_NAME, WM_OP_INVOKE_DEFAULT, &ptr);
+ ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
/* Clean up */
if (but_label.strinfo)
@@ -808,6 +836,99 @@ static void UI_OT_reloadtranslation(wmOperatorType *ot)
ot->exec = reloadtranslation_exec;
}
+int UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(event))
+{
+ /* should only return true for regions that include buttons, for now
+ * return true always */
+ if (drag->type == WM_DRAG_COLOR) {
+ SpaceImage *sima = CTX_wm_space_image(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ if (UI_but_active_drop_color(C))
+ return 1;
+
+ if (sima && (sima->mode == SI_MODE_PAINT) &&
+ sima->image && (ar && ar->regiontype == RGN_TYPE_WINDOW))
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+void UI_drop_color_copy(wmDrag *drag, wmDropBox *drop)
+{
+ uiDragColorHandle *drag_info = (uiDragColorHandle *)drag->poin;
+
+ RNA_float_set_array(drop->ptr, "color", drag_info->color);
+ RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected);
+}
+
+static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ ARegion *ar = CTX_wm_region(C);
+ uiBut *but = NULL;
+ float color[4];
+ bool gamma;
+
+ RNA_float_get_array(op->ptr, "color", color);
+ gamma = RNA_boolean_get(op->ptr, "gamma");
+
+ /* find button under mouse, check if it has RNA color property and
+ * if it does copy the data */
+ but = ui_but_find_activated(ar);
+
+ if (but && but->type == COLOR && but->rnaprop) {
+ const int color_len = RNA_property_array_length(&but->rnapoin, but->rnaprop);
+ BLI_assert(color_len <= 4);
+
+ /* keep alpha channel as-is */
+ if (color_len == 4) {
+ color[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
+ }
+
+ if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+ if (!gamma)
+ ui_block_to_display_space_v3(but->block, color);
+ RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
+ RNA_property_update(C, &but->rnapoin, but->rnaprop);
+ }
+ else if (RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
+ if (gamma)
+ ui_block_to_scene_linear_v3(but->block, color);
+ RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
+ RNA_property_update(C, &but->rnapoin, but->rnaprop);
+ }
+ }
+ else {
+ if (gamma) {
+ srgb_to_linearrgb_v3_v3(color, color);
+ }
+
+ ED_imapaint_bucket_fill(C, color, op);
+ }
+
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_FINISHED;
+}
+
+
+static void UI_OT_drop_color(wmOperatorType *ot)
+{
+ ot->name = "Drop Color";
+ ot->idname = "UI_OT_drop_color";
+ ot->description = "Drop colors to buttons";
+
+ ot->invoke = drop_color_invoke;
+
+ RNA_def_float_color(ot->srna, "color", 3, NULL, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0);
+ RNA_def_boolean(ot->srna, "gamma", 0, "Gamma Corrected", "The source color is gamma corrected ");
+}
+
+
+
/* ********************************************************* */
/* Registration */
@@ -819,7 +940,7 @@ void UI_buttons_operatortypes(void)
WM_operatortype_append(UI_OT_unset_property_button);
WM_operatortype_append(UI_OT_copy_to_selected_button);
WM_operatortype_append(UI_OT_reports_to_textblock); /* XXX: temp? */
-
+ WM_operatortype_append(UI_OT_drop_color);
#ifdef WITH_PYTHON
WM_operatortype_append(UI_OT_editsource);
WM_operatortype_append(UI_OT_edittranslation_init);
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 2ccb3740777..9265ca0d4b9 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -120,7 +120,7 @@ static int panel_aligned(ScrArea *sa, ARegion *ar)
return BUT_VERTICAL;
else if (sa->spacetype == SPACE_IMAGE && ar->regiontype == RGN_TYPE_PREVIEW)
return BUT_VERTICAL;
- else if (ELEM3(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS))
+ else if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS))
return BUT_VERTICAL;
return 0;
@@ -201,20 +201,33 @@ static void ui_panel_copy_offset(Panel *pa, Panel *papar)
pa->ofsy = papar->ofsy + papar->sizey - pa->sizey;
}
+
+/* XXX Disabled paneltab handling for now. Old 2.4x feature, *DO NOT* confuse it with new tool tabs in 2.70. ;)
+ * See also T41704.
+ */
+/* #define UI_USE_PANELTAB */
+
Panel *uiPanelFindByType(ARegion *ar, PanelType *pt)
{
Panel *pa;
-
const char *idname = pt->idname;
- const char *tabname = pt->idname;
+#ifdef UI_USE_PANELTAB
+ const char *tabname = pt->idname;
for (pa = ar->panels.first; pa; pa = pa->next) {
if (STREQLEN(pa->panelname, idname, sizeof(pa->panelname))) {
- if (STREQLEN(pa->tabname, tabname, sizeof(pa->panelname))) {
+ if (STREQLEN(pa->tabname, tabname, sizeof(pa->tabname))) {
return pa;
}
}
}
+#else
+ for (pa = ar->panels.first; pa; pa = pa->next) {
+ if (STREQLEN(pa->panelname, idname, sizeof(pa->panelname))) {
+ return pa;
+ }
+ }
+#endif
return NULL;
}
@@ -224,11 +237,13 @@ Panel *uiPanelFindByType(ARegion *ar, PanelType *pt)
*/
Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Panel *pa, bool *r_open)
{
- Panel *patab, *palast, *panext;
+ Panel *palast, *panext;
const char *drawname = CTX_IFACE_(pt->translation_context, pt->label);
const char *idname = pt->idname;
+#ifdef UI_USE_PANELTAB
const char *tabname = pt->idname;
const char *hookname = NULL;
+#endif
const bool newpanel = (pa == NULL);
int align = panel_aligned(sa, ar);
@@ -240,7 +255,6 @@ Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Pan
pa = MEM_callocN(sizeof(Panel), "new panel");
pa->type = pt;
BLI_strncpy(pa->panelname, idname, sizeof(pa->panelname));
- BLI_strncpy(pa->tabname, tabname, sizeof(pa->tabname));
if (pt->flag & PNL_DEFAULT_CLOSED) {
if (align == BUT_VERTICAL)
@@ -256,9 +270,13 @@ Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Pan
pa->runtime_flag |= PNL_NEW_ADDED;
BLI_addtail(&ar->panels, pa);
-
+
+#ifdef UI_USE_PANELTAB
+ BLI_strncpy(pa->tabname, tabname, sizeof(pa->tabname));
+
/* make new Panel tabbed? */
if (hookname) {
+ Panel *patab;
for (patab = ar->panels.first; patab; patab = patab->next) {
if ((patab->runtime_flag & PNL_ACTIVE) && patab->paneltab == NULL) {
if (STREQLEN(hookname, patab->panelname, sizeof(patab->panelname))) {
@@ -271,6 +289,9 @@ Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Pan
}
}
}
+#else
+ BLI_strncpy(pa->tabname, idname, sizeof(pa->tabname));
+#endif
}
/* Do not allow closed panels without headers! Else user could get "disappeared" UI! */
@@ -462,31 +483,41 @@ static void ui_draw_panel_scalewidget(const rcti *rect)
fdrawline(xmin + dx, ymin + 1, xmax, ymax - dy + 1);
glDisable(GL_BLEND);
}
-
static void ui_draw_panel_dragwidget(const rctf *rect)
{
- float xmin, xmax, dx;
- float ymin, ymax, dy;
-
- xmin = rect->xmin;
- xmax = rect->xmax;
- ymin = rect->ymin;
- ymax = rect->ymax;
-
- dx = (xmax - xmin) / 3.0f;
- dy = (ymax - ymin) / 3.0f;
-
- glEnable(GL_BLEND);
- glColor4ub(255, 255, 255, 50);
- fdrawline(xmin, ymax, xmax, ymin);
- fdrawline(xmin + dx, ymax, xmax, ymin + dy);
- fdrawline(xmin + 2 * dx, ymax, xmax, ymin + 2 * dy);
-
- glColor4ub(0, 0, 0, 50);
- fdrawline(xmin, ymax + 1, xmax, ymin + 1);
- fdrawline(xmin + dx, ymax + 1, xmax, ymin + dy + 1);
- fdrawline(xmin + 2 * dx, ymax + 1, xmax, ymin + 2 * dy + 1);
- glDisable(GL_BLEND);
+ unsigned char col_back[3], col_high[3], col_dark[3];
+ const int col_tint = 84;
+
+ const int px = (int)U.pixelsize;
+ const int px_zoom = max_ii(iroundf(BLI_rctf_size_y(rect) / 22.0f), 1);
+
+ const int box_margin = max_ii(iroundf((float)(px_zoom * 2.0f)), px);
+ const int box_size = max_ii(iroundf((BLI_rctf_size_y(rect) / 8.0f) - px), px);
+
+ const int x_min = rect->xmin;
+ const int y_min = rect->ymin;
+ const int y_ofs = max_ii(iroundf(BLI_rctf_size_y(rect) / 3.0f), px);
+ const int x_ofs = y_ofs;
+ int i_x, i_y;
+
+
+ UI_GetThemeColor3ubv(UI_GetThemeValue(TH_PANEL_SHOW_HEADER) ? TH_PANEL_HEADER : TH_PANEL_BACK, col_back);
+ UI_GetColorPtrShade3ubv(col_back, col_high, col_tint);
+ UI_GetColorPtrShade3ubv(col_back, col_dark, -col_tint);
+
+
+ /* draw multiple boxes */
+ for (i_x = 0; i_x < 4; i_x++) {
+ for (i_y = 0; i_y < 2; i_y++) {
+ const int x_co = (x_min + x_ofs) + (i_x * (box_size + box_margin));
+ const int y_co = (y_min + y_ofs) + (i_y * (box_size + box_margin));
+
+ glColor3ubv(col_dark);
+ glRectf(x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom);
+ glColor3ubv(col_high);
+ glRectf(x_co - box_size, y_co, x_co, y_co + box_size);
+ }
+ }
}
@@ -1131,7 +1162,7 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in
button = 1;
else if (event == AKEY)
button = 1;
- else if (ELEM3(event, 0, RETKEY, LEFTMOUSE) && shift) {
+ else if (ELEM(event, 0, RETKEY, LEFTMOUSE) && shift) {
block->panel->flag ^= PNL_PIN;
button = 2;
}
@@ -1524,6 +1555,12 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
const bool is_active = STREQ(category_id, category_id_active);
+#ifdef DEBUG
+ if (STREQ(category_id, PNL_CATEGORY_FALLBACK)) {
+ printf("WARNING: Panel has no 'bl_category', script needs updating!\n");
+ }
+#endif
+
glEnable(GL_BLEND);
#ifdef USE_FLAT_INACTIVE
@@ -1716,7 +1753,7 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
/* XXX hardcoded key warning */
if ((inside || inside_header) && event->val == KM_PRESS) {
- if (event->type == AKEY && !ELEM4(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift, event->alt)) {
+ if (event->type == AKEY && !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift, event->alt)) {
if (pa->flag & PNL_CLOSEDY) {
if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my))
@@ -1902,7 +1939,7 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
data = MEM_callocN(sizeof(uiHandlePanelData), "uiHandlePanelData");
pa->activedata = data;
- WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa);
+ WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, false);
}
if (ELEM(state, PANEL_STATE_ANIMATION, PANEL_STATE_DRAG))
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index c32f0de937e..1960c77bc95 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -43,6 +43,8 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#include "PIL_time.h"
+
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_report.h"
@@ -392,7 +394,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
data->totline++;
}
- if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
/* better not show the value of a password */
if ((but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD)) == 0) {
/* full string */
@@ -1163,8 +1165,9 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
/* widget rect, in region coords */
data->bbox.xmin = width;
data->bbox.xmax = BLI_rcti_size_x(&ar->winrct) - width;
- data->bbox.ymin = width;
- data->bbox.ymax = BLI_rcti_size_y(&ar->winrct) - width;
+ /* Do not use shadow width for height, gives insane margin with big shadows, and issue T41548 with small ones */
+ data->bbox.ymin = 8 * UI_DPI_FAC;
+ data->bbox.ymax = BLI_rcti_size_y(&ar->winrct) - 8 * UI_DPI_FAC;
/* check if button is lower half */
if (but->rect.ymax < BLI_rctf_cent_y(&but->block->rect)) {
@@ -1704,18 +1707,69 @@ uiBlock *ui_popup_block_refresh(
BLI_addhead(&block->saferct, saferct);
}
- /* clip block with window boundary */
- ui_popup_block_clip(window, block);
-
- /* the block and buttons were positioned in window space as in 2.4x, now
- * these menu blocks are regions so we bring it back to region space.
- * additionally we add some padding for the menu shadow or rounded menus */
- ar->winrct.xmin = block->rect.xmin - width;
- ar->winrct.xmax = block->rect.xmax + width;
- ar->winrct.ymin = block->rect.ymin - width;
- ar->winrct.ymax = block->rect.ymax + MENU_TOP;
-
- ui_block_translate(block, -ar->winrct.xmin, -ar->winrct.ymin);
+ if (block->flag & UI_BLOCK_RADIAL) {
+ uiBut *but;
+ int win_width = UI_SCREEN_MARGIN;
+ int winx, winy;
+
+ int x_offset = 0, y_offset = 0;
+
+ winx = WM_window_pixels_x(window);
+ winy = WM_window_pixels_y(window);
+
+ copy_v2_v2(block->pie_data.pie_center_init, block->pie_data.pie_center_spawned);
+
+ /* only try translation if area is large enough */
+ if (BLI_rctf_size_x(&block->rect) < winx - (2.0f * win_width)) {
+ if (block->rect.xmin < win_width ) x_offset += win_width - block->rect.xmin;
+ if (block->rect.xmax > winx - win_width) x_offset += winx - win_width - block->rect.xmax;
+ }
+
+ if (BLI_rctf_size_y(&block->rect) < winy - (2.0f * win_width)) {
+ if (block->rect.ymin < win_width ) y_offset += win_width - block->rect.ymin;
+ if (block->rect.ymax > winy - win_width) y_offset += winy - win_width - block->rect.ymax;
+ }
+ /* if we are offsetting set up initial data for timeout functionality */
+
+ if ((x_offset != 0) || (y_offset != 0)) {
+ block->pie_data.pie_center_spawned[0] += x_offset;
+ block->pie_data.pie_center_spawned[1] += y_offset;
+
+ ui_block_translate(block, x_offset, y_offset);
+
+ if (U.pie_initial_timeout > 0)
+ block->pie_data.flags |= UI_PIE_INITIAL_DIRECTION;
+ }
+
+ ar->winrct.xmin = 0;
+ ar->winrct.xmax = winx;
+ ar->winrct.ymin = 0;
+ ar->winrct.ymax = winy;
+
+ ui_block_calculate_pie_segment(block, block->pie_data.pie_center_init);
+
+ /* lastly set the buttons at the center of the pie menu, ready for animation */
+ if (U.pie_animation_timeout > 0) {
+ for (but = block->buttons.first; but; but = but->next) {
+ if (but->pie_dir != UI_RADIAL_NONE) {
+ BLI_rctf_recenter(&but->rect, UNPACK2(block->pie_data.pie_center_spawned));
+ }
+ }
+ }
+ }
+ else {
+ /* clip block with window boundary */
+ ui_popup_block_clip(window, block);
+ /* the block and buttons were positioned in window space as in 2.4x, now
+ * these menu blocks are regions so we bring it back to region space.
+ * additionally we add some padding for the menu shadow or rounded menus */
+ ar->winrct.xmin = block->rect.xmin - width;
+ ar->winrct.xmax = block->rect.xmax + width;
+ ar->winrct.ymin = block->rect.ymin - width;
+ ar->winrct.ymax = block->rect.ymax + MENU_TOP;
+
+ ui_block_translate(block, -ar->winrct.xmin, -ar->winrct.ymin);
+ }
if (block_old) {
block->oldblock = block_old;
@@ -1872,7 +1926,7 @@ static void ui_update_block_buts_rgb(uiBlock *block, const float rgb[3], bool is
if (rgb_gamma[2] > 1.0f) rgb_gamma[2] = modf(rgb_gamma[2], &intpart);
rgb_float_to_uchar(rgb_gamma_uchar, rgb_gamma);
- BLI_snprintf(col, sizeof(col), "%02X%02X%02X", UNPACK3OP((unsigned int), rgb_gamma_uchar));
+ BLI_snprintf(col, sizeof(col), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, ));
strcpy(bt->poin, col);
}
@@ -2160,7 +2214,7 @@ static void uiBlockPicker(uiBlock *block, float rgba[4], PointerRNA *ptr, Proper
}
rgb_float_to_uchar(rgb_gamma_uchar, rgb_gamma);
- BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3OP((unsigned int), rgb_gamma_uchar));
+ BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, ));
yco = -3.0f * UI_UNIT_Y;
bt = uiDefBut(block, TEX, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 8, 0, 0, TIP_("Hex triplet for color (#RRGGBB)"));
@@ -2353,6 +2407,12 @@ struct uiPopupMenu {
void *menu_arg;
};
+struct uiPieMenu {
+ uiBlock *block_radial; /* radial block of the pie menu (more could be added later) */
+ uiLayout *layout;
+ int mx, my;
+};
+
static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, void *arg_pup)
{
uiBlock *block;
@@ -2408,6 +2468,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT);
if (pup->popup) {
+ uiBut *but_activate = NULL;
uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_NUMSELECT);
uiBlockSetDirection(block, direction);
@@ -2421,6 +2482,10 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
* block to be under the mouse */
offset[0] = -(bt->rect.xmin + 0.8f * BLI_rctf_size_x(&bt->rect));
offset[1] = -(bt->rect.ymin + 0.5f * UI_UNIT_Y);
+
+ if (ui_but_is_editable(bt)) {
+ but_activate = bt;
+ }
}
else {
/* position mouse at 0.8*width of the button and below the tile
@@ -2430,6 +2495,20 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
offset[0] = min_ii(offset[0], -(bt->rect.xmin + 0.8f * BLI_rctf_size_x(&bt->rect)));
offset[1] = 2.1 * UI_UNIT_Y;
+
+ for (bt = block->buttons.first; bt; bt = bt->next) {
+ if (ui_but_is_editable(bt)) {
+ but_activate = bt;
+ break;
+ }
+ }
+ }
+
+ /* in rare cases this is needed since moving the popup
+ * to be within the window bounds may move it away from the mouse,
+ * This ensures we set an item to be active. */
+ if (but_activate) {
+ ui_button_activate_over(C, handle->region, but_activate);
}
block->minbounds = minwidth;
@@ -2507,7 +2586,7 @@ uiPopupBlockHandle *ui_popup_menu_create(bContext *C, ARegion *butregion, uiBut
if (!but) {
handle->popup = true;
- UI_add_popup_handlers(C, &window->modalhandlers, handle);
+ UI_add_popup_handlers(C, &window->modalhandlers, handle, false);
WM_event_add_mousemove(C);
}
@@ -2569,7 +2648,7 @@ void uiPupMenuEnd(bContext *C, uiPopupMenu *pup)
menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPUP, pup);
menu->popup = true;
- UI_add_popup_handlers(C, &window->modalhandlers, menu);
+ UI_add_popup_handlers(C, &window->modalhandlers, menu, false);
WM_event_add_mousemove(C);
MEM_freeN(pup);
@@ -2580,6 +2659,178 @@ uiLayout *uiPupMenuLayout(uiPopupMenu *pup)
return pup->layout;
}
+/*************************** Pie Menus ***************************************/
+
+static uiBlock *ui_block_func_PIE(bContext *UNUSED(C), uiPopupBlockHandle *handle, void *arg_pie)
+{
+ uiBlock *block;
+ uiPieMenu *pie = arg_pie;
+ int minwidth, width, height;
+
+ minwidth = 50;
+ block = pie->block_radial;
+
+ /* in some cases we create the block before the region,
+ * so we set it delayed here if necessary */
+ if (BLI_findindex(&handle->region->uiblocks, block) == -1)
+ uiBlockSetRegion(block, handle->region);
+
+ uiBlockLayoutResolve(block, &width, &height);
+
+ uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_NUMSELECT);
+
+ block->minbounds = minwidth;
+ block->bounds = 1;
+ block->mx = 0;
+ block->my = 0;
+ block->bounds_type = UI_BLOCK_BOUNDS_PIE_CENTER;
+
+ block->pie_data.pie_center_spawned[0] = pie->mx;
+ block->pie_data.pie_center_spawned[1] = pie->my;
+
+ return pie->block_radial;
+}
+
+static float uiPieTitleWidth(const char *name, int icon)
+{
+ return (UI_GetStringWidth(name) +
+ (UI_UNIT_X * (1.50f + (icon ? 0.25f : 0.0f))));
+}
+
+uiPieMenu *uiPieMenuBegin(struct bContext *C, const char *title, int icon, const wmEvent *event)
+{
+ uiStyle *style = UI_GetStyleDraw();
+ uiPieMenu *pie = MEM_callocN(sizeof(uiPopupMenu), "pie menu");
+
+ pie->block_radial = uiBeginBlock(C, NULL, __func__, UI_EMBOSS);
+ /* may be useful later to allow spawning pies
+ * from old positions */
+ /* pie->block_radial->flag |= UI_BLOCK_POPUP_MEMORY; */
+ pie->block_radial->puphash = ui_popup_menu_hash(title);
+ pie->block_radial->flag |= UI_BLOCK_RADIAL;
+ pie->block_radial->pie_data.event = event->type;
+
+ pie->layout = uiBlockLayout(pie->block_radial, UI_LAYOUT_VERTICAL, UI_LAYOUT_PIEMENU, 0, 0, 200, 0, 0, style);
+ pie->mx = event->x;
+ pie->my = event->y;
+
+ /* create title button */
+ if (title[0]) {
+ uiBut *but;
+ char titlestr[256];
+ int w;
+ if (icon) {
+ BLI_snprintf(titlestr, sizeof(titlestr), " %s", title);
+ w = uiPieTitleWidth(titlestr, icon);
+ but = uiDefIconTextBut(pie->block_radial, LABEL, 0, icon, titlestr, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ }
+ else {
+ w = uiPieTitleWidth(title, 0);
+ but = uiDefBut(pie->block_radial, LABEL, 0, title, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ }
+ /* do not align left */
+ but->drawflag &= ~UI_BUT_TEXT_LEFT;
+ }
+
+ return pie;
+}
+
+void uiPieMenuEnd(bContext *C, uiPieMenu *pie)
+{
+ wmWindow *window = CTX_wm_window(C);
+ uiPopupBlockHandle *menu;
+
+ menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_PIE, pie);
+ menu->popup = true;
+ menu->towardstime = PIL_check_seconds_timer();
+
+ UI_add_popup_handlers(C, &window->modalhandlers, menu, true);
+ WM_event_add_mousemove(C);
+
+ MEM_freeN(pie);
+}
+
+uiLayout *uiPieMenuLayout(uiPieMenu *pie)
+{
+ return pie->layout;
+}
+
+void uiPieMenuInvoke(struct bContext *C, const char *idname, const wmEvent *event)
+{
+ uiPieMenu *pie;
+ uiLayout *layout;
+ Menu menu;
+ MenuType *mt = WM_menutype_find(idname, true);
+
+ if (mt == NULL) {
+ printf("%s: named menu \"%s\" not found\n", __func__, idname);
+ return;
+ }
+
+ if (mt->poll && mt->poll(C, mt) == 0)
+ return;
+
+ pie = uiPieMenuBegin(C, IFACE_(mt->label), ICON_NONE, event);
+ layout = uiPieMenuLayout(pie);
+
+ menu.layout = layout;
+ menu.type = mt;
+
+ if (G.debug & G_DEBUG_WM) {
+ printf("%s: opening menu \"%s\"\n", __func__, idname);
+ }
+
+ mt->draw(C, &menu);
+
+ uiPieMenuEnd(C, pie);
+}
+
+void uiPieOperatorEnumInvoke(struct bContext *C, const char *title, const char *opname,
+ const char *propname, const wmEvent *event)
+{
+ uiPieMenu *pie;
+ uiLayout *layout;
+
+ pie = uiPieMenuBegin(C, IFACE_(title), ICON_NONE, event);
+ layout = uiPieMenuLayout(pie);
+
+ layout = uiLayoutRadial(layout);
+ uiItemsEnumO(layout, opname, propname);
+
+ uiPieMenuEnd(C, pie);
+}
+
+void uiPieEnumInvoke(struct bContext *C, const char *title, const char *path,
+ const wmEvent *event)
+{
+ PointerRNA ctx_ptr;
+ PointerRNA r_ptr;
+ PropertyRNA *r_prop;
+ uiPieMenu *pie;
+ uiLayout *layout;
+
+ RNA_pointer_create(NULL, &RNA_Context, C, &ctx_ptr);
+
+ if (!RNA_path_resolve(&ctx_ptr, path, &r_ptr, &r_prop)) {
+ return;
+ }
+
+ /* invalid property, only accept enums */
+ if (RNA_property_type(r_prop) != PROP_ENUM) {
+ BLI_assert(0);
+ return;
+ }
+
+ pie = uiPieMenuBegin(C, IFACE_(title), ICON_NONE, event);
+ layout = uiPieMenuLayout(pie);
+
+ layout = uiLayoutRadial(layout);
+ uiItemFullR(layout, &r_ptr, r_prop, RNA_NO_INDEX, 0, UI_ITEM_R_EXPAND, NULL, 0);
+
+ uiPieMenuEnd(C, pie);
+}
+
+
/*************************** Standard Popup Menus ****************************/
void uiPupMenuReports(bContext *C, ReportList *reports)
@@ -2676,7 +2927,7 @@ void uiPupBlockO(bContext *C, uiBlockCreateFunc func, void *arg, const char *opn
handle->optype = (opname) ? WM_operatortype_find(opname, 0) : NULL;
handle->opcontext = opcontext;
- UI_add_popup_handlers(C, &window->modalhandlers, handle);
+ UI_add_popup_handlers(C, &window->modalhandlers, handle, false);
WM_event_add_mousemove(C);
}
@@ -2699,7 +2950,7 @@ void uiPupBlockEx(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_f
handle->cancel_func = cancel_func;
// handle->opcontext = opcontext;
- UI_add_popup_handlers(C, &window->modalhandlers, handle);
+ UI_add_popup_handlers(C, &window->modalhandlers, handle, false);
WM_event_add_mousemove(C);
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 243aa452f17..364a62bd2a0 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -36,6 +36,8 @@
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
+#include "DNA_brush_types.h"
+#include "DNA_texture_types.h"
#include "BLI_utildefines.h"
#include "BLI_string.h"
@@ -60,6 +62,7 @@
#include "BKE_object.h"
#include "BKE_packedFile.h"
#include "BKE_particle.h"
+#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_sca.h"
#include "BKE_screen.h"
@@ -349,6 +352,8 @@ static const char *template_id_browse_tip(StructRNA *type)
case ID_BR: return N_("Browse Brush to be linked");
case ID_PA: return N_("Browse Particle Settings to be linked");
case ID_GD: return N_("Browse Grease Pencil Data to be linked");
+ case ID_PAL: return N_("Browse Palette Data to be linked");
+ case ID_PC: return N_("Browse Paint Curve Data to be linked");
}
}
return N_("Browse ID data to be linked");
@@ -489,7 +494,7 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
if (user_alert) uiButSetFlag(but, UI_BUT_REDALERT);
- if (id->lib == NULL && !(ELEM5(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) {
+ if (id->lib == NULL && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) {
uiDefButR(block, TOG, 0, "F", 0, 0, UI_UNIT_X, UI_UNIT_Y, &idptr, "use_fake_user", -1, 0, 0, -1, -1, NULL);
}
}
@@ -571,24 +576,33 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
/* delete button */
/* don't use RNA_property_is_unlink here */
- if (id && (flag & UI_ID_DELETE) && (RNA_property_flag(template->prop) & PROP_NEVER_UNLINK) == 0) {
+ if (id && (flag & UI_ID_DELETE)) {
+ /* allow unlink if 'unlinkop' is passed, even when 'PROP_NEVER_UNLINK' is set */
+ but = NULL;
+
if (unlinkop) {
but = uiDefIconButO(block, BUT, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
/* so we can access the template from operators, font unlinking needs this */
uiButSetNFunc(but, NULL, MEM_dupallocN(template), NULL);
}
else {
- but = uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0,
- TIP_("Unlink datablock "
- "(Shift + Click to set users to zero, data will then not be saved)"));
- uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
+ if ((RNA_property_flag(template->prop) & PROP_NEVER_UNLINK) == 0) {
+ but = uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0,
+ TIP_("Unlink datablock "
+ "(Shift + Click to set users to zero, data will then not be saved)"));
+ uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
- if (RNA_property_flag(template->prop) & PROP_NEVER_NULL)
- uiButSetFlag(but, UI_BUT_DISABLED);
+ if (RNA_property_flag(template->prop) & PROP_NEVER_NULL) {
+ uiButSetFlag(but, UI_BUT_DISABLED);
+ }
+ }
}
- if ((idfrom && idfrom->lib) || !editable)
- uiButSetFlag(but, UI_BUT_DISABLED);
+ if (but) {
+ if ((idfrom && idfrom->lib) || !editable) {
+ uiButSetFlag(but, UI_BUT_DISABLED);
+ }
+ }
}
if (idcode == ID_TE)
@@ -751,28 +765,6 @@ void uiTemplatePathBuilder(uiLayout *layout, PointerRNA *ptr, const char *propna
#define ERROR_LIBDATA_MESSAGE IFACE_("Can't edit external libdata")
-static void modifiers_setOnCage(bContext *C, void *ob_v, void *md_v)
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob = ob_v;
- ModifierData *md = md_v;
- int i, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 0);
-
- /* undo button operation */
- md->mode ^= eModifierMode_OnCage;
-
- for (i = 0, md = ob->modifiers.first; md; ++i, md = md->next) {
- if (md == md_v) {
- if (i >= cageIndex)
- md->mode ^= eModifierMode_OnCage;
- break;
- }
- }
-
- WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-}
-
static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
{
Object *ob = ob_v;
@@ -808,7 +800,7 @@ static int modifier_can_delete(ModifierData *md)
static int modifier_is_simulation(ModifierData *md)
{
/* Physic Tab */
- if (ELEM7(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke,
+ if (ELEM(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke,
eModifierType_Softbody, eModifierType_Surface, eModifierType_DynamicPaint))
{
return 1;
@@ -829,7 +821,7 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
PointerRNA ptr;
uiBut *but;
uiBlock *block;
- uiLayout *box, *column, *row;
+ uiLayout *box, *column, *row, *sub;
uiLayout *result = NULL;
int isVirtual = (md->mode & eModifierMode_Virtual);
char str[128];
@@ -870,7 +862,11 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
uiBlockSetEmboss(block, UI_EMBOSS);
/* modifier name */
+ if (mti->isDisabled && mti->isDisabled(md, 0)) {
+ uiLayoutSetRedAlert(row, true);
+ }
uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
+ uiLayoutSetRedAlert(row, false);
/* mode enabling buttons */
uiBlockBeginAlign(block);
@@ -881,39 +877,32 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE);
uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE);
- if (mti->flags & eModifierTypeFlag_SupportsEditmode)
- uiItemR(row, &ptr, "show_in_editmode", 0, "", ICON_NONE);
+ if (mti->flags & eModifierTypeFlag_SupportsEditmode) {
+ sub = uiLayoutRow(row, true);
+ if (!(md->mode & eModifierMode_Realtime)) {
+ uiLayoutSetActive(sub, false);
+ }
+ uiItemR(sub, &ptr, "show_in_editmode", 0, "", ICON_NONE);
+ }
}
if (ob->type == OB_MESH) {
- if (modifier_couldBeCage(scene, md) && (index <= lastCageIndex)) {
- /* -- convert to rna ? */
- but = uiDefIconButBitI(block, TOG, eModifierMode_OnCage, 0, ICON_MESH_DATA, 0, 0,
- UI_UNIT_X - 2, UI_UNIT_Y, &md->mode, 0.0, 0.0, 0.0, 0.0,
- TIP_("Apply modifier to editing cage during Edit mode"));
- if (index < cageIndex)
- uiButSetFlag(but, UI_BUT_DISABLED);
- uiButSetFunc(but, modifiers_setOnCage, ob, md);
- }
- else if (modifier_supportsCage(scene, md) && (index <= lastCageIndex)) {
- uiBlockEndAlign(block);
-
- /* place holder button */
- uiBlockSetEmboss(block, UI_EMBOSSN);
- but = uiDefIconBut(block, BUT, 0, ICON_NONE, 0, 0, UI_UNIT_X - 2, UI_UNIT_Y,
- NULL, 0.0, 0.0, 0.0, 0.0, NULL);
- uiButSetFlag(but, UI_BUT_DISABLED);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ if (modifier_supportsCage(scene, md) && (index <= lastCageIndex)) {
+ sub = uiLayoutRow(row, true);
+ if (index < cageIndex || !modifier_couldBeCage(scene, md)) {
+ uiLayoutSetActive(sub, false);
+ }
+ uiItemR(sub, &ptr, "show_on_cage", 0, "", ICON_NONE);
}
} /* tessellation point for curve-typed objects */
- else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
/* some modifiers could work with pre-tessellated curves only */
- if (ELEM3(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
+ if (ELEM(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
/* add disabled pre-tessellated button, so users could have
* message for this modifiers */
but = uiDefIconButBitI(block, TOG, eModifierMode_ApplyOnSpline, 0, ICON_SURFACE_DATA, 0, 0,
UI_UNIT_X - 2, UI_UNIT_Y, &md->mode, 0.0, 0.0, 0.0, 0.0,
- TIP_("This modifier could be applied on splines' points only"));
+ TIP_("This modifier can only be applied on splines' points"));
uiButSetFlag(but, UI_BUT_DISABLED);
}
else if (mti->type != eModifierTypeType_Constructive) {
@@ -979,7 +968,7 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
uiBlockClearButLock(block);
uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
- if (!ELEM5(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem,
+ if (!ELEM(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem,
eModifierType_Cloth, eModifierType_Smoke))
{
uiItemO(row, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"), ICON_NONE,
@@ -1298,7 +1287,7 @@ void uiTemplatePreview(uiLayout *layout, bContext *C, ID *id, int show_buttons,
char _preview_id[UI_MAX_NAME_STR];
- if (id && !ELEM5(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA, ID_LS)) {
+ if (id && !ELEM(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA, ID_LS)) {
RNA_warning("Expected ID of type material, texture, lamp, world or line style");
return;
}
@@ -1525,7 +1514,15 @@ static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand
row = uiLayoutRow(split, false);
- uiItemR(row, &ptr, "interpolation", 0, "", ICON_NONE);
+ uiBlockBeginAlign(block);
+ uiItemR(row, &ptr, "color_mode", 0, "", ICON_NONE);
+ if (ELEM(coba->color_mode, COLBAND_BLEND_HSV, COLBAND_BLEND_HSL)) {
+ uiItemR(row, &ptr, "hue_interpolation", 0, "", ICON_NONE);
+ }
+ else { /* COLBAND_BLEND_RGB */
+ uiItemR(row, &ptr, "interpolation", 0, "", ICON_NONE);
+ }
+ uiBlockEndAlign(block);
row = uiLayoutRow(layout, false);
@@ -1563,7 +1560,7 @@ static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand
uiDefButS(block, NUM, 0, "", 0, 0, 5.0f * UI_UNIT_X, UI_UNIT_Y, &coba->cur, 0.0, (float)(MAX2(0, coba->tot - 1)),
0, 0, TIP_("Choose active color stop"));
row = uiLayoutRow(subsplit, false);
- uiItemR(row, &ptr, "position", 0, IFACE_("Pos"), ICON_NONE);
+ uiItemR(row, &ptr, "position", UI_ITEM_R_SLIDER, IFACE_("Pos"), ICON_NONE);
bt = block->buttons.last;
uiButSetFunc(bt, colorband_update_cb, bt, coba);
@@ -2363,6 +2360,61 @@ void uiTemplateColorPicker(uiLayout *layout, PointerRNA *ptr, const char *propna
}
}
+void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname, int UNUSED(colors))
+{
+ PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
+ PointerRNA cptr;
+ Palette *palette;
+ PaletteColor *color;
+ uiBlock *block;
+ uiLayout *col;
+ int row_cols = 0, col_id = 0;
+ int cols_per_row = MAX2(uiLayoutGetWidth(layout) / UI_UNIT_X, 1);
+
+ if (!prop) {
+ RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+
+ cptr = RNA_property_pointer_get(ptr, prop);
+ if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Palette))
+ return;
+
+ block = uiLayoutGetBlock(layout);
+
+ palette = cptr.data;
+
+ /* first delete any pending colors */
+ BKE_palette_cleanup(palette);
+
+ color = palette->colors.first;
+
+ col = uiLayoutColumn(layout, true);
+ uiLayoutRow(col, true);
+ uiDefIconButO(block, BUT, "PALETTE_OT_color_add", WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+ uiDefIconButO(block, BUT, "PALETTE_OT_color_delete", WM_OP_INVOKE_DEFAULT, ICON_ZOOMOUT, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+
+ col = uiLayoutColumn(layout, true);
+ uiLayoutRow(col, true);
+
+ for (; color; color = color->next) {
+ PointerRNA ptr;
+
+ if (row_cols >= cols_per_row) {
+ uiLayoutRow(col, true);
+ row_cols = 0;
+ }
+
+ RNA_pointer_create(&palette->id, &RNA_PaletteColor, color, &ptr);
+ uiDefButR(block, COLOR, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, &ptr, "color", -1, 0.0, 1.0,
+ UI_PALETTE_COLOR, (col_id == palette->active_color) ? UI_PALETTE_COLOR_ACTIVE : 0.0, "");
+
+ row_cols++;
+ col_id++;
+ }
+}
+
+
/********************* Layer Buttons Template ************************/
static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
@@ -2593,8 +2645,8 @@ static void uilist_filter_items_default(struct uiList *ui_list, struct bContext
const char *filter_raw = ui_list->filter_byname;
char *filter = (char *)filter_raw, filter_buff[32], *filter_dyn = NULL;
- bool filter_exclude = (ui_list->filter_flag & UILST_FLT_EXCLUDE) != 0;
- bool order_by_name = (ui_list->filter_sort_flag & UILST_FLT_SORT_ALPHA) != 0;
+ const bool filter_exclude = (ui_list->filter_flag & UILST_FLT_EXCLUDE) != 0;
+ const bool order_by_name = (ui_list->filter_sort_flag & UILST_FLT_SORT_ALPHA) != 0;
int len = RNA_property_collection_length(dataptr, prop);
dyn_data->items_shown = dyn_data->items_len = len;
@@ -2903,8 +2955,8 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
/* Filter list items! (not for compact layout, though) */
if (dataptr->data && prop) {
- int filter_exclude = ui_list->filter_flag & UILST_FLT_EXCLUDE;
- bool order_reverse = (ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) != 0;
+ const int filter_exclude = ui_list->filter_flag & UILST_FLT_EXCLUDE;
+ const bool order_reverse = (ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) != 0;
int items_shown, idx = 0;
#if 0
int prev_ii = -1, prev_i;
@@ -3188,7 +3240,7 @@ static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2)
wmOperatorType *ot = arg2;
if (ot)
- WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, NULL);
}
static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
@@ -3443,13 +3495,9 @@ static void template_keymap_item_properties(uiLayout *layout, const char *title,
RNA_STRUCT_BEGIN (ptr, prop)
{
- int flag = RNA_property_flag(prop);
- bool is_set = RNA_property_is_set(ptr, prop);
+ const bool is_set = RNA_property_is_set(ptr, prop);
uiBut *but;
- if (flag & PROP_HIDDEN)
- continue;
-
/* recurse for nested properties */
if (RNA_property_type(prop) == PROP_POINTER) {
PointerRNA propptr = RNA_property_pointer_get(ptr, prop);
@@ -3543,7 +3591,7 @@ void uiTemplateColormanagedViewSettings(uiLayout *layout, bContext *UNUSED(C), P
col = uiLayoutColumn(layout, false);
row = uiLayoutRow(col, false);
- uiItemR(row, &view_transform_ptr, "view_transform", UI_ITEM_R_EXPAND, IFACE_("View"), ICON_NONE);
+ uiItemR(row, &view_transform_ptr, "view_transform", 0, IFACE_("View"), ICON_NONE);
col = uiLayoutColumn(layout, false);
uiItemR(col, &view_transform_ptr, "exposure", 0, NULL, ICON_NONE);
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 744ed7e5b72..008ea84b607 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -151,7 +151,7 @@ int uiDefAutoButsRNA(uiLayout *layout, PointerRNA *ptr,
const char *name;
int tot = 0;
- assert(ELEM3(label_align, '\0', 'H', 'V'));
+ assert(ELEM(label_align, '\0', 'H', 'V'));
RNA_STRUCT_BEGIN (ptr, prop)
{
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 1a614bc7012..6d497fa474c 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -33,6 +33,7 @@
#include <string.h>
#include <assert.h>
+#include "DNA_brush_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
@@ -845,7 +846,7 @@ static void widget_draw_icon(const uiBut *but, BIFIconID icon, float alpha, cons
height = ICON_DEFAULT_HEIGHT / aspect;
/* calculate blend color */
- if (ELEM4(but->type, TOG, ROW, TOGN, LISTROW)) {
+ if (ELEM(but->type, TOG, ROW, TOGN, LISTROW)) {
if (but->flag & UI_SELECT) {}
else if (but->flag & UI_ACTIVE) {}
else alpha = 0.5f;
@@ -918,45 +919,12 @@ static void ui_text_clip_give_next_off(uiBut *but, const char *str)
but->ofs += bytes;
}
-/**
- * Cut off the start of the text to fit into the width of \a rect
- *
- * \note Sets but->ofs to make sure text is correctly visible.
- * \note Clips right in some cases, this function could be cleaned up.
- */
-static void ui_text_clip_left(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
-{
- /* We are not supposed to use labels with that clipping, so we can always apply margins. */
- const int border = (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
- const int okwidth = max_ii(BLI_rcti_size_x(rect) - border, 0);
-
- /* need to set this first */
- uiStyleFontSet(fstyle);
-
- if (fstyle->kerning == 1) /* for BLF_width */
- BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
-
- but->ofs = 0;
- but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr, sizeof(but->drawstr));
-
- if ((okwidth > 0.0f) && (but->strwidth > okwidth)) {
- float strwidth;
- but->ofs = BLF_width_to_rstrlen(fstyle->uifont_id, but->drawstr,
- sizeof(but->drawstr), okwidth, &strwidth);
- but->strwidth = strwidth;
- }
-
- if (fstyle->kerning == 1) {
- BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
- }
-}
-
/* Helper.
* This func assumes things like kerning handling have already been handled!
* Return the length of modified (right-clipped + ellipsis) string.
*/
static void ui_text_clip_right_ex(uiFontStyle *fstyle, char *str, const size_t max_len, const float okwidth,
- const char *sep, const int sep_len, const float sep_strwidth)
+ const char *sep, const int sep_len, const float sep_strwidth, size_t *r_final_len)
{
float tmp;
int l_end;
@@ -969,19 +937,27 @@ static void ui_text_clip_right_ex(uiFontStyle *fstyle, char *str, const size_t m
if (sep_strwidth / okwidth > 0.2f) {
l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, &tmp);
str[l_end] = '\0';
+ if (r_final_len) {
+ *r_final_len = (size_t)l_end;
+ }
}
else {
l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth - sep_strwidth, &tmp);
memcpy(str + l_end, sep, sep_len + 1); /* +1 for trailing '\0'. */
+ if (r_final_len) {
+ *r_final_len = (size_t)(l_end + sep_len);
+ }
}
}
/**
* Cut off the middle of the text to fit into the given width.
* Note in case this middle clipping would just remove a few chars, it rather clips right, which is more readable.
+ * If rpart_sep is not Null, the part of str starting to first occurrence of rpart_sep is preserved at all cost (useful
+ * for strings with shortcuts, like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O').
*/
-static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, const float okwidth, const float minwidth,
- const size_t max_len)
+static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, float okwidth, const float minwidth,
+ const size_t max_len, const char *rpart_sep)
{
float strwidth;
@@ -1000,37 +976,76 @@ static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, const float
/* utf8 ellipsis '...', some compilers complain */
const char sep[] = {0xe2, 0x80, 0xa6, 0x0};
const int sep_len = sizeof(sep) - 1;
+ const float sep_strwidth = BLF_width(fstyle->uifont_id, sep, sep_len + 1);
+ float parts_strwidth;
size_t l_end;
- const float sep_strwidth = BLF_width(fstyle->uifont_id, sep, sep_len + 1);
- const float parts_strwidth = ((float)okwidth - sep_strwidth) / 2.0f;
+ char *rpart = NULL, rpart_buf[UI_MAX_DRAW_STR];
+ float rpart_width = 0.0f;
+ size_t rpart_len = 0;
+ size_t final_lpart_len;
+
+ if (rpart_sep) {
+ rpart = strstr(str, rpart_sep);
+
+ if (rpart) {
+ rpart_len = strlen(rpart);
+ rpart_width = BLF_width(fstyle->uifont_id, rpart, rpart_len);
+ okwidth -= rpart_width;
+ strwidth -= rpart_width;
+
+ if (okwidth < 0.0f) {
+ /* Not enough place for actual label, just display protected right part.
+ * Here just for safety, should never happen in real life! */
+ memmove(str, rpart, rpart_len + 1);
+ rpart = NULL;
+ okwidth += rpart_width;
+ strwidth = rpart_width;
+ }
+ }
+ }
+
+ parts_strwidth = (okwidth - sep_strwidth) / 2.0f;
+
+ if (rpart) {
+ strcpy(rpart_buf, rpart);
+ *rpart = '\0';
+ rpart = rpart_buf;
+ }
- if (min_ff(parts_strwidth, strwidth - okwidth) < minwidth) {
+ l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, parts_strwidth, &rpart_width);
+ if (l_end < 10 || min_ff(parts_strwidth, strwidth - okwidth) < minwidth) {
/* If we really have no place, or we would clip a very small piece of string in the middle,
* only show start of string.
*/
- ui_text_clip_right_ex(fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth);
+ ui_text_clip_right_ex(fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth, &final_lpart_len);
}
else {
size_t r_offset, r_len;
- l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, parts_strwidth, &strwidth);
- r_offset = BLF_width_to_rstrlen(fstyle->uifont_id, str, max_len, parts_strwidth, &strwidth);
- r_len = strlen(str + r_offset) + 1; /* +1 for the trailing '\0'... */
+ r_offset = BLF_width_to_rstrlen(fstyle->uifont_id, str, max_len, parts_strwidth, &rpart_width);
+ r_len = strlen(str + r_offset) + 1; /* +1 for the trailing '\0'. */
- if (l_end + sep_len + r_len > max_len) {
+ if (l_end + sep_len + r_len + rpart_len > max_len) {
/* Corner case, the str already takes all available mem, and the ellipsis chars would actually
* add more chars...
* Better to just trim one or two letters to the right in this case...
* Note: with a single-char ellipsis, this should never happen! But better be safe here...
*/
- ui_text_clip_right_ex(fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth);
+ ui_text_clip_right_ex(fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth, &final_lpart_len);
}
else {
memmove(str + l_end + sep_len, str + r_offset, r_len);
memcpy(str + l_end, sep, sep_len);
+ final_lpart_len = (size_t)(l_end + sep_len + r_len - 1); /* -1 to remove trailing '\0'! */
}
}
+
+ if (rpart) {
+ /* Add back preserved right part to our shorten str. */
+ memcpy(str + final_lpart_len, rpart, rpart_len + 1); /* +1 for trailing '\0'. */
+ }
+
strwidth = BLF_width(fstyle->uifont_id, str, max_len);
}
@@ -1041,6 +1056,9 @@ static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, const float
return strwidth;
}
+/**
+ * Wrapper around ui_text_clip_middle_ex.
+ */
static void ui_text_clip_middle(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
{
/* No margin for labels! */
@@ -1050,7 +1068,23 @@ static void ui_text_clip_middle(uiFontStyle *fstyle, uiBut *but, const rcti *rec
const float minwidth = (float)(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f;
but->ofs = 0;
- but->strwidth = ui_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len);
+ but->strwidth = ui_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, NULL);
+}
+
+/**
+ * Like ui_text_clip_middle(), but protect/preserve at all cost the right part of the string after sep.
+ * Useful for strings with shortcuts (like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O').
+ */
+static void ui_text_clip_middle_protect_right(uiFontStyle *fstyle, uiBut *but, const rcti *rect, const char *rsep)
+{
+ /* No margin for labels! */
+ const int border = ELEM(but->type, LABEL, MENU) ? 0 : (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
+ const float okwidth = (float)max_ii(BLI_rcti_size_x(rect) - border, 0);
+ const size_t max_len = sizeof(but->drawstr);
+ const float minwidth = (float)(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f;
+
+ but->ofs = 0;
+ but->strwidth = ui_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, rsep);
}
/**
@@ -1427,14 +1461,9 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
else if (ELEM(but->type, NUM, NUMSLI)) {
ui_text_clip_right_label(fstyle, but, rect);
}
-#if 0
- /* Special hack for non-embossed TEX buttons in uiList (we want them to behave as much as possible as labels). */
- else if ((but->type == TEX) && (but->flag & UI_BUT_LIST_ITEM) && (but->dt & UI_EMBOSSN)) {
- but->ofs = 0;
- }
-#endif
else if ((but->block->flag & UI_BLOCK_LOOP) && (but->type == BUT)) {
- ui_text_clip_left(fstyle, but, rect);
+ /* Clip middle, but protect in all case right part containing the shortcut, if any. */
+ ui_text_clip_middle_protect_right(fstyle, but, rect, "|");
}
else {
ui_text_clip_middle(fstyle, but, rect);
@@ -1592,6 +1621,21 @@ static struct uiWidgetColors wcol_menu_back = {
25, -20
};
+/* pie menus */
+static struct uiWidgetColors wcol_pie_menu = {
+ {10, 10, 10, 200},
+ {25, 25, 25, 230},
+ {140, 140, 140, 255},
+ {45, 45, 45, 230},
+
+ {160, 160, 160, 255},
+ {255, 255, 255, 255},
+
+ 1,
+ 10, -10
+};
+
+
/* tooltip color */
static struct uiWidgetColors wcol_tooltip = {
{0, 0, 0, 255},
@@ -1739,6 +1783,7 @@ void ui_widget_color_init(ThemeUI *tui)
tui->wcol_menu = wcol_menu;
tui->wcol_pulldown = wcol_pulldown;
tui->wcol_menu_back = wcol_menu_back;
+ tui->wcol_pie_menu = wcol_pie_menu;
tui->wcol_tooltip = wcol_tooltip;
tui->wcol_menu_item = wcol_menu_item;
tui->wcol_box = wcol_box;
@@ -1887,6 +1932,34 @@ static void widget_state_pulldown(uiWidgetType *wt, int state)
copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
}
+/* special case, pie menu items */
+static void widget_state_pie_menu_item(uiWidgetType *wt, int state)
+{
+ wt->wcol = *(wt->wcol_theme);
+
+ /* active and disabled (not so common) */
+ if ((state & UI_BUT_DISABLED) && (state & UI_ACTIVE)) {
+ widget_state_blend(wt->wcol.text, wt->wcol.text_sel, 0.5f);
+ /* draw the backdrop at low alpha, helps navigating with keys
+ * when disabled items are active */
+ copy_v4_v4_char(wt->wcol.inner, wt->wcol.item);
+ wt->wcol.inner[3] = 64;
+ }
+ /* regular disabled */
+ else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
+ widget_state_blend(wt->wcol.text, wt->wcol.inner, 0.5f);
+ }
+ /* regular active */
+ else if (state & UI_SELECT) {
+ copy_v4_v4_char(wt->wcol.outline, wt->wcol.inner_sel);
+ copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
+ }
+ else if (state & UI_ACTIVE) {
+ copy_v4_v4_char(wt->wcol.inner, wt->wcol.item);
+ copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
+ }
+}
+
/* special case, menu items */
static void widget_state_menu_item(uiWidgetType *wt, int state)
{
@@ -2822,6 +2895,17 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
widgetbase_draw(&wtb, wcol);
+ if (but->a1 == UI_PALETTE_COLOR && but->a2 == UI_PALETTE_COLOR_ACTIVE) {
+ float width = rect->xmax - rect->xmin;
+ float height = rect->ymax - rect->ymin;
+
+ glColor4ubv((unsigned char *)wcol->outline);
+ glBegin(GL_TRIANGLES);
+ glVertex2f(rect->xmin + 0.1f * width, rect->ymin + 0.9f * height);
+ glVertex2f(rect->xmin + 0.1f * width, rect->ymin + 0.5f * height);
+ glVertex2f(rect->xmin + 0.5f * width, rect->ymin + 0.9f * height);
+ glEnd();
+ }
}
static void widget_normal(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
@@ -2958,6 +3042,29 @@ static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(sta
widgetbase_draw(&wtb, wcol);
}
+static void widget_menu_radial_itembut(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
+{
+ uiWidgetBase wtb;
+ float rad;
+ float fac = but->block->pie_data.alphafac;
+
+ widget_init(&wtb);
+
+ wtb.emboss = 0;
+
+ rad = 0.5f * BLI_rcti_size_y(rect);
+ round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
+
+ wcol->inner[3] *= fac;
+ wcol->inner_sel[3] *= fac;
+ wcol->item[3] *= fac;
+ wcol->text[3] *= fac;
+ wcol->text_sel[3] *= fac;
+ wcol->outline[3] *= fac;
+
+ widgetbase_draw(&wtb, wcol);
+}
+
static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
{
uiWidgetBase wtb;
@@ -3276,6 +3383,12 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.wcol_theme = &btheme->tui.wcol_progress;
wt.custom = widget_progressbar;
break;
+
+ case UI_WTYPE_MENU_ITEM_RADIAL:
+ wt.wcol_theme = &btheme->tui.wcol_pie_menu;
+ wt.custom = widget_menu_radial_itembut;
+ wt.state = widget_state_pie_menu_item;
+ break;
}
return &wt;
@@ -3382,6 +3495,9 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
/* "nothing" */
wt = widget_type(UI_WTYPE_ICON);
}
+ else if (but->dt == UI_EMBOSSR) {
+ wt = widget_type(UI_WTYPE_MENU_ITEM_RADIAL);
+ }
else {
switch (but->type) {
@@ -3634,6 +3750,125 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
}
}
+static void draw_disk_shaded(
+ float start, float angle,
+ float radius_int, float radius_ext, int subd,
+ const char col1[4], const char col2[4],
+ bool shaded)
+{
+ const float radius_ext_scale = (0.5f / radius_ext); /* 1 / (2 * radius_ext) */
+ int i;
+
+ float s, c;
+ float y1, y2;
+ float fac;
+ unsigned char r_col[4];
+
+ glBegin(GL_TRIANGLE_STRIP);
+
+ s = sinf(start);
+ c = cosf(start);
+
+ y1 = s * radius_int;
+ y2 = s * radius_ext;
+
+ if (shaded) {
+ fac = (y1 + radius_ext) * radius_ext_scale;
+ round_box_shade_col4_r(r_col, col1, col2, fac);
+
+ glColor4ubv(r_col);
+ }
+
+ glVertex2f(c * radius_int, s * radius_int);
+
+ if (shaded) {
+ fac = (y2 + radius_ext) * radius_ext_scale;
+ round_box_shade_col4_r(r_col, col1, col2, fac);
+
+ glColor4ubv(r_col);
+ }
+ glVertex2f(c * radius_ext, s * radius_ext);
+
+ for (i = 1; i < subd; i++) {
+ float a;
+
+ a = start + ((i) / (float)(subd - 1)) * angle;
+ s = sinf(a);
+ c = cosf(a);
+ y1 = s * radius_int;
+ y2 = s * radius_ext;
+
+ if (shaded) {
+ fac = (y1 + radius_ext) * radius_ext_scale;
+ round_box_shade_col4_r(r_col, col1, col2, fac);
+
+ glColor4ubv(r_col);
+ }
+ glVertex2f(c * radius_int, s * radius_int);
+
+ if (shaded) {
+ fac = (y2 + radius_ext) * radius_ext_scale;
+ round_box_shade_col4_r(r_col, col1, col2, fac);
+
+ glColor4ubv(r_col);
+ }
+ glVertex2f(c * radius_ext, s * radius_ext);
+ }
+ glEnd();
+
+}
+
+void ui_draw_pie_center(uiBlock *block)
+{
+ bTheme *btheme = UI_GetTheme();
+ float cx = block->pie_data.pie_center_spawned[0];
+ float cy = block->pie_data.pie_center_spawned[1];
+
+ float *pie_dir = block->pie_data.pie_dir;
+
+ float pie_radius_internal = U.pixelsize * U.pie_menu_threshold;
+ float pie_radius_external = U.pixelsize * (U.pie_menu_threshold + 7.0f);
+
+ int subd = 40;
+
+ float angle = atan2(pie_dir[1], pie_dir[0]);
+ float range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? ((float)M_PI / 2.0f) : ((float)M_PI / 4.0f);
+
+ glPushMatrix();
+ glTranslatef(cx, cy, 0.0f);
+
+ glEnable(GL_BLEND);
+ if (btheme->tui.wcol_pie_menu.shaded) {
+ char col1[4], col2[4];
+ shadecolors4(col1, col2, btheme->tui.wcol_pie_menu.inner, btheme->tui.wcol_pie_menu.shadetop, btheme->tui.wcol_pie_menu.shadedown);
+ draw_disk_shaded(0.0f, (float)(M_PI * 2.0), pie_radius_internal, pie_radius_external, subd, col1, col2, true);
+ }
+ else {
+ glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.inner);
+ draw_disk_shaded(0.0f, (float)(M_PI * 2.0), pie_radius_internal, pie_radius_external, subd, NULL, NULL, false);
+ }
+
+ if (!(block->pie_data.flags & UI_PIE_INVALID_DIR)) {
+ if (btheme->tui.wcol_pie_menu.shaded) {
+ char col1[4], col2[4];
+ shadecolors4(col1, col2, btheme->tui.wcol_pie_menu.inner_sel, btheme->tui.wcol_pie_menu.shadetop, btheme->tui.wcol_pie_menu.shadedown);
+ draw_disk_shaded(angle - range / 2.0f, range, pie_radius_internal, pie_radius_external, subd, col1, col2, true);
+ }
+ else {
+ glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.inner_sel);
+ draw_disk_shaded(angle - range / 2.0f, range, pie_radius_internal, pie_radius_external, subd, NULL, NULL, false);
+ }
+ }
+
+ glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.outline);
+ glutil_draw_lined_arc(0.0f, (float)M_PI * 2.0f, pie_radius_internal, subd);
+ glutil_draw_lined_arc(0.0f, (float)M_PI * 2.0f, pie_radius_external, subd);
+
+ glDisable(GL_BLEND);
+ glPopMatrix();
+}
+
+
uiWidgetColors *ui_tooltip_get_theme(void)
{
uiWidgetType *wt = widget_type(UI_WTYPE_TOOLTIP);
@@ -3711,7 +3946,7 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic
const float minwidth = (float)(UI_DPI_ICON_SIZE);
BLI_strncpy(drawstr, name, sizeof(drawstr));
- ui_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len);
+ ui_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, NULL);
glColor4ubv((unsigned char *)wt->wcol.text);
uiStyleFontDraw(fstyle, rect, drawstr);
@@ -3786,7 +4021,7 @@ void ui_draw_preview_item(uiFontStyle *fstyle, rcti *rect, const char *name, int
const float minwidth = (float)(UI_DPI_ICON_SIZE);
BLI_strncpy(drawstr, name, sizeof(drawstr));
- ui_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len);
+ ui_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, NULL);
glColor4ubv((unsigned char *)wt->wcol.text);
uiStyleFontDraw(fstyle, &trect, drawstr);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 372ced0a6fd..0879f335c68 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -36,11 +36,10 @@
#include "MEM_guardedalloc.h"
#include "DNA_curve_types.h"
-#include "DNA_userdef_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
-#include "DNA_mesh_types.h" /* init_userdef_factory */
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -51,7 +50,6 @@
#include "BKE_main.h"
#include "BKE_texture.h"
-
#include "BIF_gl.h"
#include "UI_interface.h"
@@ -337,6 +335,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->normal; break;
case TH_VNORMAL:
cp = ts->vertex_normal; break;
+ case TH_LNORMAL:
+ cp = ts->loop_normal; break;
case TH_BONE_SOLID:
cp = ts->bone_solid; break;
case TH_BONE_POSE:
@@ -537,6 +537,13 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->preview_stitch_active;
break;
+ case TH_PAINT_CURVE_HANDLE:
+ cp = ts->paint_curve_handle;
+ break;
+ case TH_PAINT_CURVE_PIVOT:
+ cp = ts->paint_curve_pivot;
+ break;
+
case TH_UV_OTHERS:
cp = ts->uv_others;
break;
@@ -774,6 +781,8 @@ static void ui_theme_space_init_handles_color(ThemeSpace *theme_space)
rgba_char_args_set(theme_space->handle_sel_auto, 0xf0, 0xff, 0x40, 255);
rgba_char_args_set(theme_space->handle_sel_vect, 0x40, 0xc0, 0x30, 255);
rgba_char_args_set(theme_space->handle_sel_align, 0xf0, 0x90, 0xa0, 255);
+ rgba_char_args_set(theme_space->handle_vertex, 0x00, 0x00, 0x00, 0xff);
+ rgba_char_args_set(theme_space->handle_vertex_select, 0xff, 0xff, 0, 0xff);
rgba_char_args_set(theme_space->act_spline, 0xdb, 0x25, 0x12, 255);
}
@@ -859,6 +868,7 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tv3d.face_select, 255, 133, 0, 60);
rgba_char_args_set(btheme->tv3d.normal, 0x22, 0xDD, 0xDD, 255);
rgba_char_args_set(btheme->tv3d.vertex_normal, 0x23, 0x61, 0xDD, 255);
+ rgba_char_args_set(btheme->tv3d.loop_normal, 0xDD, 0x23, 0xDD, 255);
rgba_char_args_set(btheme->tv3d.face_dot, 255, 133, 0, 255);
rgba_char_args_set(btheme->tv3d.editmesh_active, 255, 255, 255, 128);
rgba_char_args_set_fl(btheme->tv3d.edge_crease, 0.8, 0, 0.6, 1.0);
@@ -871,6 +881,8 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tv3d.title, 0, 0, 0, 255);
rgba_char_args_set(btheme->tv3d.freestyle_edge_mark, 0x7f, 0xff, 0x7f, 255);
rgba_char_args_set(btheme->tv3d.freestyle_face_mark, 0x7f, 0xff, 0x7f, 51);
+ rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
+ rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
btheme->tv3d.facedot_size = 4;
@@ -1129,8 +1141,6 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tclip.path_after, 0x00, 0x00, 0xff, 255);
rgba_char_args_set(btheme->tclip.grid, 0x5e, 0x5e, 0x5e, 255);
rgba_char_args_set(btheme->tclip.cframe, 0x60, 0xc0, 0x40, 255);
- rgba_char_args_set(btheme->tclip.handle_vertex, 0x00, 0x00, 0x00, 0xff);
- rgba_char_args_set(btheme->tclip.handle_vertex_select, 0xff, 0xff, 0, 0xff);
rgba_char_args_set(btheme->tclip.list, 0x66, 0x66, 0x66, 0xff);
rgba_char_args_set(btheme->tclip.strip, 0x0c, 0x0a, 0x0a, 0x80);
rgba_char_args_set(btheme->tclip.strip_select, 0xff, 0x8c, 0x00, 0xff);
@@ -2427,9 +2437,39 @@ void init_userdef_do_versions(void)
}
}
- {
+ if (U.versionfile < 272 || (U.versionfile == 272 && U.subversionfile < 2)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
+ rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
+ rgba_char_args_set_fl(btheme->tima.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
+ rgba_char_args_set_fl(btheme->tima.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
+ }
+ }
+
+ if (U.versionfile < 271 || (U.versionfile == 271 && U.subversionfile < 5)) {
bTheme *btheme;
+
+ struct uiWidgetColors wcol_pie_menu = {
+ {10, 10, 10, 200},
+ {25, 25, 25, 230},
+ {140, 140, 140, 255},
+ {45, 45, 45, 230},
+
+ {160, 160, 160, 255},
+ {255, 255, 255, 255},
+
+ 1,
+ 10, -10
+ };
+
+ U.pie_menu_radius = 100;
+ U.pie_menu_threshold = 12;
+ U.pie_animation_timeout = 6;
+
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ btheme->tui.wcol_pie_menu = wcol_pie_menu;
+
ui_theme_space_init_handles_color(&btheme->tclip);
ui_theme_space_init_handles_color(&btheme->tima);
btheme->tima.handle_vertex_size = 5;
@@ -2437,6 +2477,16 @@ void init_userdef_do_versions(void)
}
}
+ if (U.versionfile < 271 || (U.versionfile == 271 && U.subversionfile < 6)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ /* check for (alpha == 0) is safe, then color was never set */
+ if (btheme->tv3d.loop_normal[3] == 0) {
+ rgba_char_args_set(btheme->tv3d.loop_normal, 0xDD, 0x23, 0xDD, 255);
+ }
+ }
+ }
+
if (U.pixelsize == 0.0f)
U.pixelsize = 1.0f;
@@ -2449,25 +2499,3 @@ void init_userdef_do_versions(void)
// XXX reset_autosave();
}
-
-/**
- * Override values in in-memory startup.blend, avoids resaving for small changes.
- */
-void init_userdef_factory(void)
-{
- /* defaults from T37518 */
-
- U.uiflag |= USER_ZBUF_CURSOR;
- U.uiflag |= USER_QUIT_PROMPT;
- U.uiflag |= USER_CONTINUOUS_MOUSE;
-
- U.versions = 1;
- U.savetime = 2;
-
- {
- Mesh *me;
- for (me = G.main->mesh.first; me; me = me->id.next) {
- me->flag &= ~ME_TWOSIDED;
- }
- }
-}
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index 45dd47097f5..ccc6f6de94e 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -384,7 +384,7 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_
* - cur must not fall outside of tot
* - axis locks (zoom and offset) must be maintained
* - zoom must not be excessive (check either sizes or zoom values)
- * - aspect ratio should be respected (NOTE: this is quite closely realted to zoom too)
+ * - aspect ratio should be respected (NOTE: this is quite closely related to zoom too)
*/
/* Step 1: if keepzoom, adjust the sizes of the rects only
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index e30c6ca61ba..2b84c0678ae 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -767,6 +767,8 @@ static int view_zoomin_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void VIEW2D_OT_zoom_in(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Zoom In";
ot->description = "Zoom in the view";
@@ -778,10 +780,12 @@ static void VIEW2D_OT_zoom_in(wmOperatorType *ot)
ot->poll = view_zoom_poll;
/* rna - must keep these in sync with the other operators */
- RNA_def_float(ot->srna, "zoomfacx", 0, -FLT_MAX, FLT_MAX, "Zoom Factor X", "", -FLT_MAX, FLT_MAX);
- RNA_def_float(ot->srna, "zoomfacy", 0, -FLT_MAX, FLT_MAX, "Zoom Factor Y", "", -FLT_MAX, FLT_MAX);
+ prop = RNA_def_float(ot->srna, "zoomfacx", 0, -FLT_MAX, FLT_MAX, "Zoom Factor X", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_float(ot->srna, "zoomfacy", 0, -FLT_MAX, FLT_MAX, "Zoom Factor Y", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
-
+
/* this operator only needs this single callback, where it calls the view_zoom_*() methods */
static int view_zoomout_exec(bContext *C, wmOperator *op)
{
@@ -828,6 +832,8 @@ static int view_zoomout_invoke(bContext *C, wmOperator *op, const wmEvent *event
static void VIEW2D_OT_zoom_out(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Zoom Out";
ot->description = "Zoom out the view";
@@ -839,8 +845,10 @@ static void VIEW2D_OT_zoom_out(wmOperatorType *ot)
ot->poll = view_zoom_poll;
/* rna - must keep these in sync with the other operators */
- RNA_def_float(ot->srna, "zoomfacx", 0, -FLT_MAX, FLT_MAX, "Zoom Factor X", "", -FLT_MAX, FLT_MAX);
- RNA_def_float(ot->srna, "zoomfacy", 0, -FLT_MAX, FLT_MAX, "Zoom Factor Y", "", -FLT_MAX, FLT_MAX);
+ prop = RNA_def_float(ot->srna, "zoomfacx", 0, -FLT_MAX, FLT_MAX, "Zoom Factor X", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_float(ot->srna, "zoomfacy", 0, -FLT_MAX, FLT_MAX, "Zoom Factor Y", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/* ********************************************************* */
@@ -1139,6 +1147,7 @@ static int view_zoomdrag_modal(bContext *C, wmOperator *op, const wmEvent *event
static void VIEW2D_OT_zoom(wmOperatorType *ot)
{
+ PropertyRNA *prop;
/* identifiers */
ot->name = "Zoom 2D View";
ot->description = "Zoom in/out the view";
@@ -1156,8 +1165,10 @@ static void VIEW2D_OT_zoom(wmOperatorType *ot)
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
/* rna - must keep these in sync with the other operators */
- RNA_def_float(ot->srna, "deltax", 0, -FLT_MAX, FLT_MAX, "Delta X", "", -FLT_MAX, FLT_MAX);
- RNA_def_float(ot->srna, "deltay", 0, -FLT_MAX, FLT_MAX, "Delta Y", "", -FLT_MAX, FLT_MAX);
+ prop = RNA_def_float(ot->srna, "deltax", 0, -FLT_MAX, FLT_MAX, "Delta X", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_float(ot->srna, "deltay", 0, -FLT_MAX, FLT_MAX, "Delta Y", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/* ********************************************************* */
@@ -1522,6 +1533,7 @@ typedef struct v2dScrollerMove {
short zone; /* -1 is min zoomer, 0 is bar, 1 is max zoomer */ // XXX find some way to provide visual feedback of this (active color?)
float fac; /* view adjustment factor, based on size of region */
+ float fac_round; /* for pixel rounding (avoid visible UI jitter) */
float delta; /* amount moved by mouse on axis of interest */
float scrollbarwidth; /* width of the scrollbar itself, used for page up/down clicks */
@@ -1560,7 +1572,7 @@ enum {
*/
static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_min, int sh_max)
{
- short in_min, in_max, in_bar, out_min, out_max, in_view = 1;
+ bool in_min, in_max, in_bar, out_min, out_max, in_view = 1;
/* firstly, check if
* - 'bubble' fills entire scroller
@@ -1583,9 +1595,9 @@ static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_
/* check if mouse is in or past either handle */
/* TODO: check if these extents are still valid or not */
- in_max = ( (mouse >= (sh_max - V2D_SCROLLER_HANDLE_SIZE)) && (mouse <= (sh_max + V2D_SCROLLER_HANDLE_SIZE)) );
- in_min = ( (mouse <= (sh_min + V2D_SCROLLER_HANDLE_SIZE)) && (mouse >= (sh_min - V2D_SCROLLER_HANDLE_SIZE)) );
- in_bar = ( (mouse < (sh_max - V2D_SCROLLER_HANDLE_SIZE)) && (mouse > (sh_min + V2D_SCROLLER_HANDLE_SIZE)) );
+ in_max = ((mouse >= (sh_max - V2D_SCROLLER_HANDLE_SIZE)) && (mouse <= (sh_max + V2D_SCROLLER_HANDLE_SIZE)));
+ in_min = ((mouse <= (sh_min + V2D_SCROLLER_HANDLE_SIZE)) && (mouse >= (sh_min - V2D_SCROLLER_HANDLE_SIZE)));
+ in_bar = ((mouse < (sh_max - V2D_SCROLLER_HANDLE_SIZE)) && (mouse > (sh_min + V2D_SCROLLER_HANDLE_SIZE)));
out_min = mouse < (sh_min - V2D_SCROLLER_HANDLE_SIZE);
out_max = mouse > (sh_max + V2D_SCROLLER_HANDLE_SIZE);
@@ -1640,7 +1652,10 @@ static void scroller_activate_init(bContext *C, wmOperator *op, const wmEvent *e
/* horizontal scroller - calculate adjustment factor first */
mask_size = (float)BLI_rcti_size_x(&v2d->hor);
vsm->fac = BLI_rctf_size_x(&tot_cur_union) / mask_size;
-
+
+ /* pixel rounding */
+ vsm->fac_round = (BLI_rctf_size_x(&v2d->cur)) / (float)(BLI_rcti_size_x(&ar->winrct) + 1);
+
/* get 'zone' (i.e. which part of scroller is activated) */
vsm->zone = mouse_in_scroller_handle(event->mval[0],
v2d->hor.xmin, v2d->hor.xmax,
@@ -1659,6 +1674,9 @@ static void scroller_activate_init(bContext *C, wmOperator *op, const wmEvent *e
mask_size = (float)BLI_rcti_size_y(&v2d->vert);
vsm->fac = BLI_rctf_size_y(&tot_cur_union) / mask_size;
+ /* pixel rounding */
+ vsm->fac_round = (BLI_rctf_size_y(&v2d->cur)) / (float)(BLI_rcti_size_y(&ar->winrct) + 1);
+
/* get 'zone' (i.e. which part of scroller is activated) */
vsm->zone = mouse_in_scroller_handle(event->mval[1],
v2d->vert.ymin, v2d->vert.ymax,
@@ -1706,6 +1724,9 @@ static void scroller_activate_apply(bContext *C, wmOperator *op)
/* calculate amount to move view by */
temp = vsm->fac * vsm->delta;
+
+ /* round to pixel */
+ temp = roundf(temp / vsm->fac_round) * vsm->fac_round;
/* type of movement */
switch (vsm->zone) {