[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [54742] trunk/blender: Toggle-Drag UI Feature

Campbell Barton ideasman42 at gmail.com
Fri Feb 22 06:56:21 CET 2013


Revision: 54742
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=54742
Author:   campbellbarton
Date:     2013-02-22 05:56:20 +0000 (Fri, 22 Feb 2013)
Log Message:
-----------
Toggle-Drag UI Feature

Dragging on toggle buttons can now be used to press multiple buttons at once, especially useful for layer and outliner buttons.


notes:
- automatically enabled for all toggle buttons
  (may change this if it becomes a problem).
- only buttons of the same type are pressed
  (helps avoid annoyances eg; dragging past layer buttons onto other 3d header buttons and pressing by accident).
- automatic axis locking - dragging will lock to X/Y depending on the initial drag direction,
  makes swipe motions work better, especially with the outliner.


implementation details:
- may re-implement as a region handler (currently its a modal operator).
- checking buttons in-between cursor motion events could be more efficient (but currently works ok).
- button execution needs to be improved
  (currently executing a button thats not under the mouse needed a workaround for passing uiHandleButtonData),
  requires further changes to UI code, will do next.

Modified Paths:
--------------
    trunk/blender/release/scripts/startup/bl_ui/space_view3d_toolbar.py
    trunk/blender/source/blender/editors/include/UI_interface.h
    trunk/blender/source/blender/editors/interface/interface.c
    trunk/blender/source/blender/editors/interface/interface_handlers.c
    trunk/blender/source/blender/editors/interface/interface_intern.h
    trunk/blender/source/blender/editors/interface/interface_ops.c

Modified: trunk/blender/release/scripts/startup/bl_ui/space_view3d_toolbar.py
===================================================================
--- trunk/blender/release/scripts/startup/bl_ui/space_view3d_toolbar.py	2013-02-22 04:09:04 UTC (rev 54741)
+++ trunk/blender/release/scripts/startup/bl_ui/space_view3d_toolbar.py	2013-02-22 05:56:20 UTC (rev 54742)
@@ -1060,7 +1060,7 @@
         col.label("Show Zero Weights:")
         rowsub = col.row()
         rowsub.active = (not tool_settings.use_multipaint)
-        rowsub.prop(tool_settings, "vertex_group_user", text="Show Group Use", expand=True)
+        rowsub.prop(tool_settings, "vertex_group_user", expand=True)
 
         self.unified_paint_settings(col, context)
 

Modified: trunk/blender/source/blender/editors/include/UI_interface.h
===================================================================
--- trunk/blender/source/blender/editors/include/UI_interface.h	2013-02-22 04:09:04 UTC (rev 54741)
+++ trunk/blender/source/blender/editors/include/UI_interface.h	2013-02-22 05:56:20 UTC (rev 54742)
@@ -437,6 +437,7 @@
 void    uiButSetDragImage(uiBut *but, const char *path, int icon, struct ImBuf *ima, float scale);
 
 int     UI_but_active_drop_name(struct bContext *C);
+struct uiBut  *ui_but_find_mouse_over(struct ARegion *ar, int x, int y);
 
 void    uiButSetFlag(uiBut *but, int flag);
 void    uiButClearFlag(uiBut *but, int flag);
@@ -447,7 +448,9 @@
 /* special button case, only draw it when used actively, for outliner etc */
 int     uiButActiveOnly(const struct bContext *C, uiBlock *block, uiBut *but);
 
+void    uiButExecute(const struct bContext *C, uiBut *but);
 
+
 /* Buttons
  *
  * Functions to define various types of buttons in a block. Postfixes:

Modified: trunk/blender/source/blender/editors/interface/interface.c
===================================================================
--- trunk/blender/source/blender/editors/interface/interface.c	2013-02-22 04:09:04 UTC (rev 54741)
+++ trunk/blender/source/blender/editors/interface/interface.c	2013-02-22 05:56:20 UTC (rev 54742)
@@ -713,6 +713,12 @@
 	return 1;
 }
 
+/* simulate button click */
+void uiButExecute(const bContext *C, uiBut *but)
+{
+	ui_button_execute_do((bContext *)C, CTX_wm_region(C), but);
+}
+
 /* use to check if we need to disable undo, but don't make any changes
  * returns FALSE if undo needs to be disabled. */
 static int ui_but_is_rna_undo(uiBut *but)
@@ -1394,6 +1400,18 @@
 	return 0;
 }
 
