Commit: 127330d6cadd107d645acd8d97d2f15a75798bf1
Author: Campbell Barton
Date:   Sat Feb 8 09:34:01 2014 +1100
https://developer.blender.org/rB127330d6cadd107d645acd8d97d2f15a75798bf1

UI: multi-drag number button editing

clicking and dragging down edits multiple number buttons at once. (patch D270)

===================================================================

M       source/blender/editors/include/UI_interface.h
M       source/blender/editors/interface/interface.c
M       source/blender/editors/interface/interface_handlers.c
M       source/blender/editors/interface/interface_intern.h
M       source/blender/editors/interface/interface_widgets.c

===================================================================

diff --git a/source/blender/editors/include/UI_interface.h 
b/source/blender/editors/include/UI_interface.h
index 5925796..a059ca6 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -172,6 +172,7 @@ enum {
        UI_BUT_VEC_SIZE_LOCK = (1 << 22),  /* used to flag if color hsv-circle 
should keep luminance */
        UI_BUT_COLOR_CUBIC   = (1 << 23),  /* cubic saturation for the color 
wheel */
        UI_BUT_LIST_ITEM     = (1 << 24),  /* This but is "inside" a list item 
(currently used to change theme colors). */
+       UI_BUT_DRAG_MULTI    = (1 << 25),  /* edit this button as well as the 
active button (not just dragging) */
 };
 
 #define UI_PANEL_WIDTH          340
