[Bf-blender-cvs] [eced830] wiggly-widgets: Support selecting multiple (face map) widgets

Julian Eisel noreply at git.blender.org
Mon Nov 23 23:19:51 CET 2015


Commit: eced830925c4135611df1d40f5d1c2d7daad69d1
Author: Julian Eisel
Date:   Mon Nov 23 23:07:35 2015 +0100
Branches: wiggly-widgets
https://developer.blender.org/rBeced830925c4135611df1d40f5d1c2d7daad69d1

Support selecting multiple (face map) widgets

There are occasional crashes but I wasn't able to reproduce reliably. If somebody is able to, please tell me (or maybe it's already fixed) :)
GHash and arrays are used here to avoid slow linked lists and multiple iterations.

Also removes need for the fix mentioned in rBb1e01a242.

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

M	source/blender/windowmanager/WM_types.h
M	source/blender/windowmanager/intern/wm_widgets.c
M	source/blender/windowmanager/wm_event_system.h

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

diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 0e09f2c..fd975e9 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -726,14 +726,17 @@ typedef struct wmWidgetMap {
 	 * \brief Widget map runtime context
 	 *
 	 * Contains information about this widget map. Currently
-	 * highlighted widget, currently selected widget, ...
+	 * highlighted widget, currently selected widgets, ...
 	 */
 	struct {
 		/* we redraw the widgetmap when this changes */
 		wmWidget *highlighted_widget;
 		/* user has clicked this widget and it gets all input */
 		wmWidget *active_widget;
-		wmWidget *selected_widget;
+		/* array for all selected widgets
+		 * TODO  check on using BLI_array */
+		wmWidget **selected_widgets;
+		int tot_selected;
 
 		/* set while widget is highlighted/active */
 		wmWidgetGroup *activegroup;
diff --git a/source/blender/windowmanager/intern/wm_widgets.c b/source/blender/windowmanager/intern/wm_widgets.c
index 8d8c865..fef1158 100644
--- a/source/blender/windowmanager/intern/wm_widgets.c
+++ b/source/blender/windowmanager/intern/wm_widgets.c
@@ -41,6 +41,7 @@
 #include "MEM_guardedalloc.h"
 
 #include "BLI_listbase.h"
+#include "BLI_ghash.h"
 #include "BLI_string.h"
 #include "BLI_math.h"
 #include "BLI_path_util.h"
@@ -171,6 +172,31 @@ wmWidgetGroupType *WM_widgetgrouptype_new(
 	return wgrouptype;
 }
 
+/**
+ * Creates an idname hash table for all (visible) widgets with \a flag in \a wmap
+ */
+static GHash *wm_widgetgroup_widget_hash_new(
+        const bContext *C, wmWidgetMap *wmap,
+        const int flag, const bool visible_only)
+{
+	GHash *hash = BLI_ghash_str_new(__func__);
+
+	/* collect widgets */
+	for (wmWidgetGroup *wgroup = wmap->widgetgroups.first; wgroup; wgroup = wgroup->next) {
+		if (!wgroup->type->poll || wgroup->type->poll(C, wgroup->type)) {
+			for (wmWidget *widget = wgroup->widgets.first; widget; widget = widget->next) {
+				if ((!visible_only || (widget->flag & WM_WIDGET_HIDDEN) == 0) &&
+				    (flag == 0 || widget->flag & flag))
+				{
+					BLI_ghash_insert(hash, widget->idname, widget);
+				}
+			}
+		}
+	}
+
+	return hash;
+}
+
 wmWidget *WM_widget_new(void (*draw)(const bContext *C, wmWidget *customdata),
                         void (*render_3d_intersection)(const bContext *C, wmWidget *customdata, int selectionbase),
                         int  (*intersect)(bContext *C, const wmEvent *event, wmWidget *widget),
@@ -188,8 +214,10 @@ wmWidget *WM_widget_new(void (*draw)(const bContext *C, wmWidget *customdata),
 	return widget;
 }
 
-
-static void wm_widget_delete(ListBase *widgetlist, wmWidget *widget)
+/**
+ * Free widget data, not widget itself.
+ */
+static void wm_widget_data_free(wmWidget *widget)
 {
 	if (widget->opptr.data) {
 		WM_operator_properties_free(&widget->opptr);
@@ -197,7 +225,11 @@ static void wm_widget_delete(ListBase *widgetlist, wmWidget *widget)
 
 	MEM_freeN(widget->props);
 	MEM_freeN(widget->ptr);
+}
 
+static void wm_widget_delete(ListBase *widgetlist, wmWidget *widget)
+{
+	wm_widget_data_free(widget);
 	BLI_freelinkN(widgetlist, widget);
 }
 
@@ -242,6 +274,13 @@ BLI_INLINE bool widgets_compare(const wmWidget *a, const wmWidget *b)
 	return STREQ(a->idname, b->idname);
 }
 
+static void widget_highlight_update(wmWidgetMap *wmap, const wmWidget *old_, wmWidget *new_)
+{
+	new_->flag |= WM_WIDGET_HIGHLIGHT;
+	wmap->wmap_context.highlighted_widget = new_;
+	new_->highlighted_part = old_->highlighted_part;
+}
+
 void WM_widgets_update(const bContext *C, wmWidgetMap *wmap)
 {
 	wmWidget *widget;
@@ -249,12 +288,11 @@ void WM_widgets_update(const bContext *C, wmWidgetMap *wmap)
 	if (!wmap)
 		return;
 
-	if ((widget = wmap->wmap_context.selected_widget) ||
-	    (widget = wmap->wmap_context.active_widget))
-	{
+	if ((widget = wmap->wmap_context.active_widget)) {
 		widget_calculate_scale(widget, C);
 	}
 	else if (wmap->widgetgroups.first) {
+		GHash *hash = BLI_ghash_str_new(__func__);
 		wmWidgetGroup *wgroup;
 
 		for (wgroup = wmap->widgetgroups.first; wgroup; wgroup = wgroup->next) {
@@ -265,10 +303,12 @@ void WM_widgets_update(const bContext *C, wmWidgetMap *wmap)
 				for (widget = wgroup->widgets.first; widget;) {
 					wmWidget *widget_next = widget->next;
 
-					if (widget == wmap->wmap_context.selected_widget) {
-						/* skip */
+					/* do not delete selected and highlighted widgets,
+					 * keep them to compare with new ones */
+					if (widget->flag & WM_WIDGET_SELECTED) {
+						BLI_remlink(&wgroup->widgets, widget);
+						widget->next = widget->prev = NULL;
 					}
-					/* do not delete the highlighted widget, instead keep it to compare with the new one */
 					else if (widget->flag & WM_WIDGET_HIGHLIGHT) {
 						highlighted = widget;
 						BLI_remlink(&wgroup->widgets, widget);
@@ -287,9 +327,7 @@ void WM_widgets_update(const bContext *C, wmWidgetMap *wmap)
 				if (highlighted) {
 					for (widget = wgroup->widgets.first; widget; widget = widget->next) {
 						if (widgets_compare(widget, highlighted)) {
-							widget->flag |= WM_WIDGET_HIGHLIGHT;
-							wmap->wmap_context.highlighted_widget = widget;
-							widget->highlighted_part = highlighted->highlighted_part;
+							widget_highlight_update(wmap, highlighted, widget);
 							wm_widget_delete(&wgroup->widgets, highlighted);
 							highlighted = NULL;
 							break;
@@ -306,9 +344,36 @@ void WM_widgets_update(const bContext *C, wmWidgetMap *wmap)
 
 				for (widget = wgroup->widgets.first; widget; widget = widget->next) {
 					widget_calculate_scale(widget, C);
+					/* insert newly created widget into hash table */
+					BLI_ghash_insert(hash, widget->idname, widget);
 				}
 			}
 		}
+
+		if (wmap->wmap_context.selected_widgets) {
+			for (int i = 0; i < wmap->wmap_context.tot_selected; i++) {
+				wmWidget *sel_old = wmap->wmap_context.selected_widgets[i];
+				wmWidget *sel_new = BLI_ghash_lookup(hash, sel_old->idname);
+
+				/* fails if wgtype->poll state changed */
+				if (!sel_new)
+					continue;
+
+				BLI_assert(widgets_compare(sel_old, sel_new));
+
+				/* widget was selected and highlighted */
+				if (sel_old->flag & WM_WIDGET_HIGHLIGHT) {
+					widget_highlight_update(wmap, sel_old, sel_new);
+				}
+				wm_widget_data_free(sel_old);
+				/* XXX freeing sel_old leads to crashes, hrmpf */
+
+				sel_new->flag |= WM_WIDGET_SELECTED;
+				wmap->wmap_context.selected_widgets[i] = sel_new;
+			}
+		}
+
+		BLI_ghash_free(hash, NULL, NULL);
 	}
 }
 
@@ -348,9 +413,14 @@ void WM_widgets_draw(const bContext *C, const wmWidgetMap *wmap, const bool in_s
 		glPopMatrix();
 	}
 
+
+#define WIDGET_DRAW_POLL(widget_) \
+	(in_scene == ((widget_->flag & WM_WIDGET_SCENE_DEPTH) != 0)) && \
+	((widget_->flag & WM_WIDGET_HIDDEN) == 0)
+
 	widget = wmap->wmap_context.active_widget;
 
-	if (widget && in_scene == ((widget->flag & WM_WIDGET_SCENE_DEPTH) != 0)) {
+	if (widget && WIDGET_DRAW_POLL(widget)) {
 		if (widget->flag & WM_WIDGET_DRAW_ACTIVE) {
 			/* notice that we don't update the widgetgroup, widget is now on
 			 * its own, it should have all relevant data to update itself */
@@ -363,10 +433,9 @@ void WM_widgets_draw(const bContext *C, const wmWidgetMap *wmap, const bool in_s
 		for (wgroup = wmap->widgetgroups.first; wgroup; wgroup = wgroup->next) {
 			if (widgetgroup_poll_check(C, wgroup)) {
 				for (widget = wgroup->widgets.first; widget; widget = widget->next) {
-					if ((widget->flag & WM_WIDGET_HIDDEN) == 0 &&
-					    (!(widget->flag & WM_WIDGET_DRAW_HOVER) || (widget->flag & WM_WIDGET_HIGHLIGHT)) &&
+					if ((WIDGET_DRAW_POLL(widget)) &&
 					    ((widget->flag & WM_WIDGET_SELECTED) == 0) && /* selected is drawn later */
-					    ((widget->flag & WM_WIDGET_SCENE_DEPTH) != 0) == in_scene)
+					    ((widget->flag & WM_WIDGET_DRAW_HOVER) == 0 || (widget->flag & WM_WIDGET_HIGHLIGHT)))
 					{
 						widget->draw(C, widget);
 					}
@@ -376,11 +445,14 @@ void WM_widgets_draw(const bContext *C, const wmWidgetMap *wmap, const bool in_s
 	}
 
 	/* draw selected widgets last */
-	if ((widget = wmap->wmap_context.selected_widget) && in_scene == ((widget->flag & WM_WIDGET_SCENE_DEPTH) != 0)) {
-		if (widgetgroup_poll_check(C, widget->wgroup)) {
-			/* notice that we don't update the widgetgroup, widget is now on
-			 * its own, it should have all relevant data to update itself */
-			widget->draw(C, widget);
+	if (wmap->wmap_context.selected_widgets) {
+		for (int i = 0; i < wmap->wmap_context.tot_selected; i++) {
+			widget = wmap->wmap_context.selected_widgets[i];
+			if (widgetgroup_poll_check(C, widget->wgroup) && WIDGET_DRAW_POLL(widget)) {
+				/* notice that we don't update the widgetgroup, widget is now on
+				 * its own, it should have all relevant data to update itself */
+				widget->draw(C, widget);
+			}
 		}
 	}
 
@@ -635,7 +707,7 @@ static int widget_set_select_invoke(bContext *C, wmOperator *UNUSED(op), const w
 		wmWidget *widget = wmap->wmap_context.highlighted_widget;
 		if (widget) {
 			if (widget->flag & WM_WIDGET_SELECTABLE) {
-				wm_widgetmap_set_selected_widget(C, wmap, widget);
+				wm_widgetmap_select_widget(C, wmap, widget);
 				return OPERATOR_FINISHED;
 			}
 			break;
@@ -1045,67 +1117,87 @@ void wm_widgetmap_set_active_widget(
 		}
 		wmap->wmap_context.active_widget = NULL;
 
-		if (C) {
-			ARegion *ar = CTX_wm_region(C);
-			ED_region_tag_redraw(ar);
-			WM_event_add_mousemove(C);
-		}
+		ED_region_tag_redraw(CTX_wm_region(C));
+		WM_event_add_mousemove(C);
 	}
 }
 
-wmWidget *wm_widgetmap_get_selected_widget(wmWidgetMap *wmap)
+/**
+ * Deselect all selected widgets in \a wmap.
+ * \return if selection has changed.
+ */
+static bool wm_widgetmap_deselect_all(wmWidgetMap *wmap, wmWidget ***sel)
 {
-	return wmap->wmap_context.selected_widget;
+	if (*sel == NULL || wmap->wmap_context.tot_selected == 0)
+		return false;
+
+	for (int i = 0; i < wmap->wmap_context.tot_selected; i++) {
+		(*sel)[i]->flag &= ~WM_WIDGET_SELECTED;
+		(*sel)[i] = NULL;
+	}
+	MEM_SAFE_FREE(*sel);
+	wmap->wmap_context.tot_selected = 0;
+
+	/* always return true, we already checked
+	 * if there's anything to deselect */
+	return true;
 }
 
-void wm_widgetmap_set_selected_wi

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list