+int ui_is_but_bool(uiBut *but)
+{
+	if (ELEM5(but->type, TOG, TOGN, TOGR, ICONTOG, ICONTOGN))
+		return 1;
+
+	if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_BOOLEAN)
+		return 1;
+
+	return 0;
+}
+
+
 int ui_is_but_unit(uiBut *but)
 {
 	UnitSettings *unit = but->block->unit;

Modified: trunk/blender/source/blender/editors/interface/interface_handlers.c
===================================================================
--- trunk/blender/source/blender/editors/interface/interface_handlers.c	2013-02-22 04:09:04 UTC (rev 54741)
+++ trunk/blender/source/blender/editors/interface/interface_handlers.c	2013-02-22 05:56:20 UTC (rev 54742)
@@ -85,6 +85,7 @@
 /* proto */
 static void ui_add_smart_controller(bContext *C, uiBut *from, uiBut *to);
 static void ui_add_link(bContext *C, uiBut *from, uiBut *to);
+static int ui_do_but_EXIT(bContext *C, uiBut *but, struct uiHandleButtonData *data, const wmEvent *event);
 
 /***************** structs and defines ****************/
 
@@ -761,14 +762,27 @@
 	WM_gestures_remove(C);
 
 	if (ABS(data->dragstartx - event->x) + ABS(data->dragstarty - event->y) > U.dragthreshold) {
-		wmDrag *drag;
-		
+
 		button_activate_state(C, but, BUTTON_STATE_EXIT);
 		data->cancel = TRUE;
 		
-		drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but));
-		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));
+		if (ui_is_but_bool(but)) {
+			const bool is_set = (ui_get_but_val(but) != 0.0);
+			PointerRNA ptr;
+			WM_operator_properties_create(&ptr, "UI_OT_drag_toggle");
+			RNA_boolean_set(&ptr, "state", !is_set);
+			RNA_int_set(&ptr, "last_x", data->dragstartx);
+			RNA_int_set(&ptr, "last_y", data->dragstarty);
+			WM_operator_name_call(C, "UI_OT_drag_toggle", WM_OP_INVOKE_DEFAULT, &ptr);
+			WM_operator_properties_free(&ptr);
+		}
+		else {
+			wmDrag *drag;
+
+			drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but));
+			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));
+		}
 		return 1;
 	}
 	
@@ -2472,13 +2486,24 @@
 static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
 {
 	if (data->state == BUTTON_STATE_HIGHLIGHT) {
+		if (event->type == LEFTMOUSE && event->val == KM_PRESS && ui_is_but_bool(but)) {
+			button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
+			data->dragstartx = event->x;
+			data->dragstarty = event->y;
+			return WM_UI_HANDLER_CONTINUE;
+		}
+
 		if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
 			data->togdual = event->ctrl;
 			data->togonly = !event->shift;
 			button_activate_state(C, but, BUTTON_STATE_EXIT);
-			return WM_UI_HANDLER_BREAK;
+			return WM_UI_HANDLER_CONTINUE;
 		}
 	}
+	else if (data->state == BUTTON_STATE_WAIT_DRAG) {
+		/* note: the 'BUTTON_STATE_WAIT_DRAG' part of 'ui_do_but_EXIT' could be refactored into its own function */
+		return ui_do_but_EXIT(C, but, data, event);
+	}
 	return WM_UI_HANDLER_CONTINUE;
 }
 
@@ -2499,6 +2524,12 @@
 				return WM_UI_HANDLER_CONTINUE;
 			}
 		}
+		if (event->type == LEFTMOUSE && ui_is_but_bool(but)) {
+			button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
+			data->dragstartx = event->x;
+			data->dragstarty = event->y;
+			return WM_UI_HANDLER_CONTINUE;
+		}
 		
 		if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
 			int ret = WM_UI_HANDLER_BREAK;
@@ -3215,6 +3246,12 @@
 				return WM_UI_HANDLER_BREAK;
 			}
 		}
+		if (event->type == LEFTMOUSE && ui_is_but_bool(but)) {
+			button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
+			data->dragstartx = event->x;
+			data->dragstarty = event->y;
+			return WM_UI_HANDLER_BREAK;
+		}
 		
 		/* regular open menu */
 		if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
@@ -5415,7 +5452,7 @@
 	return 1;
 }
 