diff --git a/source/blender/editors/interface/interface.c 
b/source/blender/editors/interface/interface.c
index 8ad96b4..fb0b035 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -584,7 +584,7 @@ static void ui_but_update_linklines(uiBlock *block, uiBut 
*oldbut, uiBut *newbut
 static bool ui_but_update_from_old_block(const bContext *C, uiBlock *block, 
uiBut **but_p, uiBut **but_old_p)
 {
        /* flags from the buttons we want to refresh, may want to add more 
here... */
-       const int flag_copy = UI_BUT_REDALERT;
+       const int flag_copy = UI_BUT_REDALERT | UI_BUT_DRAG_MULTI;
        const int drawflag_copy = 0;  /* None currently. */
 
        uiBlock *oldblock = block->oldblock;
@@ -676,6 +676,8 @@ static bool ui_but_update_from_old_block(const bContext *C, 
uiBlock *block, uiBu
                /* note: if layout hasn't been applied yet, it uses old button 
pointers... */
        }
        else {
+               but->flag = (but->flag & ~flag_copy) | (oldbut->flag & 
flag_copy);
+
                /* ensures one button can get activated, and in case the buttons
                 * draw are the same this gives O(1) lookup for each button */
                BLI_remlink(&oldblock->buttons, oldbut);
@@ -1577,6 +1579,32 @@ bool ui_is_but_unit(const uiBut *but)
        return true;
 }
 
+/**
+ * Check if this button is similar enough to be grouped with another.
+ */
+bool ui_is_but_compatible(const uiBut *but_a, const uiBut *but_b)
+{
+       if (but_a->type != but_b->type)
+               return false;
+       if (but_a->pointype != but_b->pointype)
+               return false;
+
+       if (but_a->rnaprop) {
+               if (but_a->rnapoin.type != but_b->rnapoin.type)
+                       return false;
+               if (but_a->rnapoin.data != but_b->rnapoin.data)
+                       return false;
+               if (but_a->rnapoin.id.data != but_b->rnapoin.id.data)
+                       return false;
+               if (RNA_property_type(but_a->rnaprop) != 
RNA_property_type(but_b->rnaprop))
+                       return false;
+               if (RNA_property_subtype(but_a->rnaprop) != 
RNA_property_subtype(but_b->rnaprop))
+                       return false;
+       }
+
+       return true;
+}
+
 bool ui_is_but_rna_valid(uiBut *but)
 {
        if (but->rnaprop == NULL || RNA_struct_contains_property(&but->rnapoin, 
but->rnaprop)) {
diff --git a/source/blender/editors/interface/interface_handlers.c 
b/source/blender/editors/interface/interface_handlers.c
index 625e38e..f189af7 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -47,7 +47,11 @@
 #include "DNA_screen_types.h"
 
 #include "BLI_math.h"
-#include "BLI_blenlib.h"
+#include "BLI_listbase.h"
+#include "BLI_linklist.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_rect.h"
 #include "BLI_utildefines.h"
 #include "BLI_string_cursor_utf8.h"
 
@@ -86,6 +90,9 @@
 /* support dragging toggle buttons */
 #define USE_DRAG_TOGGLE
 
+/* support dragging multiple number buttons at once */
+#define USE_DRAG_MULTINUM
+
 /* so we can avoid very small mouse-moves from jumping away from keyboard 
navigation [#34936] */
 #define USE_KEYNAV_LIMIT
 
@@ -134,6 +141,59 @@ typedef enum uiHandleButtonState {
        BUTTON_STATE_EXIT
 } uiHandleButtonState;
 
+
+#ifdef USE_DRAG_MULTINUM
+
+/* how far to drag before we check for gesture direction (in pixels),
+ * 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),
+ * locking down the buttons so we can drag freely without worrying about 
vertical movement. */
+#define DRAG_MULTINUM_THRESHOLD_DRAG_Y (UI_UNIT_Y / 4)
+
+/* how strict to be when detecting a vertical gesture, [0.5 == sloppy], [0.9 
== strict], (unsigned dot-product)
+ * note: we should be quite strict here, since doing a vertical gesture by 
accident should be avoided,
+ * however with some care a user should be able to do a vertical movement 
without *missing*. */
+#define DRAG_MULTINUM_THRESHOLD_VERTICAL (0.75f)
+
+
+/* a simple version of uiHandleButtonData when accessing multiple buttons */
+typedef struct uiButMultiState {
+       double origvalue;
+       uiBut *but;
+} uiButMultiState;
+
+typedef struct uiHandleButtonMulti {
+       enum {
+               BUTTON_MULTI_INIT_UNSET = 0,    /* gesture direction unknown, 
wait until mouse has moved enough... */
+               BUTTON_MULTI_INIT_SETUP,        /* vertical gesture detected, 
flag buttons interactively (UI_BUT_DRAG_MULTI) */
+               BUTTON_MULTI_INIT_ENABLE,       /* flag buttons finished, apply 
horizontal motion to active and flagged */
+               BUTTON_MULTI_INIT_DISABLE,      /* vertical gesture _not_ 
detected, take no further action */
+       } init;
+
+       bool has_mbuts;  /* any buttons flagged UI_BUT_DRAG_MULTI */
+       LinkNode *mbuts;
+       uiButStore *bs_mbuts;
+
+       /* before activating, we need to check gesture direction
+        * accumulate signed cursor movement here so we can tell if this is a 
vertical motion or not. */
+       float drag_dir[2];
+
+       /* values copied direct from event->x,y
+        * used to detect buttons between the current and initial mouse 
position */
+       int drag_start[2];
+
+       /* store x location once BUTTON_MULTI_INIT_SETUP is set,
+        * moving outside this sets BUTTON_MULTI_INIT_ENABLE */
+       int drag_lock_x;
+
+} uiHandleButtonMulti;
+
+#endif  /* USE_DRAG_MULTINUM */
+
+
+
 typedef struct uiHandleButtonData {
        wmWindowManager *wm;
        wmWindow *window;
@@ -197,6 +257,11 @@ typedef struct uiHandleButtonData {
        struct uiKeyNavLock searchbox_keynav_state;
 #endif
 
+#ifdef USE_DRAG_MULTINUM
+       /* Multi-buttons will be updated in unison with the active button. */
+       uiHandleButtonMulti multi_data;
+#endif
+
        /* post activate */
        uiButtonActivateType posttype;
        uiBut *postbut;
@@ -251,6 +316,11 @@ static int ui_handler_region_menu(bContext *C, const 
wmEvent *event, void *userd
 static void ui_handle_button_activate(bContext *C, ARegion *ar, uiBut *but, 
uiButtonActivateType type);
 static void button_timers_tooltip_remove(bContext *C, uiBut *but);
 
+#ifdef USE_DRAG_MULTINUM
+static void ui_multibut_restore(uiHandleButtonData *data, uiBlock *block);
+static uiButMultiState *ui_multibut_lookup(uiHandleButtonData *data, const 
uiBut *but);
+#endif
+
 /* buttons clipboard */
 static ColorBand but_copypaste_coba = {0};
 static CurveMapping but_copypaste_curve = {0};
@@ -736,6 +806,182 @@ static void ui_apply_but_CURVE(bContext *C, uiBut *but, 
uiHandleButtonData *data
 
 /* ****************** drag drop code *********************** */
 
+
+#ifdef USE_DRAG_MULTINUM
+
+/* small multi-but api */
+static void ui_multibut_add(uiHandleButtonData *data, uiBut *but)
+{
+       uiButMultiState *mbut_state;
+
+       BLI_assert(but->flag & UI_BUT_DRAG_MULTI);
+       BLI_assert(data->multi_data.has_mbuts);
+
+
+       mbut_state = MEM_callocN(sizeof(*mbut_state), __func__);
+       mbut_state->but = but;
+       mbut_state->origvalue = ui_get_but_val(but);
+
+       BLI_linklist_prepend(&data->multi_data.mbuts, mbut_state);
+
+       UI_butstore_register(data->multi_data.bs_mbuts, &mbut_state->but);
+}
+
+static uiButMultiState *ui_multibut_lookup(uiHandleButtonData *data, const 
uiBut *but)
+{
+       LinkNode *l;
+
+       for (l = data->multi_data.mbuts; l; l = l->next) {
+               uiButMultiState *mbut_state;
+
+               mbut_state = l->link;
+
+               if (mbut_state->but == but) {
+                       return mbut_state;
+               }
+       }
+
+       return NULL;
+}
+
+static void ui_multibut_restore(uiHandleButtonData *data, uiBlock *block)
+{
+       uiBut *but;
+
+       for (but = block->buttons.first; but; but = but->next) {
+               if (but->flag & UI_BUT_DRAG_MULTI) {
+                       uiButMultiState *mbut_state = ui_multibut_lookup(data, 
but);
+                       if (mbut_state) {
+                               ui_set_but_val(but, mbut_state->origvalue);
+                       }
+               }
+       }
+}
+
+static void ui_multibut_free(uiHandleButtonData *data, uiBlock *block)
+{
+       BLI_linklist_freeN(data->multi_data.mbuts);
+       data->multi_data.mbuts = NULL;
+
+       if (data->multi_data.bs_mbuts) {
+               UI_butstore_free(block, data->multi_data.bs_mbuts);
+               data->multi_data.bs_mbuts = NULL;
+       }
+}
+
+static bool ui_multibut_states_tag(uiBut *but_active, uiHandleButtonData 
*data, const wmEvent *event)
+{
+       uiBut *but;
+       float seg[2][2];
+       bool changed = false;
+
+       seg[0][0] = data->multi_data.drag_start[0];
+       seg[0][1] = data->multi_data.drag_start[1];
+
+       seg[1][0] = event->x;
+       seg[1][1] = event->y;
+
+       BLI_assert(data->multi_data.init == BUTTON_MULTI_INIT_SETUP);
+
+       ui_window_to_block_fl(data->region, but_active->block, &seg[0][0], 
&seg[0][1]);
+       ui_window_to_block_fl(data->region, but_active->block, &seg[1][0], 
&seg[1][1]);
+
+       data->multi_data.has_mbuts = false;
+
+       /* follow ui_but_find_mouse_over_ex logic */
+       for (but = but_active->block->buttons.first; but; but = but->next) {
+               bool drag_prev = false;
+               bool drag_curr = false;
+
+               /* re-set each time */
+               if (but->flag & UI_BUT_DRAG_MULTI) {
+                       but->flag &= ~UI_BUT_DRAG_MULTI;
+                       drag_prev = true;
+               }
+
+               if (ui_is_but_interactive(but, false)) {
+
+                       /* drag checks */
+                       if (but_active != but) {
+                               if (ui_is_but_compatible(but_active, but)) {
+
+                                       BLI_assert(but->active == NULL);
+
+                                       /* finally check for overlap */
+                                       if (BLI_rctf_isect_segment(&but->rect, 
seg[0], seg[1])) {
+
+                                               but->flag |= UI_BUT_DRAG_MULTI;
+                                               data->multi_data.has_mbuts = 
true;
+                                               drag_curr = true;
+                                       }
+                               }
+                       }
+               }
+
+               changed |= (drag_prev != drag_curr);
+       }
+
+       return changed;
+}
+
+static void ui_multibut_states_create(uiBut *but_active, uiHandleButtonData 
*data)
+{
+       uiBut *but;
+
+       BLI_assert(data->multi_data.init == BUTTON_MULTI_INIT_SETUP);
+
+       data->multi_data.bs_mbuts = UI_butstore_create(but_active->block);
+
+       for (but = but_active->block->buttons

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to