-static uiBut *ui_but_find_mouse_over(ARegion *ar, int x, int y)
+uiBut *ui_but_find_mouse_over(ARegion *ar, int x, int y)
 {
 	uiBlock *block;
 	uiBut *but, *butover = NULL;
@@ -5784,8 +5821,10 @@
 	ED_region_tag_redraw(data->region);
 	
 	/* clean up button */
-	MEM_freeN(but->active);
-	but->active = NULL;
+	if (but->active) {
+		MEM_freeN(but->active);
+		but->active = NULL;
+	}
 	but->flag &= ~(UI_ACTIVE | UI_SELECT);
 	but->flag |= UI_BUT_LAST_ACTIVE;
 	if (!onfree)
@@ -6034,6 +6073,20 @@
 	ui_do_button(C, but->block, but, &event);
 }
 
+void ui_button_execute_do(struct bContext *C, struct ARegion *ar, uiBut *but)
+{
+	/* note: ideally we would not have to change 'but->active' howevwer
+	 * some functions we call don't use data (as they should be doing) */
+	void *active_back = but->active;
+	uiHandleButtonData *data = MEM_callocN(sizeof(uiHandleButtonData), "uiHandleButtonData_Fake");
+	but->active = data;
+	data->region = ar;
+	ui_apply_button(C, but->block, but, data, true);
+	/* use onfree event so undo is handled by caller and apply is already done above */
+	button_activate_exit((bContext *)C, data, but, false, true);
+	but->active = active_back;
+}
+
 static void ui_handle_button_activate(bContext *C, ARegion *ar, uiBut *but, uiButtonActivateType type)
 {
 	uiBut *oldbut;

Modified: trunk/blender/source/blender/editors/interface/interface_intern.h
===================================================================
--- trunk/blender/source/blender/editors/interface/interface_intern.h	2013-02-22 04:09:04 UTC (rev 54741)
+++ trunk/blender/source/blender/editors/interface/interface_intern.h	2013-02-22 05:56:20 UTC (rev 54742)
@@ -406,6 +406,7 @@
 
 extern void ui_check_but(uiBut *but);
 extern int  ui_is_but_float(uiBut *but);
+extern int  ui_is_but_bool(uiBut *but);
 extern int  ui_is_but_unit(uiBut *but);
 extern int  ui_is_but_rna_valid(uiBut *but);
 extern int  ui_is_but_utf8(uiBut *but);
@@ -509,6 +510,7 @@
 /* interface_handlers.c */
 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_execute_do(struct bContext *C, struct ARegion *ar, uiBut *but);
 extern void ui_button_active_free(const struct bContext *C, uiBut *but);
 extern int ui_button_is_active(struct ARegion *ar);
 extern int ui_button_open_menu_direction(uiBut *but);

Modified: trunk/blender/source/blender/editors/interface/interface_ops.c
===================================================================
--- trunk/blender/source/blender/editors/interface/interface_ops.c	2013-02-22 04:09:04 UTC (rev 54741)
+++ trunk/blender/source/blender/editors/interface/interface_ops.c	2013-02-22 05:56:20 UTC (rev 54742)
@@ -1071,6 +1071,228 @@
 	ot->exec = reloadtranslation_exec;
 }
 
+
+/* -------------------------------------------------------------------- */
+/* Toggle Drag Operator */
+
+typedef struct DragOpInfo {
+	bool xy_lock[2];
+	float but_cent_start[2];
+	eButType but_type_start;
+} DragOpInfo;
+
+typedef struct DragOpPlotData {
+	bContext *C;
+	ARegion *ar;
+	bool is_set;
+	eButType but_type_start;
+	bool do_draw;
+	const uiBut *but_prev;
+} DragOpPlotData;
+
+static const uiBut *ui_but_set_xy(bContext *C, ARegion *ar, const bool is_set, const eButType but_type_start,
+                                  const int xy[2], const uiBut *but_prev)
+{
+	uiBut *but = ui_but_find_mouse_over(ar, xy[0], xy[1]);
+
+	if (but_prev == but) {
+		return but_prev;
+	}
+
+	if (but && ui_is_but_bool(but) && but->type == but_type_start) {
+		/* is it pressed? */
+		bool is_set_but = (ui_get_but_val(but) != 0.0);
+		BLI_assert(ui_is_but_bool(but) == true);
+		if (is_set_but != is_set) {
+			uiButExecute(C, but);
+			return but;
+		}
+	}
+
+	return but_prev;
+}
+
+static int ui_but_set_cb(int x, int y, void *data_v)
+{
+	DragOpPlotData *data = data_v;
+	int xy[2] = {x, y};
+	data->but_prev = ui_but_set_xy(data->C, data->ar, data->is_set, data->but_type_start, xy, data->but_prev);

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list