diff options
Diffstat (limited to 'source/blender/windowmanager')
-rw-r--r-- | source/blender/windowmanager/WM_api.h | 60 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_types.h | 23 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm.c | 1 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_event_system.c | 92 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_generic_widgets.c | 550 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_operators.c | 6 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_widgets.c | 566 | ||||
-rw-r--r-- | source/blender/windowmanager/wm.h | 44 | ||||
-rw-r--r-- | source/blender/windowmanager/wm_event_system.h | 17 |
9 files changed, 974 insertions, 385 deletions
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index f0dbc4d4108..15a3a35b00b 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -506,31 +506,48 @@ struct wmWidget *WM_widget_new(void (*draw)(const struct bContext *, struct wmWi int (*intersect)(struct bContext *, const struct wmEvent *, struct wmWidget *), int (*handler)(struct bContext *, const struct wmEvent *, struct wmWidget *)); -void WM_widget_property(struct wmWidget *, int slot, struct PointerRNA *ptr, const char *propname); -struct PointerRNA *WM_widget_operator(struct wmWidget *, const char *opname); -void WM_widgets_update(const struct bContext *C, struct wmWidgetMap *wmap); -void WM_widgets_draw(const struct bContext *C, const struct wmWidgetMap *wmap, const bool in_scene); -void WM_event_add_area_widgetmap_handlers(struct ARegion *ar); -void WM_modal_handler_attach_widgetgroup(struct bContext *C, struct wmEventHandler *handler, - struct wmWidgetGroupType *wgrouptype, struct wmOperator *op); -void WM_widgetgroup_customdata_set(struct wmWidgetGroup *wgroup, void *data); +void WM_widgets_update(const struct bContext *C, struct wmWidgetMap *wmap); +void WM_widgets_draw(const struct bContext *C, const struct wmWidgetMap *wmap, const bool in_scene); +void WM_event_add_area_widgetmap_handlers(struct ARegion *ar); +void WM_modal_handler_attach_widgetgroup(struct bContext *C, struct wmEventHandler *handler, + struct wmWidgetGroupType *wgrouptype, struct wmOperator *op); +void WM_widgetgroup_customdata_set(struct wmWidgetGroup *wgroup, void *data); void *WM_widgetgroup_customdata(const struct wmWidgetGroup *wgroup); +/* wmWidget->flag */ +enum widgetflags { + /* states */ + WM_WIDGET_HIGHLIGHT = (1 << 0), + WM_WIDGET_ACTIVE = (1 << 1), + WM_WIDGET_SELECTED = (1 << 2), + /* settings */ + WM_WIDGET_DRAW_HOVER = (1 << 3), + WM_WIDGET_DRAW_ACTIVE = (1 << 4), /* draw while dragging */ + WM_WIDGET_SCALE_3D = (1 << 5), + WM_WIDGET_SCENE_DEPTH = (1 << 6), /* widget is depth culled with scene objects*/ + WM_WIDGET_HIDDEN = (1 << 7), + WM_WIDGET_SELECTABLE = (1 << 8), +}; + +void WM_widget_set_property(struct wmWidget *, int slot, struct PointerRNA *ptr, const char *propname); +struct PointerRNA *WM_widget_set_operator(struct wmWidget *, const char *opname); void WM_widget_set_origin(struct wmWidget *widget, const float origin[3]); -void WM_widget_set_3d_scale(struct wmWidget *widget, const bool scale); -void WM_widget_flag_set(struct wmWidget *widget, const int flag, const bool enable); -void WM_widget_set_draw_on_hover_only(struct wmWidget *widget, const bool draw); -void WM_widget_set_scene_depth(struct wmWidget *widget, const bool scene); +void WM_widget_set_offset(struct wmWidget *widget, const float offset[3]); +void WM_widget_set_flag(struct wmWidget *widget, const int flag, const bool enable); void WM_widget_set_scale(struct wmWidget *widget, float scale); void WM_widget_set_line_width(struct wmWidget *widget, const float line_width); void WM_widget_set_colors(struct wmWidget *widget, const float col[4], const float col_hi[4]); +wmKeyMap *WM_widgetgroup_keymap_common(wmKeyConfig *config, const char *wgroupname); + struct wmWidgetMapType *WM_widgetmaptype_find(const char *idname, const int spaceid, const int regionid, const bool is_3d, const bool create); -struct wmWidgetGroupType *WM_widgetgrouptype_new(int (*poll)(const struct bContext *, struct wmWidgetGroupType *), - void (*create)(const struct bContext *, struct wmWidgetGroup *), - const struct Main *bmain, const char *mapidname, - const short spaceid, const short regionid, const bool is_3d); +struct wmWidgetGroupType *WM_widgetgrouptype_new( + int (*poll)(const struct bContext *, struct wmWidgetGroupType *), + void (*create)(const struct bContext *, struct wmWidgetGroup *), + wmKeyMap *(*keymap_init)(wmKeyConfig *, const char *), + const struct Main *bmain, const char *mapidname, const char *name, + const short spaceid, const short regionid, const bool is_3d); void WM_widgetgrouptype_unregister(struct bContext *C, struct Main *bmain, struct wmWidgetGroupType *wgroup); /* creates a widgetmap with all registered widgets for that type */ @@ -549,6 +566,7 @@ enum { WIDGET_ARROW_STYLE_INVERTED = (1 << 3), /* inverted offset during interaction - if set it also sets constrained below */ WIDGET_ARROW_STYLE_CONSTRAINED = (1 << 4), /* clamp arrow interaction to property width */ WIDGET_ARROW_STYLE_BOX = (1 << 5), /* use a box for the arrowhead */ + WIDGET_ARROW_STYLE_CONE = (1 << 6), }; enum { @@ -580,21 +598,21 @@ enum { struct wmWidget *WIDGET_arrow_new(struct wmWidgetGroup *wgroup, const char *name, const int style); void WIDGET_arrow_set_direction(struct wmWidget *widget, const float direction[3]); void WIDGET_arrow_set_up_vector(struct wmWidget *widget, const float direction[3]); -void WIDGET_arrow_set_line_vec(struct wmWidget *widget, const float (*vec)[3], const int tot_points); -void WIDGET_arrow_set_scale(struct wmWidget *widget, const float scale); +void WIDGET_arrow_set_line_len(struct wmWidget *widget, const float len); +void WIDGET_arrow_set_ui_range(struct wmWidget *widget, const float min, const float max); +void WIDGET_arrow_set_range_fac(struct wmWidget *widget, const float range_fac); +void WIDGET_arrow_cone_set_aspect(struct wmWidget *widget, const float aspect[2]); struct wmWidget *WIDGET_dial_new(struct wmWidgetGroup *wgroup, const char *name, const int style); -void WIDGET_dial_set_direction(struct wmWidget *widget, const float direction[3]); +void WIDGET_dial_set_up_vector(struct wmWidget *widget, const float direction[3]); struct wmWidget *WIDGET_plane_new(struct wmWidgetGroup *wgroup, const char *name, const int style); void WIDGET_plane_set_direction(struct wmWidget *widget, const float direction[3]); -void WIDGET_plane_set_offset(struct wmWidget *widget, const float offset[3]); void WIDGET_plane_set_up_vector(struct wmWidget *widget, const float direction[3]); struct wmWidget *WIDGET_rect_transform_new( struct wmWidgetGroup *wgroup, const char *name, const int style, const float width, const float height); -void WIDGET_rect_transform_set_offset(struct wmWidget *widget, const float offset[2]); struct wmWidget *WIDGET_facemap_new( struct wmWidgetGroup *wgroup, const char *name, const int style, diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 248f5760720..3e43047c96c 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -108,6 +108,8 @@ extern "C" { struct bContext; struct wmEvent; +struct wmKeyMap; +struct wmKeyConfig; struct wmWindowManager; struct wmOperator; struct ImBuf; @@ -672,18 +674,17 @@ typedef struct wmDropBox { /* WidgetGroups store and manage groups of widgets. - * They are responsible for drawing necessary widgets and updating their state and position. - * Also they */ + * They are responsible for drawing necessary widgets and updating their state and position. */ typedef struct wmWidget wmWidget; typedef struct wmWidgetGroup wmWidgetGroup; typedef struct wmWidgetMapType wmWidgetMapType; -typedef struct wmWidgetGroupType wmWidgetGroupType; /* factory class for a widgetgroup type, gets called every time a new area is spawned */ typedef struct wmWidgetGroupType { struct wmWidgetGroupType *next, *prev; char idname[64]; /* MAX_NAME */ + char name[64]; /* widget group name - displayed in UI (keymap editor) */ /* poll if widgetmap should be active */ int (*poll)(const struct bContext *C, struct wmWidgetGroupType *wgrouptype) ATTR_WARN_UNUSED_RESULT; @@ -691,6 +692,12 @@ typedef struct wmWidgetGroupType { /* update widgets, called right before drawing */ void (*create)(const struct bContext *C, struct wmWidgetGroup *wgroup); + /* keymap init callback for this widgetgroup */ + struct wmKeyMap *(*keymap_init)(struct wmKeyConfig *, const char *); + + /* keymap created with callback from above */ + struct wmKeyMap *keymap; + /* rna for properties */ struct StructRNA *srna; @@ -711,16 +718,18 @@ typedef struct wmWidgetGroupType { typedef struct wmWidgetMap { struct wmWidgetMap *next, *prev; - + struct wmWidgetMapType *type; ListBase widgetgroups; - + /* highlighted widget for this map. We redraw the widgetmap when this changes */ struct wmWidget *highlighted_widget; /* active widget for this map. User has clicked currently this widget and it gets all input */ struct wmWidget *active_widget; - - /* active group is overriding all other widgets while active */ + /* selected widget for this map. */ + struct wmWidget *selected_widget; + + /* active group - set while widget is highlighted/active */ struct wmWidgetGroup *activegroup; } wmWidgetMap; diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index fd46d9bd1d0..4b3d66b9e71 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -342,6 +342,7 @@ void WM_keymap_init(bContext *C) * it's persistent across sessions */ if (!(wm->defaultconf->flag & KEYCONF_INIT_DEFAULT)) { wm_window_keymap(wm->defaultconf); + wm_widgets_keymap(wm->defaultconf); ED_spacetypes_keymap(wm->defaultconf); wm->defaultconf->flag |= KEYCONF_INIT_DEFAULT; diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 2a9de6f5029..98f88c9a081 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1697,6 +1697,9 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand CTX_wm_region_set(C, NULL); } + /* update widgets during modal handlers */ + wm_widget_handler_modal_update(C, event, handler); + /* remove modal handler, operator itself should have been canceled and freed */ if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) { WM_cursor_grab_disable(CTX_wm_window(C), NULL); @@ -1933,6 +1936,9 @@ static int wm_action_not_handled(int action) return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK | WM_HANDLER_MODAL); } +/* use old, hardcoded widget map handling - kept in case new one doesn't work out */ +//#define USE_OLD_WIDGETMAP_HANDLING + static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers) { #ifndef NDEBUG @@ -2063,16 +2069,59 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers } } else if (handler->widgetmap) { - wmWidgetMap *wmap = handler->widgetmap; - unsigned char part; - short event_processed = 0; - wmWidget *widget = wm_widgetmap_get_active_widget(wmap); ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); + wmWidgetMap *wmap = handler->widgetmap; + wmWidget *widget = wm_widgetmap_get_highlighted_widget(wmap); + short event_processed = 0; + unsigned char part; wm_widgetmap_handler_context(C, handler); wm_region_mouse_co(C, event); +#ifndef USE_OLD_WIDGETMAP_HANDLING + /* handle widget highlighting */ + if (event->type == MOUSEMOVE && !wm_widgetmap_get_active_widget(wmap)) { + if (wm_widgetmap_is_3d(wmap)) { + widget = wm_widget_find_highlighted_3D(wmap, C, event, &part); + wm_widgetmap_set_highlighted_widget(wmap, C, widget, part); + } + else { + widget = wm_widget_find_highlighted(wmap, C, event, &part); + wm_widgetmap_set_highlighted_widget(wmap, C, widget, part); + } + } + /* handle user configurable widgetmap keymap */ + else if (widget && wmap->activegroup) { + /* get user customized keymap from default one */ + const wmKeyMap *keymap = WM_keymap_active(wm, wmap->activegroup->type->keymap); + wmKeyMapItem *kmi; + + if (!keymap->poll || keymap->poll(C)) { + for (kmi = keymap->items.first; kmi; kmi = kmi->next) { + if (wm_eventmatch(event, kmi)) { + wmOperator *op = handler->op; + + /* weak, but allows interactive callback to not use rawkey */ + event->keymap_idname = kmi->idname; + + /* handler->op is called later, we want keymap op to be triggered here */ + handler->op = NULL; + action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr); + handler->op = op; + + if (action & WM_HANDLER_BREAK) { + break; + } + } + } + } + } + + UNUSED_VARS(event_processed); +#else + widget = wm_widgetmap_get_active_widget(wmap); + /* handle the widget first, before passing the event down */ switch (event->type) { case MOUSEMOVE: @@ -2090,12 +2139,11 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers wm_widgetmap_set_highlighted_widget(wmap, C, widget, part); } break; - case LEFTMOUSE: - { if (widget) { if (event->val == KM_RELEASE) { wm_widgetmap_set_active_widget(wmap, C, event, NULL, false); + wm_widgetmap_set_selected_widget(C, wmap, NULL); event_processed = EVT_WIDGET_RELEASED; action |= WM_HANDLER_BREAK; } @@ -2112,27 +2160,51 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers } } break; + case RIGHTMOUSE: + case ESCKEY: + { + wmWidget *highlight = wm_widgetmap_get_highlighted_widget(wmap); + if (event->type == RIGHTMOUSE && highlight) { + if (highlight->flag & WM_WIDGET_SELECTABLE) { + if (event->val == KM_RELEASE) { + wm_widgetmap_set_selected_widget(C, wmap, highlight); + action |= WM_HANDLER_BREAK; + } + } + } + else if (widget) { + if (widget->cancel) { + widget->cancel(C, widget); + } + wm_widgetmap_set_active_widget(wmap, C, event, NULL, false); + event_processed = EVT_WIDGET_RELEASED; + action |= WM_HANDLER_BREAK; + } + else { + wm_widgetmap_set_selected_widget(C, wmap, NULL); + } + break; } } - +#endif + /* restore the area */ CTX_wm_area_set(C, area); CTX_wm_region_set(C, region); if (handler->op) { +#ifdef USE_OLD_WIDGETMAP_HANDLING /* if event was processed by an active widget pass the modified event to the operator */ if (event_processed) { event->type = event_processed; } +#endif action |= wm_handler_operator_call(C, handlers, handler, event, NULL); } } else { /* modal, swallows all */ action |= wm_handler_operator_call(C, handlers, handler, event, NULL); - - /* update widgets during modal handlers */ - wm_widget_handler_modal_update(C, event, handler); } if (action & WM_HANDLER_BREAK) { diff --git a/source/blender/windowmanager/intern/wm_generic_widgets.c b/source/blender/windowmanager/intern/wm_generic_widgets.c index e56d415e700..7e26c086ba0 100644 --- a/source/blender/windowmanager/intern/wm_generic_widgets.c +++ b/source/blender/windowmanager/intern/wm_generic_widgets.c @@ -15,7 +15,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2009 Blender Foundation. + * The Original Code is Copyright (C) 2014 Blender Foundation. * All rights reserved. * * Contributor(s): Blender Foundation @@ -23,8 +23,12 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/editors/interface/interface_generic_widgets.c - * \ingroup edinterface +/** \file blender/windowmanager/intern/wm_generic_widgets.c + * \ingroup wm + * + * ***************************************************** + * GENERIC WIDGET LIBRARY + * ***************************************************** */ #include "RNA_types.h" @@ -69,17 +73,15 @@ #include "WM_types.h" -/****************************************************** - * GENERIC WIDGET LIBRARY * - ******************************************************/ - - /* to use custom arrows exported to arrow_widget.c */ //#define WIDGET_USE_CUSTOM_ARROWS -/* to use custom dials exported to arrow_widget.c */ +/* to use custom dials exported to dial_widget.c */ //#define WIDGET_USE_CUSTOM_DIAS +/* -------------------------------------------------------------------- */ +/* Widget drawing */ + typedef struct WidgetDrawInfo { int nverts; int ntris; @@ -151,24 +153,43 @@ static void widget_draw_intern(WidgetDrawInfo *info, const bool select) } } -/********* Arrow widget ************/ -#define ARROW_UP_VECTOR_SET 1 +/* -------------------------------------------------------------------- */ +/* Widget defines */ + +/** \name Arrow Widget + * + * 3D Widget + * + * \brief Simple arrow widget which is dragged into a certain direction. + * The arrow head can have have varying shapes, e.g. cone, box, etc. + * + * \{ */ + +/* ArrowWidget->flag */ +enum { + ARROW_UP_VECTOR_SET = (1 << 0), + ARROW_CUSTOM_RANGE_SET = (1 << 1), +}; typedef struct ArrowWidget { wmWidget widget; int style; int flag; + + float len; /* arrow line length */ float direction[3]; float up[3]; - float (*line)[3]; /* custom coords for arrow line drawing */ - int tot_line_points; /* amount of points for arrow line drawing */ + float aspect[2]; /* cone style only */ + + float range_fac; /* factor for arrow min/max distance */ float offset; /* property range and minimum for constrained arrows */ float range, min; } ArrowWidget; typedef struct ArrowInteraction { + float orig_value; /* initial property value */ float orig_origin[3]; float orig_mouse[2]; float orig_offset; @@ -203,41 +224,80 @@ static void arrow_draw_geom(const ArrowWidget *arrow, const bool select) glPopAttrib(); } + else if (arrow->style & WIDGET_ARROW_STYLE_CONE) { + const float unitx = arrow->aspect[0]; + const float unity = arrow->aspect[1]; + const float vec[4][3] = { + {-unitx, -unity, 0}, + { unitx, -unity, 0}, + { unitx, unity, 0}, + {-unitx, unity, 0}, + }; + + glLineWidth(arrow->widget.line_width); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, vec); + glDrawArrays(GL_LINE_LOOP, 0, ARRAY_SIZE(vec)); + glDisableClientState(GL_VERTEX_ARRAY); + glLineWidth(1.0); + } else { #ifdef WIDGET_USE_CUSTOM_ARROWS widget_draw_intern(&arrow_head_draw_info, select); #else + const float vec[2][3] = { + {0.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, arrow->len}, + }; + glLineWidth(arrow->widget.line_width); glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, arrow->line); - glDrawArrays(GL_LINES, 0, arrow->tot_line_points); + glVertexPointer(3, GL_FLOAT, 0, vec); + glDrawArrays(GL_LINE_STRIP, 0, ARRAY_SIZE(vec)); glDisableClientState(GL_VERTEX_ARRAY); glLineWidth(1.0); - /* draw arrow head */ - glTranslatef(UNPACK3(arrow->line[arrow->tot_line_points - 1])); + /* *** draw arrow head *** */ + + glPushMatrix(); if (arrow->style & WIDGET_ARROW_STYLE_BOX) { const float size = 0.05f; - /* draw cube */ + /* translate to line end with some extra offset so box starts exactly where line ends */ + glTranslatef(0.0f, 0.0f, arrow->len + size); + /* scale down to box size */ glScalef(size, size, size); + + /* draw cube */ widget_draw_intern(&cube_draw_info, select); } else { GLUquadricObj *qobj = gluNewQuadric(); const float len = 0.25f; const float width = 0.06f; + const bool use_lighting = select == false && ((U.tw_flag & V3D_SHADED_WIDGETS) != 0); + + /* translate to line end */ + glTranslatef(0.0f, 0.0f, arrow->len); + + if (use_lighting) { + glShadeModel(GL_SMOOTH); + } gluQuadricDrawStyle(qobj, GLU_FILL); - gluCylinder(qobj, width, 0.0, len, 8, 1); gluQuadricOrientation(qobj, GLU_INSIDE); gluDisk(qobj, 0.0, width, 8, 1); gluQuadricOrientation(qobj, GLU_OUTSIDE); + gluCylinder(qobj, width, 0.0, len, 8, 1); + + if (use_lighting) { + glShadeModel(GL_FLAT); + } } - (void)select; + glPopMatrix(); #endif } @@ -276,6 +336,7 @@ static void arrow_draw_intern(ArrowWidget *arrow, const bool select, const bool } glEnable(GL_BLEND); + glTranslate3fv(arrow->widget.offset); arrow_draw_geom(arrow, select); glDisable(GL_BLEND); @@ -293,8 +354,8 @@ static void arrow_draw_intern(ArrowWidget *arrow, const bool select, const bool glEnable(GL_BLEND); glColor4f(0.5f, 0.5f, 0.5f, 0.5f); + glTranslate3fv(arrow->widget.offset); arrow_draw_geom(arrow, select); - glDisable(GL_BLEND); glPopMatrix(); @@ -312,7 +373,11 @@ static void widget_arrow_draw(const bContext *UNUSED(C), wmWidget *widget) arrow_draw_intern((ArrowWidget *)widget, false, (widget->flag & WM_WIDGET_HIGHLIGHT) != 0); } -#define ARROW_RANGE 1.5f +/** + * Calculate arrow offset independent from prop min value, + * meaning the range will not be offset by min value first. + */ +#define USE_ABS_HANDLE_RANGE static int widget_arrow_handler(bContext *C, const wmEvent *event, wmWidget *widget) { @@ -330,6 +395,7 @@ static int widget_arrow_handler(bContext *C, const wmEvent *event, wmWidget *wid float facdir = 1.0f; bool use_vertical = false; + copy_v3_v3(orig_origin, data->orig_origin); orig_origin[3] = 1.0f; add_v3_v3v3(offset, orig_origin, arrow->direction); @@ -403,14 +469,24 @@ static int widget_arrow_handler(bContext *C, const wmEvent *event, wmWidget *wid if (widget->props[ARROW_SLOT_OFFSET_WORLD_SPACE]) { PointerRNA ptr = widget->ptr[ARROW_SLOT_OFFSET_WORLD_SPACE]; PropertyRNA *prop = widget->props[ARROW_SLOT_OFFSET_WORLD_SPACE]; + float max = arrow->min + arrow->range; float value; value = data->orig_offset + facdir * len_v3(offset); if (arrow->style & WIDGET_ARROW_STYLE_CONSTRAINED) { if (arrow->style & WIDGET_ARROW_STYLE_INVERTED) - value = arrow->min + arrow->range - (value * arrow->range / ARROW_RANGE); + value = max - (value * arrow->range / arrow->range_fac); else - value = arrow->min + (value * arrow->range / ARROW_RANGE); +#ifdef USE_ABS_HANDLE_RANGE + value = value * arrow->range / arrow->range_fac; +#else + value = arrow->min + (value * arrow->range / arrow->range_fac); +#endif + } + + /* clamp to custom range */ + if (arrow->flag & ARROW_CUSTOM_RANGE_SET) { + CLAMP(value, arrow->min, max); } RNA_property_float_set(&ptr, prop, value); @@ -421,9 +497,13 @@ static int widget_arrow_handler(bContext *C, const wmEvent *event, wmWidget *wid /* accounts for clamping properly */ if (arrow->style & WIDGET_ARROW_STYLE_CONSTRAINED) { if (arrow->style & WIDGET_ARROW_STYLE_INVERTED) - arrow->offset = ARROW_RANGE * (arrow->min + arrow->range - value) / arrow->range; + arrow->offset = arrow->range_fac * (max - value) / arrow->range; else - arrow->offset = ARROW_RANGE * ((value - arrow->min) / arrow->range); +#ifdef USE_ABS_HANDLE_RANGE + arrow->offset = arrow->range_fac * (value / arrow->range); +#else + arrow->offset = arrow->range_fac * ((value - arrow->min) / arrow->range); +#endif } else arrow->offset = value; @@ -443,6 +523,12 @@ static int widget_arrow_invoke(bContext *UNUSED(C), const wmEvent *event, wmWidg { ArrowWidget *arrow = (ArrowWidget *) widget; ArrowInteraction *data = MEM_callocN(sizeof(ArrowInteraction), "arrow_interaction"); + PointerRNA ptr = widget->ptr[ARROW_SLOT_OFFSET_WORLD_SPACE]; + PropertyRNA *prop = widget->props[ARROW_SLOT_OFFSET_WORLD_SPACE]; + + if (prop) { + data->orig_value = RNA_property_float_get(&ptr, prop); + } data->orig_offset = arrow->offset; @@ -465,20 +551,29 @@ static void widget_arrow_bind_to_prop(wmWidget *widget, const int UNUSED(slot)) PropertyRNA *prop = widget->props[ARROW_SLOT_OFFSET_WORLD_SPACE]; if (prop) { - const float float_prop = RNA_property_float_get(&ptr, prop); + float float_prop = RNA_property_float_get(&ptr, prop); if (arrow->style & WIDGET_ARROW_STYLE_CONSTRAINED) { float min, max, step, precision; - RNA_property_float_ui_range(&ptr, prop, &min, &max, &step, &precision); - arrow->range = max - min; - arrow->min = min; + if (arrow->flag & ARROW_CUSTOM_RANGE_SET) { + max = arrow->min + arrow->range; + } + else { + RNA_property_float_ui_range(&ptr, prop, &min, &max, &step, &precision); + arrow->range = max - min; + arrow->min = min; + } if (arrow->style & WIDGET_ARROW_STYLE_INVERTED) { - arrow->offset = ARROW_RANGE * (max - float_prop) / arrow->range; + arrow->offset = arrow->range_fac * (max - float_prop) / arrow->range; } else { - arrow->offset = ARROW_RANGE * ((float_prop - arrow->min) / arrow->range); +#ifdef USE_ABS_HANDLE_RANGE + arrow->offset = arrow->range_fac * (float_prop / arrow->range); +#else + arrow->offset = arrow->range_fac * ((float_prop - arrow->min) / arrow->range); +#endif } } else { @@ -490,14 +585,25 @@ static void widget_arrow_bind_to_prop(wmWidget *widget, const int UNUSED(slot)) arrow->offset = 0.0f; } +static void widget_arrow_cancel(bContext *C, wmWidget *widget) +{ + PointerRNA ptr = widget->ptr[ARROW_SLOT_OFFSET_WORLD_SPACE]; + PropertyRNA *prop = widget->props[ARROW_SLOT_OFFSET_WORLD_SPACE]; + ArrowInteraction *data = widget->interaction_data; + + /* reset property */ + RNA_property_float_set(&ptr, prop, data->orig_value); + RNA_property_update(C, &ptr, prop); +} + +/** \name Arrow Widget API + * + * \{ */ + wmWidget *WIDGET_arrow_new(wmWidgetGroup *wgroup, const char *name, const int style) { ArrowWidget *arrow = MEM_callocN(sizeof(ArrowWidget), name); const float dir_default[3] = {0.0f, 0.0f, 1.0f}; - const float line_default[2][3] = { - {0.0f, 0.0f, 0.0f}, - {0.0f, 0.0f, 1.0f} - }; int real_style = style; #ifdef WIDGET_USE_CUSTOM_ARROWS @@ -532,29 +638,33 @@ wmWidget *WIDGET_arrow_new(wmWidgetGroup *wgroup, const char *name, const int st arrow->widget.invoke = widget_arrow_invoke; arrow->widget.render_3d_intersection = widget_arrow_render_3d_intersect; arrow->widget.bind_to_prop = widget_arrow_bind_to_prop; - arrow->widget.flag |= WM_WIDGET_SCALE_3D; + arrow->widget.cancel = widget_arrow_cancel; + arrow->widget.flag |= (WM_WIDGET_SCALE_3D | WM_WIDGET_DRAW_ACTIVE); arrow->style = real_style; - - /* defaults */ + arrow->len = 1.0f; + arrow->range_fac = 1.0f; copy_v3_v3(arrow->direction, dir_default); - arrow->tot_line_points = ARRAY_SIZE(line_default); - arrow->line = MEM_mallocN(sizeof(line_default), __func__); - memcpy(arrow->line, line_default, sizeof(line_default)); wm_widget_register(wgroup, &arrow->widget, name); return (wmWidget *)arrow; } +/** + * Define direction the arrow will point towards + */ void WIDGET_arrow_set_direction(wmWidget *widget, const float direction[3]) { ArrowWidget *arrow = (ArrowWidget *)widget; - + copy_v3_v3(arrow->direction, direction); normalize_v3(arrow->direction); } +/** + * Define up-direction of the arrow widget + */ void WIDGET_arrow_set_up_vector(wmWidget *widget, const float direction[3]) { ArrowWidget *arrow = (ArrowWidget *)widget; @@ -570,20 +680,67 @@ void WIDGET_arrow_set_up_vector(wmWidget *widget, const float direction[3]) } /** - * Define a custom coord vec for arrow line drawing + * Define a custom arrow line length + */ +void WIDGET_arrow_set_line_len(wmWidget *widget, const float len) +{ + ArrowWidget *arrow = (ArrowWidget *)widget; + arrow->len = len; +} + +/** + * Define a custom property UI range + * + * \note Needs to be called before WM_widget_set_property! + */ +void WIDGET_arrow_set_ui_range(wmWidget *widget, const float min, const float max) +{ + ArrowWidget *arrow = (ArrowWidget *)widget; + + BLI_assert(min < max); + BLI_assert(!(arrow->widget.props[0] && "Make sure this function is called before WM_widget_set_property")); + + arrow->range = max - min; + arrow->min = min; + arrow->flag |= ARROW_CUSTOM_RANGE_SET; +} + +/** + * Define a custom factor for arrow min/max distance + * + * \note Needs to be called before WM_widget_set_property! + */ +void WIDGET_arrow_set_range_fac(wmWidget *widget, const float range_fac) +{ + ArrowWidget *arrow = (ArrowWidget *)widget; + + BLI_assert(!(arrow->widget.props[0] && "Make sure this function is called before WM_widget_set_property")); + + arrow->range_fac = range_fac; +} + +/** + * Define xy-aspect for arrow cone */ -void WIDGET_arrow_set_line_vec(wmWidget *widget, const float (*vec)[3], const int tot_points) +void WIDGET_arrow_cone_set_aspect(wmWidget *widget, const float aspect[2]) { ArrowWidget *arrow = (ArrowWidget *)widget; - const size_t vec_size = 3 * tot_points * sizeof(float); - arrow->tot_line_points = tot_points; - arrow->line = MEM_reallocN(arrow->line, vec_size); - memcpy(arrow->line, vec, vec_size); + copy_v2_v2(arrow->aspect, aspect); } +/** \} */ // Arrow Widget API +/** \} */ // Arrow Widget + -/********* Dial widget ************/ +/** \name Dial Widget + * + * 3D Widget + * + * \brief Circle shaped widget for circular interaction. + * Currently no own handling, use with operator only. + * + * \{ */ typedef struct DialWidget { wmWidget widget; @@ -593,24 +750,23 @@ typedef struct DialWidget { static void dial_draw_geom(const DialWidget *dial, const bool select) { +#ifdef WIDGET_USE_CUSTOM_DIAS + glEnable(GL_MULTISAMPLE_ARB); + + widget_draw_intern(&dial_draw_info, select); +#else GLUquadricObj *qobj = gluNewQuadric(); const float width = 1.0f; const int resol = 32; glEnable(GL_MULTISAMPLE_ARB); -#ifdef WIDGET_USE_CUSTOM_DIAS - widget_draw_intern(&dial_draw_info, select); - - (void)qobj; (void)width; (void)resol; -#else - glLineWidth(dial->widget.line_width); gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); gluDisk(qobj, 0.0, width, resol, 1); glLineWidth(1.0); - (void)select; + UNUSED_VARS(select); #endif glDisable(GL_MULTISAMPLE_ARB); @@ -635,6 +791,7 @@ static void dial_draw_intern(DialWidget *dial, const bool select, const bool hig else glColor4fv(dial->widget.col); + glTranslate3fv(dial->widget.offset); dial_draw_geom(dial, select); glPopMatrix(); @@ -688,6 +845,10 @@ static void widget_dial_draw(const bContext *C, wmWidget *widget) } } +/** \name Dial Widget API + * + * \{ */ + wmWidget *WIDGET_dial_new(wmWidgetGroup *wgroup, const char *name, const int style) { DialWidget *dial = MEM_callocN(sizeof(DialWidget), name); @@ -719,7 +880,10 @@ wmWidget *WIDGET_dial_new(wmWidgetGroup *wgroup, const char *name, const int sty return (wmWidget *)dial; } -void WIDGET_dial_set_direction(wmWidget *widget, const float direction[3]) +/** + * Define up-direction of the dial widget + */ +void WIDGET_dial_set_up_vector(wmWidget *widget, const float direction[3]) { DialWidget *dial = (DialWidget *)widget; @@ -727,21 +891,32 @@ void WIDGET_dial_set_direction(wmWidget *widget, const float direction[3]) normalize_v3(dial->direction); } -/********* Plane widget ************/ +/** \} */ // Dial Widget API +/** \} */ // Dial Widget + +/** \name Plane Widget + * + * 3D Widget + * + * \brief Flat and rectangular shaped widget for planar interaction. + * Currently no own handling, use with operator only. + * + * \{ */ + +/* PlaneWidget->flag */ #define PLANE_UP_VECTOR_SET 1 typedef struct PlaneWidget { wmWidget widget; float direction[3]; - float offset[3]; float up[3]; int flag; } PlaneWidget; -static void widget_plane_draw_geom(const float ofs[3], const float col_inner[4], const float col_outer[4]) +static void widget_plane_draw_geom(const float col_inner[4], const float col_outer[4]) { static float vec[4][3] = { {-1, -1, 0}, @@ -750,8 +925,6 @@ static void widget_plane_draw_geom(const float ofs[3], const float col_inner[4], {-1, 1, 0}, }; - glTranslatef(UNPACK3(ofs)); - glEnable(GL_MULTISAMPLE_ARB); glEnableClientState(GL_VERTEX_ARRAY); @@ -799,7 +972,8 @@ static void widget_plane_draw_intern(PlaneWidget *plane, const bool UNUSED(selec col_inner[3] *= 0.5f; glEnable(GL_BLEND); - widget_plane_draw_geom(plane->offset, col_inner, col_outer); + glTranslate3fv(plane->widget.offset); + widget_plane_draw_geom(col_inner, col_outer); glDisable(GL_BLEND); glPopMatrix(); @@ -816,6 +990,10 @@ static void widget_plane_draw(const bContext *UNUSED(C), wmWidget *widget) widget_plane_draw_intern((PlaneWidget *)widget, false, (widget->flag & WM_WIDGET_HIGHLIGHT)); } +/** \name Plane Widget API + * + * \{ */ + wmWidget *WIDGET_plane_new(wmWidgetGroup *wgroup, const char *name, const int UNUSED(style)) { PlaneWidget *plane = MEM_callocN(sizeof(PlaneWidget), name); @@ -828,13 +1006,15 @@ wmWidget *WIDGET_plane_new(wmWidgetGroup *wgroup, const char *name, const int UN /* defaults */ copy_v3_v3(plane->direction, dir_default); - zero_v3(plane->offset); wm_widget_register(wgroup, &plane->widget, name); return (wmWidget *)plane; } +/** + * Define direction the plane will point towards + */ void WIDGET_plane_set_direction(wmWidget *widget, const float direction[3]) { PlaneWidget *plane = (PlaneWidget *)widget; @@ -843,13 +1023,9 @@ void WIDGET_plane_set_direction(wmWidget *widget, const float direction[3]) normalize_v3(plane->direction); } -void WIDGET_plane_set_offset(wmWidget *widget, const float offset[3]) -{ - PlaneWidget *plane = (PlaneWidget *)widget; - - copy_v3_v3(plane->offset, offset); -} - +/** + * Define up-direction of the plane widget + */ void WIDGET_plane_set_up_vector(wmWidget *widget, const float direction[3]) { PlaneWidget *plane = (PlaneWidget *)widget; @@ -864,8 +1040,20 @@ void WIDGET_plane_set_up_vector(wmWidget *widget, const float direction[3]) } } -/********* Cage widget ************/ +/** \} */ // Plane Widget API +/** \} */ // Plane Widget + + +/** \name Cage Widget + * + * 2D Widget + * + * \brief Rectangular widget acting as a 'cage' around its content. + * Interacting scales or translates the widget. + * + * \{ */ +/* wmWidget->highlighted_part */ enum { WIDGET_RECT_TRANSFORM_INTERSECT_TRANSLATE = 1, WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_LEFT = 2, @@ -879,7 +1067,6 @@ enum { typedef struct RectTransformWidget { wmWidget widget; - float offset[2]; /* position of widget */ float w, h; /* dimensions of widget */ float rotation; /* rotation of the rectangle */ float scale[2]; /* scaling for the widget for non-destructive editing. */ @@ -918,7 +1105,7 @@ static void rect_transform_draw_interaction( { float verts[4][2]; unsigned short elems[4] = {0, 1, 3, 2}; - + switch (highlighted) { case WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_LEFT: verts[0][0] = -half_w + w; @@ -930,7 +1117,7 @@ static void rect_transform_draw_interaction( verts[3][0] = -half_w + w; verts[3][1] = half_h; break; - + case WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_RIGHT: verts[0][0] = half_w - w; verts[0][1] = -half_h; @@ -941,7 +1128,7 @@ static void rect_transform_draw_interaction( verts[3][0] = half_w - w; verts[3][1] = half_h; break; - + case WIDGET_RECT_TRANSFORM_INTERSECT_SCALEY_DOWN: verts[0][0] = -half_w; verts[0][1] = -half_h + h; @@ -952,7 +1139,7 @@ static void rect_transform_draw_interaction( verts[3][0] = half_w; verts[3][1] = -half_h + h; break; - + case WIDGET_RECT_TRANSFORM_INTERSECT_SCALEY_UP: verts[0][0] = -half_w; verts[0][1] = half_h - h; @@ -963,11 +1150,11 @@ static void rect_transform_draw_interaction( verts[3][0] = half_w; verts[3][1] = half_h - h; break; - + default: return; } - + glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, verts); glLineWidth(line_width + 3.0); @@ -978,7 +1165,7 @@ static void rect_transform_draw_interaction( glDrawArrays(GL_LINE_STRIP, 0, 3); glLineWidth(1.0); - (void)elems; + UNUSED_VARS(elems); } static void widget_rect_transform_draw(const bContext *UNUSED(C), wmWidget *widget) @@ -990,14 +1177,14 @@ static void widget_rect_transform_draw(const bContext *UNUSED(C), wmWidget *widg float half_w = w / 2.0f; float half_h = h / 2.0f; float aspx = 1.0f, aspy = 1.0f; - + r.xmin = -half_w; r.ymin = -half_h; r.xmax = half_w; r.ymax = half_h; - + glPushMatrix(); - glTranslatef(widget->origin[0] + cage->offset[0], widget->origin[1] + cage->offset[1], 0.0f); + glTranslatef(widget->origin[0] + widget->offset[0], widget->origin[1] + widget->offset[1], 0.0f); if (cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM) glScalef(cage->scale[0], cage->scale[0], 1.0); else @@ -1029,7 +1216,7 @@ static void widget_rect_transform_draw(const bContext *UNUSED(C), wmWidget *widg glPopMatrix(); } -static int widget_rect_tranfrorm_get_cursor(wmWidget *widget) +static int widget_rect_transform_get_cursor(wmWidget *widget) { switch (widget->highlighted_part) { case WIDGET_RECT_TRANSFORM_INTERSECT_TRANSLATE: @@ -1045,7 +1232,7 @@ static int widget_rect_tranfrorm_get_cursor(wmWidget *widget) } } -static int widget_rect_tranfrorm_intersect(bContext *UNUSED(C), const wmEvent *event, wmWidget *widget) +static int widget_rect_transform_intersect(bContext *UNUSED(C), const wmEvent *event, wmWidget *widget) { RectTransformWidget *cage = (RectTransformWidget *)widget; const float mouse[2] = {event->mval[0], event->mval[1]}; @@ -1058,11 +1245,11 @@ static int widget_rect_tranfrorm_intersect(bContext *UNUSED(C), const wmEvent *e bool isect; rctf r; float aspx = 1.0f, aspy = 1.0f; - + /* rotate mouse in relation to the center and relocate it */ sub_v2_v2v2(point_local, mouse, widget->origin); - point_local[0] -= cage->offset[0]; - point_local[1] -= cage->offset[1]; + point_local[0] -= widget->offset[0]; + point_local[1] -= widget->offset[1]; //rotate_m2(matrot, -cage->transform.rotation); if (cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM) @@ -1071,7 +1258,7 @@ static int widget_rect_tranfrorm_intersect(bContext *UNUSED(C), const wmEvent *e point_local[0] /= cage->scale[0]; point_local[1] /= cage->scale[0]; } - + if (cage->w > cage->h) aspx = h / w; else @@ -1084,9 +1271,9 @@ static int widget_rect_tranfrorm_intersect(bContext *UNUSED(C), const wmEvent *e r.ymin = -half_h + h; r.xmax = half_w - w; r.ymax = half_h - h; - + isect = BLI_rctf_isect_pt_v(&r, point_local); - + if (isect) return WIDGET_RECT_TRANSFORM_INTERSECT_TRANSLATE; @@ -1096,43 +1283,43 @@ static int widget_rect_tranfrorm_intersect(bContext *UNUSED(C), const wmEvent *e r.ymin = -half_h; r.xmax = -half_w + w; r.ymax = half_h; - + isect = BLI_rctf_isect_pt_v(&r, point_local); - + if (isect) return WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_LEFT; - + r.xmin = half_w - w; r.ymin = -half_h; r.xmax = half_w; r.ymax = half_h; - + isect = BLI_rctf_isect_pt_v(&r, point_local); - + if (isect) return WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_RIGHT; - + r.xmin = -half_w; r.ymin = -half_h; r.xmax = half_w; r.ymax = -half_h + h; - + isect = BLI_rctf_isect_pt_v(&r, point_local); - + if (isect) return WIDGET_RECT_TRANSFORM_INTERSECT_SCALEY_DOWN; - + r.xmin = -half_w; r.ymin = half_h - h; r.xmax = half_w; r.ymax = half_h; - + isect = BLI_rctf_isect_pt_v(&r, point_local); - + if (isect) return WIDGET_RECT_TRANSFORM_INTERSECT_SCALEY_UP; } - + return 0; } @@ -1156,13 +1343,13 @@ static bool widget_rect_transform_get_property(wmWidget *widget, const int slot, fprintf(stderr, "Rect Transform widget offset not only be bound to array float property"); return false; } - RNA_property_float_get_array(&widget->ptr[slot], widget->props[slot], value); } else if (slot == RECT_TRANSFORM_SLOT_SCALE) { RectTransformWidget *cage = (RectTransformWidget *)widget; - if (cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM) + if (cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM) { *value = RNA_property_float_get(&widget->ptr[slot], widget->props[slot]); + } else { if (RNA_property_array_length(&widget->ptr[slot], widget->props[slot]) != 2) { fprintf(stderr, "Rect Transform widget scale not only be bound to array float property"); @@ -1172,7 +1359,7 @@ static bool widget_rect_transform_get_property(wmWidget *widget, const int slot, } } } - + return true; } @@ -1180,45 +1367,45 @@ static int widget_rect_transform_invoke(bContext *UNUSED(C), const wmEvent *even { RectTransformWidget *cage = (RectTransformWidget *) widget; RectTransformInteraction *data = MEM_callocN(sizeof (RectTransformInteraction), "cage_interaction"); - - copy_v2_v2(data->orig_offset, cage->offset); + + copy_v2_v2(data->orig_offset, widget->offset); copy_v2_v2(data->orig_scale, cage->scale); - + data->orig_mouse[0] = event->mval[0]; data->orig_mouse[1] = event->mval[1]; - + widget->interaction_data = data; - + return OPERATOR_RUNNING_MODAL; } static int widget_rect_transform_handler(bContext *C, const wmEvent *event, wmWidget *widget) { - RectTransformWidget *cage = (RectTransformWidget *) widget; + RectTransformWidget *cage = (RectTransformWidget *)widget; RectTransformInteraction *data = widget->interaction_data; ARegion *ar = CTX_wm_region(C); float valuex, valuey; /* needed here as well in case clamping occurs */ - const float orig_ofx = cage->offset[0], orig_ofy = cage->offset[1]; - + const float orig_ofx = widget->offset[0], orig_ofy = widget->offset[1]; + valuex = (event->mval[0] - data->orig_mouse[0]); valuey = (event->mval[1] - data->orig_mouse[1]); - + if (widget->highlighted_part == WIDGET_RECT_TRANSFORM_INTERSECT_TRANSLATE) { - cage->offset[0] = data->orig_offset[0] + valuex; - cage->offset[1] = data->orig_offset[1] + valuey; + widget->offset[0] = data->orig_offset[0] + valuex; + widget->offset[1] = data->orig_offset[1] + valuey; } else if (widget->highlighted_part == WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_LEFT) { - cage->offset[0] = data->orig_offset[0] + valuex / 2.0; + widget->offset[0] = data->orig_offset[0] + valuex / 2.0; cage->scale[0] = (cage->w * data->orig_scale[0] - valuex) / cage->w; } else if (widget->highlighted_part == WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_RIGHT) { - cage->offset[0] = data->orig_offset[0] + valuex / 2.0; + widget->offset[0] = data->orig_offset[0] + valuex / 2.0; cage->scale[0] = (cage->w * data->orig_scale[0] + valuex) / cage->w; } else if (widget->highlighted_part == WIDGET_RECT_TRANSFORM_INTERSECT_SCALEY_DOWN) { - cage->offset[1] = data->orig_offset[1] + valuey / 2.0; - + widget->offset[1] = data->orig_offset[1] + valuey / 2.0; + if (cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM) { cage->scale[0] = (cage->h * data->orig_scale[0] - valuey) / cage->h; } @@ -1227,8 +1414,8 @@ static int widget_rect_transform_handler(bContext *C, const wmEvent *event, wmWi } } else if (widget->highlighted_part == WIDGET_RECT_TRANSFORM_INTERSECT_SCALEY_UP) { - cage->offset[1] = data->orig_offset[1] + valuey / 2.0; - + widget->offset[1] = data->orig_offset[1] + valuey / 2.0; + if (cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM) { cage->scale[0] = (cage->h * data->orig_scale[0] + valuey) / cage->h; } @@ -1236,33 +1423,33 @@ static int widget_rect_transform_handler(bContext *C, const wmEvent *event, wmWi cage->scale[1] = (cage->h * data->orig_scale[1] + valuey) / cage->h; } } - + /* clamping - make sure widget is at least 5 pixels wide */ if (cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM) { if (cage->scale[0] < WIDGET_RECT_MIN_WIDTH / cage->h || cage->scale[0] < WIDGET_RECT_MIN_WIDTH / cage->w) { cage->scale[0] = max_ff(WIDGET_RECT_MIN_WIDTH / cage->h, WIDGET_RECT_MIN_WIDTH / cage->w); - cage->offset[0] = orig_ofx; - cage->offset[1] = orig_ofy; + widget->offset[0] = orig_ofx; + widget->offset[1] = orig_ofy; } } else { if (cage->scale[0] < WIDGET_RECT_MIN_WIDTH / cage->w) { cage->scale[0] = WIDGET_RECT_MIN_WIDTH / cage->w; - cage->offset[0] = orig_ofx; + widget->offset[0] = orig_ofx; } if (cage->scale[1] < WIDGET_RECT_MIN_WIDTH / cage->h) { cage->scale[1] = WIDGET_RECT_MIN_WIDTH / cage->h; - cage->offset[1] = orig_ofy; + widget->offset[1] = orig_ofy; } } - + if (widget->props[RECT_TRANSFORM_SLOT_OFFSET]) { PointerRNA ptr = widget->ptr[RECT_TRANSFORM_SLOT_OFFSET]; PropertyRNA *prop = widget->props[RECT_TRANSFORM_SLOT_OFFSET]; - RNA_property_float_set_array(&ptr, prop, cage->offset); + RNA_property_float_set_array(&ptr, prop, widget->offset); RNA_property_update(C, &ptr, prop); } @@ -1278,23 +1465,54 @@ static int widget_rect_transform_handler(bContext *C, const wmEvent *event, wmWi } RNA_property_update(C, &ptr, prop); } - + /* tag the region for redraw */ ED_region_tag_redraw(ar); - + return OPERATOR_PASS_THROUGH; } static void widget_rect_transform_bind_to_prop(wmWidget *widget, const int slot) { RectTransformWidget *cage = (RectTransformWidget *) widget; - + if (slot == RECT_TRANSFORM_SLOT_OFFSET) - widget_rect_transform_get_property(widget, RECT_TRANSFORM_SLOT_OFFSET, cage->offset); + widget_rect_transform_get_property(widget, RECT_TRANSFORM_SLOT_OFFSET, widget->offset); if (slot == RECT_TRANSFORM_SLOT_SCALE) widget_rect_transform_get_property(widget, RECT_TRANSFORM_SLOT_SCALE, cage->scale); } +static void widget_rect_transform_cancel(bContext *C, wmWidget *widget) +{ + RectTransformWidget *cage = (RectTransformWidget *) widget; + RectTransformInteraction *data = widget->interaction_data; + + /* reset properties */ + if (widget->props[RECT_TRANSFORM_SLOT_OFFSET]) { + PointerRNA ptr = widget->ptr[RECT_TRANSFORM_SLOT_OFFSET]; + PropertyRNA *prop = widget->props[RECT_TRANSFORM_SLOT_OFFSET]; + + RNA_property_float_set_array(&ptr, prop, data->orig_offset); + RNA_property_update(C, &ptr, prop); + } + if (widget->props[RECT_TRANSFORM_SLOT_SCALE]) { + PointerRNA ptr = widget->ptr[RECT_TRANSFORM_SLOT_SCALE]; + PropertyRNA *prop = widget->props[RECT_TRANSFORM_SLOT_SCALE]; + + if (cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM){ + RNA_property_float_set(&ptr, prop, data->orig_scale[0]); + } + else { + RNA_property_float_set_array(&ptr, prop, data->orig_scale); + } + RNA_property_update(C, &ptr, prop); + } +} + +/** \name Cage Widget API + * + * \{ */ + wmWidget *WIDGET_rect_transform_new( wmWidgetGroup *wgroup, const char *name, const int style, const float width, const float height) @@ -1305,27 +1523,33 @@ wmWidget *WIDGET_rect_transform_new( cage->widget.invoke = widget_rect_transform_invoke; cage->widget.bind_to_prop = widget_rect_transform_bind_to_prop; cage->widget.handler = widget_rect_transform_handler; - cage->widget.intersect = widget_rect_tranfrorm_intersect; - cage->widget.get_cursor = widget_rect_tranfrorm_get_cursor; + cage->widget.intersect = widget_rect_transform_intersect; + cage->widget.cancel = widget_rect_transform_cancel; + cage->widget.get_cursor = widget_rect_transform_get_cursor; cage->widget.max_prop = 2; + cage->widget.flag |= WM_WIDGET_DRAW_ACTIVE; cage->scale[0] = cage->scale[1] = 1.0f; cage->style = style; cage->w = width; cage->h = height; - + wm_widget_register(wgroup, &cage->widget, name); - + return (wmWidget *)cage; } -void WIDGET_rect_transform_set_offset(wmWidget *widget, const float offset[2]) -{ - RectTransformWidget *cage = (RectTransformWidget *)widget; +/** \} */ // Cage Widget API +/** \} */ // Cage Widget - copy_v2_v2(cage->offset, offset); -} -/********* Facemap widget ************/ +/** \name Facemap Widget + * + * 3D Widget + * + * \brief Widget representing shape of a face map. + * Currently no own handling, use with operator only. + * + * \{ */ typedef struct FacemapWidget { wmWidget widget; @@ -1340,7 +1564,10 @@ static void widget_facemap_draw(const bContext *C, wmWidget *widget) FacemapWidget *fmap_widget = (FacemapWidget *)widget; glPushMatrix(); glMultMatrixf(fmap_widget->ob->obmat); + glTranslate3fv(widget->offset); + glEnable(GL_MULTISAMPLE_ARB); ED_draw_object_facemap(CTX_data_scene(C), fmap_widget->ob, fmap_widget->facemap); + glDisable(GL_MULTISAMPLE_ARB); glPopMatrix(); } @@ -1350,29 +1577,50 @@ static void widget_facemap_render_3d_intersect(const bContext *C, wmWidget *widg widget_facemap_draw(C, widget); } +#if 0 +static int widget_facemap_invoke(bContext *UNUSED(C), const wmEvent *event, wmWidget *widget) +{ + return OPERATOR_PASS_THROUGH; +} + +static int widget_facemap_handler(bContext *C, const wmEvent *event, wmWidget *widget) +{ + return OPERATOR_PASS_THROUGH; +} +#endif -struct wmWidget *WIDGET_facemap_new( +/** \name Facemap Widget API + * + * \{ */ + +wmWidget *WIDGET_facemap_new( wmWidgetGroup *wgroup, const char *name, const int style, Object *ob, const int facemap) { FacemapWidget *fmap_widget = MEM_callocN(sizeof(FacemapWidget), "CageWidget"); fmap_widget->widget.draw = widget_facemap_draw; -// fmap_widget->widget.invoke = NULL; +// fmap_widget->widget.invoke = widget_facemap_invoke; // fmap_widget->widget.bind_to_prop = NULL; -// fmap_widget->widget.handler = NULL; +// fmap_widget->widget.handler = widget_facemap_handler; fmap_widget->widget.render_3d_intersection = widget_facemap_render_3d_intersect; + fmap_widget->widget.flag |= WM_WIDGET_SELECTABLE ; fmap_widget->ob = ob; fmap_widget->facemap = facemap; fmap_widget->style = style; - + wm_widget_register(wgroup, &fmap_widget->widget, name); - + return (wmWidget *)fmap_widget; } +/** \} */ // Facemap Widget API +/** \} */ // Facemap Widget + + +/* -------------------------------------------------------------------- */ void fix_linking_widget_lib(void) { - (void) 0; + (void)0; } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 0f0e6c9b771..b0acc3c0f1e 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -5328,6 +5328,12 @@ void wm_operatortype_init(void) WM_operatortype_append(WM_OT_previews_ensure); WM_operatortype_append(WM_OT_previews_clear); WM_operatortype_append(WM_OT_doc_view_manual_ui_context); + + /* widgets */ + WM_operatortype_append(WIDGETGROUP_OT_widget_set_active); + WM_operatortype_append(WIDGETGROUP_OT_widget_set_select); + WM_operatortype_append(WIDGETGROUP_OT_widget_tweak); + WM_operatortype_append(WIDGETGROUP_OT_widget_tweak_cancel); } /* circleselect-like modal operators */ diff --git a/source/blender/windowmanager/intern/wm_widgets.c b/source/blender/windowmanager/intern/wm_widgets.c index b32fa7b78e0..613d20c14f8 100644 --- a/source/blender/windowmanager/intern/wm_widgets.c +++ b/source/blender/windowmanager/intern/wm_widgets.c @@ -15,8 +15,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2007 Blender Foundation but based - * on ghostwinlay.c (C) 2001-2002 by NaN Holding BV + * The Original Code is Copyright (C) 2014 Blender Foundation. * All rights reserved. * * Contributor(s): Blender Foundation, 2008 @@ -70,6 +69,7 @@ #include "GPU_select.h" #include "RNA_access.h" +#include "RNA_define.h" #include "BPY_extern.h" /** @@ -101,60 +101,73 @@ static ListBase widgetmaptypes = {NULL, NULL}; wmWidgetGroupType *WM_widgetgrouptype_new( int (*poll)(const bContext *C, wmWidgetGroupType *), void (*create)(const bContext *, wmWidgetGroup *), - const Main *bmain, const char *mapidname, + wmKeyMap *(*keymap_init)(wmKeyConfig *, const char *), + const Main *bmain, const char *mapidname, const char *name, const short spaceid, const short regionid, const bool is_3d) { - bScreen *sc; wmWidgetMapType *wmaptype = WM_widgetmaptype_find(mapidname, spaceid, regionid, is_3d, false); wmWidgetGroupType *wgrouptype; - + bScreen *sc; + if (!wmaptype) { fprintf(stderr, "widgetgrouptype creation: widgetmap type does not exist"); return NULL; } - + wgrouptype = MEM_callocN(sizeof(wmWidgetGroupType), "widgetgroup"); - + wgrouptype->poll = poll; wgrouptype->create = create; + wgrouptype->keymap_init = keymap_init; wgrouptype->spaceid = spaceid; wgrouptype->regionid = regionid; wgrouptype->is_3d = is_3d; - BLI_strncpy(wgrouptype->mapidname, mapidname, 64); + BLI_strncpy(wgrouptype->name, name, MAX_NAME); + BLI_strncpy(wgrouptype->mapidname, mapidname, MAX_NAME); /* add the type for future created areas of the same type */ BLI_addtail(&wmaptype->widgetgrouptypes, wgrouptype); - - /* now create a widget for all existing areas. (main is missing when we create new areas so not needed) */ - if (bmain) { - for (sc = bmain->screen.first; sc; sc = sc->id.next) { - ScrArea *sa; - for (sa = sc->areabase.first; sa; sa = sa->next) { - SpaceLink *sl; - - for (sl = sa->spacedata.first; sl; sl = sl->next) { - ARegion *ar; - ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - - for (ar = lb->first; ar; ar = ar->next) { - wmWidgetMap *wmap; - for (wmap = ar->widgetmaps.first; wmap; wmap = wmap->next) { - if (wmap->type == wmaptype) { - wmWidgetGroup *wgroup = MEM_callocN(sizeof(wmWidgetGroup), "widgetgroup"); - wgroup->type = wgrouptype; - - /* just add here, drawing will occur on next update */ - BLI_addtail(&wmap->widgetgroups, wgroup); - wm_widgetmap_set_highlighted_widget(wmap, NULL, NULL, 0); - ED_region_tag_redraw(ar); - } + + /* Main is missing on startup when we create new areas. + * So this is only called for widgets initialized on runtime */ + if (!bmain) + return wgrouptype; + + + /* init keymap - on startup there's an extra call to init keymaps for 'permanent' widget-groups */ + wm_widgetgrouptype_keymap_init(wgrouptype, ((wmWindowManager *)bmain->wm.first)->defaultconf); + + /* now create a widget for all existing areas */ + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + ScrArea *sa; + + for (sa = sc->areabase.first; sa; sa = sa->next) { + SpaceLink *sl; + + for (sl = sa->spacedata.first; sl; sl = sl->next) { + ARegion *ar; + ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + + for (ar = lb->first; ar; ar = ar->next) { + wmWidgetMap *wmap; + + for (wmap = ar->widgetmaps.first; wmap; wmap = wmap->next) { + if (wmap->type == wmaptype) { + wmWidgetGroup *wgroup = MEM_callocN(sizeof(wmWidgetGroup), "widgetgroup"); + + wgroup->type = wgrouptype; + + /* just add here, drawing will occur on next update */ + BLI_addtail(&wmap->widgetgroups, wgroup); + wm_widgetmap_set_highlighted_widget(wmap, NULL, NULL, 0); + ED_region_tag_redraw(ar); } } } } } } - + return wgrouptype; } @@ -164,9 +177,9 @@ wmWidget *WM_widget_new(void (*draw)(const bContext *C, wmWidget *customdata), int (*handler)(bContext *C, const wmEvent *event, wmWidget *widget)) { wmWidget *widget; - + widget = MEM_callocN(sizeof(wmWidget), "widget"); - + widget->draw = draw; widget->handler = handler; widget->intersect = intersect; @@ -175,50 +188,6 @@ wmWidget *WM_widget_new(void (*draw)(const bContext *C, wmWidget *customdata), return widget; } -void WM_widget_property(wmWidget *widget, const int slot, PointerRNA *ptr, const char *propname) -{ - if (slot < 0 || slot >= widget->max_prop) { - fprintf(stderr, "invalid index %d when binding property for widget type %s\n", slot, widget->idname); - return; - } - - /* if widget evokes an operator we cannot use it for property manipulation */ - widget->opname = NULL; - widget->ptr[slot] = *ptr; - widget->props[slot] = RNA_struct_find_property(ptr, propname); - - if (widget->bind_to_prop) - widget->bind_to_prop(widget, slot); -} - -PointerRNA *WM_widget_operator(wmWidget *widget, const char *opname) -{ - wmOperatorType *ot = WM_operatortype_find(opname, 0); - - if (ot) { - widget->opname = opname; - - WM_operator_properties_create_ptr(&widget->opptr, ot); - - return &widget->opptr; - } - else { - fprintf(stderr, "Error binding operator to widget: operator %s not found!\n", opname); - } - - return NULL; -} - -void WM_widgetgroup_customdata_set(wmWidgetGroup *wgroup, void *data) -{ - wgroup->customdata = data; -} - -void *WM_widgetgroup_customdata(const wmWidgetGroup *wgroup) -{ - return wgroup->customdata; -} - static void wm_widget_delete(ListBase *widgetlist, wmWidget *widget) { @@ -228,7 +197,7 @@ static void wm_widget_delete(ListBase *widgetlist, wmWidget *widget) MEM_freeN(widget->props); MEM_freeN(widget->ptr); - + BLI_freelinkN(widgetlist, widget); } @@ -239,8 +208,6 @@ static void widget_calculate_scale(wmWidget *widget, const bContext *C) float scale = 1.0f; if (rv3d && (U.tw_flag & V3D_3D_WIDGETS) == 0 && (widget->flag & WM_WIDGET_SCALE_3D)) { - ED_view3d_update_viewmat(CTX_data_scene(C), CTX_wm_view3d(C), CTX_wm_region(C), NULL, NULL); - if (widget->get_final_position) { float position[3]; @@ -255,7 +222,22 @@ static void widget_calculate_scale(wmWidget *widget, const bContext *C) widget->scale = scale * widget->user_scale; } -static bool widgets_compare(const wmWidget *a, const wmWidget *b) +/** + * Initialize keymaps for all existing widget-groups + */ +void wm_widgets_keymap(wmKeyConfig *keyconf) +{ + wmWidgetMapType *wmaptype; + wmWidgetGroupType *wgrouptype; + + for (wmaptype = widgetmaptypes.first; wmaptype; wmaptype = wmaptype->next) { + for (wgrouptype = wmaptype->widgetgrouptypes.first; wgrouptype; wgrouptype = wgrouptype->next) { + wm_widgetgrouptype_keymap_init(wgrouptype, keyconf); + } + } +} + +BLI_INLINE bool widgets_compare(const wmWidget *a, const wmWidget *b) { return STREQ(a->idname, b->idname); } @@ -276,16 +258,18 @@ void WM_widgets_update(const bContext *C, wmWidgetMap *wmap) wmWidgetGroup *wgroup; for (wgroup = wmap->widgetgroups.first; wgroup; wgroup = wgroup->next) { - if (!wgroup->type->poll || wgroup->type->poll(C, wgroup->type)) - { + if (!wgroup->type->poll || wgroup->type->poll(C, wgroup->type)) { wmWidget *highlighted = NULL; /* first delete and recreate the widgets */ for (widget = wgroup->widgets.first; widget;) { wmWidget *widget_next = widget->next; + if (widget == wmap->selected_widget) { + /* skip */ + } /* do not delete the highlighted widget, instead keep it to compare with the new one */ - if (widget->flag & WM_WIDGET_HIGHLIGHT) { + else if (widget->flag & WM_WIDGET_HIGHLIGHT) { highlighted = widget; BLI_remlink(&wgroup->widgets, widget); widget->next = widget->prev = NULL; @@ -356,17 +340,18 @@ void WM_widgets_draw(const bContext *C, const wmWidgetMap *wmap, const bool in_s widget = wmap->active_widget; - if (widget && in_scene == ((widget->flag & WM_WIDGET_SCENE_DEPTH)!= 0)) { - /* 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 (widget && in_scene == ((widget->flag & WM_WIDGET_SCENE_DEPTH) != 0)) { + 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 */ + widget->draw(C, widget); + } } else if (wmap->widgetgroups.first) { wmWidgetGroup *wgroup; - + for (wgroup = wmap->widgetgroups.first; wgroup; wgroup = wgroup->next) { - if (!wgroup->type->poll || wgroup->type->poll(C, wgroup->type)) - { + if (!wgroup->type->poll || wgroup->type->poll(C, wgroup->type)) { 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)) && @@ -379,6 +364,13 @@ void WM_widgets_draw(const bContext *C, const wmWidgetMap *wmap, const bool in_s } } + /* draw selected widgets last */ + if ((widget = wmap->selected_widget) && in_scene == ((widget->flag & WM_WIDGET_SCENE_DEPTH) != 0)) { + /* 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 (use_lighting) glPopAttrib(); } @@ -387,10 +379,10 @@ void WM_event_add_area_widgetmap_handlers(ARegion *ar) { wmWidgetMap *wmap; wmEventHandler *handler; - + for (wmap = ar->widgetmaps.first; wmap; wmap = wmap->next) { handler = MEM_callocN(sizeof(wmEventHandler), "widget handler"); - + handler->widgetmap = wmap; BLI_addtail(&ar->handlers, handler); } @@ -411,7 +403,7 @@ void WM_modal_handler_attach_widgetgroup( wmWidgetMap *wmap; for (wmap = handler->op_region->widgetmaps.first; wmap; wmap = wmap->next) { wmWidgetMapType *wmaptype = wmap->type; - + if (wmaptype->spaceid == wgrouptype->spaceid && wmaptype->regionid == wgrouptype->regionid) { handler->widgetmap = wmap; } @@ -435,6 +427,21 @@ static void widget_unique_idname_set(wmWidgetGroup *wgroup, wmWidget *widget, co } /** + * Search for an active widget in region \a ar + */ +static wmWidget *widget_find_active_in_region(const ARegion *ar, wmWidgetMap **r_wmap) +{ + for (*r_wmap = ar->widgetmaps.first; *r_wmap; *r_wmap = (*r_wmap)->next) { + if ((*r_wmap)->active_widget) { + return (*r_wmap)->active_widget; + } + } + + *r_wmap = NULL; + return NULL; +} + +/** * Register \a widget * * \param name name used to create a unique idname for \a widget in \a wgroup @@ -456,60 +463,70 @@ bool wm_widget_register(wmWidgetGroup *wgroup, wmWidget *widget, const char *nam if (widget->max_prop == 0) { widget->max_prop = 1; } - + widget->props = MEM_callocN(sizeof(PropertyRNA *) * widget->max_prop, "widget->props"); widget->ptr = MEM_callocN(sizeof(PointerRNA) * widget->max_prop, "widget->ptr"); - + + widget->wgroup = wgroup; + BLI_addtail(&wgroup->widgets, widget); return true; } -void WM_widget_set_origin(wmWidget *widget, const float origin[3]) +void WM_widget_set_property(wmWidget *widget, const int slot, PointerRNA *ptr, const char *propname) { - copy_v3_v3(widget->origin, origin); + if (slot < 0 || slot >= widget->max_prop) { + fprintf(stderr, "invalid index %d when binding property for widget type %s\n", slot, widget->idname); + return; + } + + /* if widget evokes an operator we cannot use it for property manipulation */ + widget->opname = NULL; + widget->ptr[slot] = *ptr; + widget->props[slot] = RNA_struct_find_property(ptr, propname); + + if (widget->bind_to_prop) + widget->bind_to_prop(widget, slot); } -void WM_widget_set_3d_scale(wmWidget *widget, const bool scale) +PointerRNA *WM_widget_set_operator(wmWidget *widget, const char *opname) { - if (scale) { - widget->flag |= WM_WIDGET_SCALE_3D; + wmOperatorType *ot = WM_operatortype_find(opname, 0); + + if (ot) { + widget->opname = opname; + + WM_operator_properties_create_ptr(&widget->opptr, ot); + + return &widget->opptr; } else { - widget->flag &= ~WM_WIDGET_SCALE_3D; + fprintf(stderr, "Error binding operator to widget: operator %s not found!\n", opname); } + + return NULL; } -void WM_widget_flag_set(wmWidget *widget, const int flag, const bool enable) +void WM_widget_set_origin(wmWidget *widget, const float origin[3]) { - if (enable) { - widget->flag |= flag; - } - else { - widget->flag &= ~flag; - } + copy_v3_v3(widget->origin, origin); } -void WM_widget_set_draw_on_hover_only(wmWidget *widget, const bool draw) +void WM_widget_set_offset(wmWidget *widget, const float offset[3]) { - if (draw) { - widget->flag |= WM_WIDGET_DRAW_HOVER; - } - else { - widget->flag &= ~WM_WIDGET_DRAW_HOVER; - } + copy_v3_v3(widget->offset, offset); } -void WM_widget_set_scene_depth(wmWidget *widget, const bool scene) +void WM_widget_set_flag(wmWidget *widget, const int flag, const bool enable) { - if (scene) { - widget->flag |= WM_WIDGET_SCENE_DEPTH; + if (enable) { + widget->flag |= flag; } else { - widget->flag &= ~WM_WIDGET_SCENE_DEPTH; + widget->flag &= ~flag; } } - void WM_widget_set_scale(wmWidget *widget, const float scale) { widget->user_scale = scale; @@ -524,7 +541,7 @@ void WM_widget_set_line_width(wmWidget *widget, const float line_width) * Set widget rgba colors * * \param col Normal state color - * \param col_hi Highlighted state color + * \param col_hi Highlighted state color */ void WM_widget_set_colors(wmWidget *widget, const float col[4], const float col_hi[4]) { @@ -533,14 +550,173 @@ void WM_widget_set_colors(wmWidget *widget, const float col[4], const float col_ } +/** \name Widget operators + * + * Basic operators for widget interaction with user configurable keymaps. + * + * \{ */ + +static int widget_set_active_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + wmWidgetMap *wmap; + const bool deactivate = RNA_boolean_get(op->ptr, "deactivate"); + + for (wmap = ar->widgetmaps.first; wmap; wmap = wmap->next) { + if (deactivate) { + wm_widgetmap_set_active_widget(wmap, C, event, NULL); + + /* ugly hack - send widget release event */ + ((wmEvent *)event)->type = EVT_WIDGET_RELEASED; + } + else { + wmWidget *widget = wmap->highlighted_widget; + if (widget) { + wm_widgetmap_set_active_widget(wmap, C, event, widget); + break; + } + else { + BLI_assert(0); + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + } + } + + return OPERATOR_FINISHED; +} + +void WIDGETGROUP_OT_widget_set_active(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Widget Activate"; + ot->description = "Activate the currently highlighted widget"; + ot->idname = "WIDGETGROUP_OT_widget_set_active"; + + /* api callbacks */ + ot->invoke = widget_set_active_invoke; + + ot->flag = OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "deactivate", 0, "Deactivate", "Deactivate currently active widget"); +} + +static int widget_set_select_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) +{ + ARegion *ar = CTX_wm_region(C); + wmWidgetMap *wmap; + + for (wmap = ar->widgetmaps.first; wmap; wmap = wmap->next) { + wmWidget *widget = wmap->highlighted_widget; + if (widget) { + if (widget->flag & WM_WIDGET_SELECTABLE) { + wm_widgetmap_set_selected_widget(C, wmap, widget); + } + break; + } + else { + BLI_assert(0); + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + } + + return OPERATOR_FINISHED; +} + +void WIDGETGROUP_OT_widget_set_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Widget Select"; + ot->description = "Select the currently highlighted widget"; + ot->idname = "WIDGETGROUP_OT_widget_set_select"; + + /* api callbacks */ + ot->invoke = widget_set_select_invoke; + + ot->flag = OPTYPE_UNDO; + + /* TODO - more fancy selections are not implemented yet */ +// RNA_def_boolean(ot->srna, "deactivate", 0, "Deactivate", "Deactivate currently active widget"); +} + +static int widget_tweak_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + wmWidgetMap *wmap; + wmWidget *widget = widget_find_active_in_region(ar, &wmap); + + if (!widget) { + BLI_assert(0); + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + /* handle widget */ + widget->handler(C, event, widget); + + /* ugly hack - send widget update event */ + ((wmEvent *)event)->type = EVT_WIDGET_UPDATE; + + return OPERATOR_FINISHED; +} + +void WIDGETGROUP_OT_widget_tweak(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Widget Tweak"; + ot->description = "Tweak the active widget"; + ot->idname = "WIDGETGROUP_OT_widget_tweak"; + + /* api callbacks */ + ot->invoke = widget_tweak_invoke; +} + +static int widget_cancel_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + wmWidgetMap *wmap; + wmWidget *widget = widget_find_active_in_region(ar, &wmap); + + if (!widget) { + /* don't assert(0) here, this might be called if modal handler + * which has widget attached uses same shortcut as widget-cancel */ + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + if (widget->cancel) { + widget->cancel(C, widget); + } + wm_widgetmap_set_active_widget(wmap, C, event, NULL); + + /* ugly hack - send widget release event */ + ((wmEvent *)event)->type = EVT_WIDGET_RELEASED; + + return OPERATOR_FINISHED; +} + +void WIDGETGROUP_OT_widget_tweak_cancel(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Widget Tweak Cancel"; + ot->description = "Cancel tweaking of active widget"; + ot->idname = "WIDGETGROUP_OT_widget_tweak_cancel"; + + /* api callbacks */ + ot->invoke = widget_cancel_invoke; +} + +/** \} */ // Widget operators + + wmWidgetMapType *WM_widgetmaptype_find( const char *idname, const int spaceid, const int regionid, const bool is_3d, const bool create) { wmWidgetMapType *wmaptype; for (wmaptype = widgetmaptypes.first; wmaptype; wmaptype = wmaptype->next) { - if (wmaptype->spaceid == spaceid && wmaptype->regionid == regionid && wmaptype->is_3d == is_3d - && strcmp(wmaptype->idname, idname) == 0) { + if (wmaptype->spaceid == spaceid && + wmaptype->regionid == regionid && + wmaptype->is_3d == is_3d && + STREQ(wmaptype->idname, idname)) + { return wmaptype; } } @@ -553,14 +729,14 @@ wmWidgetMapType *WM_widgetmaptype_find( wmaptype->is_3d = is_3d; BLI_strncpy(wmaptype->idname, idname, 64); BLI_addhead(&widgetmaptypes, wmaptype); - + return wmaptype; } void WM_widgetmaptypes_free(void) { wmWidgetMapType *wmaptype; - + for (wmaptype = widgetmaptypes.first; wmaptype; wmaptype = wmaptype->next) { BLI_freelistN(&wmaptype->widgetgrouptypes); } @@ -602,38 +778,38 @@ static int wm_widget_find_highlighted_3D_intern( const bool do_passes = GPU_select_query_check_active(); extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect); - + + rect.xmin = event->mval[0] - hotspot; rect.xmax = event->mval[0] + hotspot; rect.ymin = event->mval[1] - hotspot; rect.ymax = event->mval[1] + hotspot; - + selrect = rect; - + view3d_winmatrix_set(ar, v3d, &rect); mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); - + if (do_passes) GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0); else GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_ALL, 0); /* do the drawing */ widget_find_active_3D_loop(C, visible_widgets); - + hits = GPU_select_end(); - + if (do_passes) { GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits); widget_find_active_3D_loop(C, visible_widgets); GPU_select_end(); } - + view3d_winmatrix_set(ar, v3d, NULL); mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); if (hits == 1) { return buffer[3]; - } /* find the widget the value belongs to */ else if (hits > 1) { @@ -655,6 +831,7 @@ static int wm_widget_find_highlighted_3D_intern( return minval; } + return -1; } @@ -686,24 +863,24 @@ wmWidget *wm_widget_find_highlighted_3D(wmWidgetMap *wmap, bContext *C, const wm *part = 0; /* set up view matrices */ view3d_operator_needs_opengl(C); - + ret = wm_widget_find_highlighted_3D_intern(&visible_widgets, C, event, 0.5f * hotspot); - + if (ret != -1) { LinkData *link; int retsec; retsec = wm_widget_find_highlighted_3D_intern(&visible_widgets, C, event, 0.2f * hotspot); - + if (retsec != -1) ret = retsec; - + link = BLI_findlink(&visible_widgets, ret >> 8); *part = ret & 255; result = link->data; } BLI_freelistN(&visible_widgets); - + return result; } @@ -735,7 +912,7 @@ bool WM_widgetmap_cursor_set(const wmWidgetMap *wmap, wmWindow *win) return true; } } - + return false; } @@ -746,23 +923,27 @@ void wm_widgetmap_set_highlighted_widget(wmWidgetMap *wmap, bContext *C, wmWidge wmap->highlighted_widget->flag &= ~WM_WIDGET_HIGHLIGHT; wmap->highlighted_widget->highlighted_part = 0; } - + wmap->highlighted_widget = widget; - + if (widget) { widget->flag |= WM_WIDGET_HIGHLIGHT; widget->highlighted_part = part; - + wmap->activegroup = widget->wgroup; + if (C && widget->get_cursor) { wmWindow *win = CTX_wm_window(C); WM_cursor_set(win, widget->get_cursor(widget)); } } - else if (C) { - wmWindow *win = CTX_wm_window(C); - WM_cursor_set(win, CURSOR_STD); + else { + wmap->activegroup = NULL; + if (C) { + wmWindow *win = CTX_wm_window(C); + WM_cursor_set(win, CURSOR_STD); + } } - + /* tag the region for redraw */ if (C) { ARegion *ar = CTX_wm_region(C); @@ -778,35 +959,23 @@ wmWidget *wm_widgetmap_get_highlighted_widget(wmWidgetMap *wmap) void wm_widgetmap_set_active_widget( wmWidgetMap *wmap, bContext *C, - wmEvent *event, wmWidget *widget, - const bool call_op) + const wmEvent *event, wmWidget *widget) { if (widget) { - if (call_op) { + if (widget->opname) { wmOperatorType *ot; - const bool has_custom_op = widget->opname != NULL; - const char *opname = has_custom_op ? widget->opname : "WM_OT_widget_tweak"; - ot = WM_operatortype_find(opname, 0); + ot = WM_operatortype_find(widget->opname, 0); if (ot) { /* first activate the widget itself */ if (widget->invoke && widget->handler) { widget->flag |= WM_WIDGET_ACTIVE; widget->invoke(C, event, widget); - wmap->active_widget = widget; } + wmap->active_widget = widget; - /* if operator runs modal, we will need to activate the current widgetmap on the operator handler, - * so it can process events first, then pass them on to the operator */ - if (WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &widget->opptr) == OPERATOR_RUNNING_MODAL) { - /* check if operator added a a modal event handler */ - wmEventHandler *handler = CTX_wm_window(C)->modalhandlers.first; - - if (has_custom_op == false && handler && handler->op && handler->op->type == ot) { - handler->widgetmap = wmap; - } - } + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &widget->opptr); /* we failed to hook the widget to the operator handler or operator was cancelled, return */ if (!wmap->active_widget) { @@ -846,7 +1015,7 @@ void wm_widgetmap_set_active_widget( } } wmap->active_widget = NULL; - + if (C) { ARegion *ar = CTX_wm_region(C); ED_region_tag_redraw(ar); @@ -855,6 +1024,33 @@ void wm_widgetmap_set_active_widget( } } +wmWidget *wm_widgetmap_get_selected_widget(wmWidgetMap *wmap) +{ + return wmap->selected_widget; +} + +void wm_widgetmap_set_selected_widget(bContext *C, wmWidgetMap *wmap, wmWidget *widget) +{ + if (widget) { + wmap->selected_widget = widget; + widget->flag |= WM_WIDGET_SELECTED; + wm_widgetmap_set_highlighted_widget(wmap, C, NULL, wmap->highlighted_widget->highlighted_part); + } + else { + widget = wmap->selected_widget; + if (widget) { + wmap->selected_widget = NULL; + widget->flag &= ~WM_WIDGET_SELECTED; + } + } + + /* tag the region for redraw */ + if (C) { + ARegion *ar = CTX_wm_region(C); + ED_region_tag_redraw(ar); + } +} + void wm_widgetmap_handler_context(bContext *C, wmEventHandler *handler) { bScreen *screen = CTX_wm_screen(C); @@ -915,7 +1111,7 @@ void wm_widget_handler_modal_update(bContext *C, wmEvent *event, wmEventHandler } /* operator not running anymore */ else { - wm_widgetmap_set_active_widget(wmap, C, event, NULL, false); + wm_widgetmap_set_active_widget(wmap, C, event, NULL); } /* restore the area */ @@ -959,7 +1155,7 @@ void WM_widgetmap_delete(wmWidgetMap *wmap) for (wgroup = wmap->widgetgroups.first; wgroup; wgroup = wgroup->next) { wmWidget *widget; - + for (widget = wgroup->widgets.first; widget;) { wmWidget *widget_next = widget->next; wm_widget_delete(&wgroup->widgets, widget); @@ -981,7 +1177,7 @@ static void wm_widgetgroup_free(bContext *C, wmWidgetMap *wmap, wmWidgetGroup *w wm_widgetmap_set_highlighted_widget(wmap, C, NULL, 0); } if (widget->flag & WM_WIDGET_ACTIVE) { - wm_widgetmap_set_active_widget(wmap, C, NULL, NULL, false); + wm_widgetmap_set_active_widget(wmap, C, NULL, NULL); } wm_widget_delete(&wgroup->widgets, widget); widget = widget_next; @@ -1004,6 +1200,34 @@ static void wm_widgetgroup_free(bContext *C, wmWidgetMap *wmap, wmWidgetGroup *w MEM_freeN(wgroup); } +/** + * Common default keymap for widget groups + */ +wmKeyMap *WM_widgetgroup_keymap_common(wmKeyConfig *config, const char *wgroupname) +{ + wmKeyMap *km = WM_keymap_find(config, wgroupname, 0, 0); + wmKeyMapItem *kmi; + + kmi = WM_keymap_add_item(km, "WIDGETGROUP_OT_widget_set_active", ACTIONMOUSE, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "deactivate", false); + kmi = WM_keymap_add_item(km, "WIDGETGROUP_OT_widget_set_active", ACTIONMOUSE, KM_RELEASE, 0, 0); + RNA_boolean_set(kmi->ptr, "deactivate", true); + + WM_keymap_add_item(km, "WIDGETGROUP_OT_widget_tweak", MOUSEMOVE, KM_ANY, KM_ANY, 0); + + WM_keymap_add_item(km, "WIDGETGROUP_OT_widget_tweak_cancel", RIGHTMOUSE, KM_PRESS, 0, 0); + WM_keymap_add_item(km, "WIDGETGROUP_OT_widget_tweak_cancel", ESCKEY, KM_PRESS, 0, 0); + + WM_keymap_add_item(km, "WIDGETGROUP_OT_widget_set_select", SELECTMOUSE, KM_PRESS, 0, 0); + + return km; +} + +void wm_widgetgrouptype_keymap_init(wmWidgetGroupType *wgrouptype, wmKeyConfig *keyconf) +{ + wgrouptype->keymap = wgrouptype->keymap_init(keyconf, wgrouptype->name); +} + void WM_widgetgrouptype_unregister(bContext *C, Main *bmain, wmWidgetGroupType *wgrouptype) { bScreen *sc; @@ -1036,8 +1260,10 @@ void WM_widgetgrouptype_unregister(bContext *C, Main *bmain, wmWidgetGroupType * } wmaptype = WM_widgetmaptype_find(wgrouptype->mapidname, wgrouptype->spaceid, wgrouptype->regionid, wgrouptype->is_3d, false); + BLI_remlink(&wmaptype->widgetgrouptypes, wgrouptype); wgrouptype->prev = wgrouptype->next = NULL; + MEM_freeN(wgrouptype); } diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h index c5a1d5f7f6d..f2bed99815d 100644 --- a/source/blender/windowmanager/wm.h +++ b/source/blender/windowmanager/wm.h @@ -49,12 +49,15 @@ typedef struct wmPaintCursor { void (*draw)(bContext *C, int, int, void *customdata); } wmPaintCursor; -/* widgets are set per screen/area/region by registering them on widgetmaps */ +/* widgets are set per region by registering them on widgetmaps */ typedef struct wmWidget { struct wmWidget *next, *prev; - + char idname[MAX_NAME + 4]; /* + 4 for unique '.001', '.002', etc suffix */ + /* pointer back to parent widget group */ + wmWidgetGroup *wgroup; + /* draw widget */ void (*draw)(const struct bContext *C, struct wmWidget *widget); /* determine if the mouse intersects with the widget. The calculation should be done in the callback itself */ @@ -76,14 +79,19 @@ typedef struct wmWidget { /* activate a widget state when the user clicks on it */ int (*invoke)(struct bContext *C, const struct wmEvent *event, struct wmWidget *widget); + /* called after canceling widget handling - used to reset property */ + void (*cancel)(struct bContext *C, struct wmWidget *widget); + int (*get_cursor)(struct wmWidget *widget); - - int flag; /* flags set by drawing and interaction, such as highlighting */ + + int flag; /* flags set by drawing and interaction, such as highlighting */ unsigned char highlighted_part; /* center of widget in space, 2d or 3d */ float origin[3]; + /* custom offset from origin */ + float offset[3]; /* runtime property, set the scale while drawing on the viewport */ float scale; @@ -104,26 +112,16 @@ typedef struct wmWidget { const char *opname; /* operator properties if widget spawns and controls an operator, or owner pointer if widget spawns and controls a property */ - struct PointerRNA opptr; + PointerRNA opptr; /* maximum number of properties attached to the widget */ int max_prop; - + /* arrays of properties attached to various widget parameters. As the widget is interacted with, those properties get updated */ - struct PointerRNA *ptr; - struct PropertyRNA **props; + PointerRNA *ptr; + PropertyRNA **props; } wmWidget; -/* wmWidget->flag */ -enum widgetflags { - /* states */ - WM_WIDGET_HIGHLIGHT = (1 << 0), - WM_WIDGET_ACTIVE = (1 << 1), - WM_WIDGET_DRAW_HOVER = (1 << 2), - WM_WIDGET_SCALE_3D = (1 << 3), - WM_WIDGET_SCENE_DEPTH = (1 << 4), /* widget is depth culled with scene objects*/ - WM_WIDGET_HIDDEN = (1 << 5), -}; extern void wm_close_and_free(bContext *C, wmWindowManager *); extern void wm_close_and_free_all(bContext *C, ListBase *); @@ -171,8 +169,14 @@ void wm_open_init_load_ui(wmOperator *op, bool use_prefs); void wm_open_init_use_scripts(wmOperator *op, bool use_prefs); /* wm_widgets.c */ -bool wm_widgetmap_is_3d(const struct wmWidgetMap *wmap); -bool wm_widget_register(struct wmWidgetGroup *wgroup, struct wmWidget *widget, const char *name); +bool wm_widgetmap_is_3d(const wmWidgetMap *wmap); +bool wm_widget_register(wmWidgetGroup *wgroup, wmWidget *widget, const char *name); +void wm_widgets_keymap(wmKeyConfig *keyconf); + +void WIDGETGROUP_OT_widget_set_active(wmOperatorType *ot); +void WIDGETGROUP_OT_widget_set_select(wmOperatorType *ot); +void WIDGETGROUP_OT_widget_tweak(wmOperatorType *ot); +void WIDGETGROUP_OT_widget_tweak_cancel(wmOperatorType *ot); /* hack to store circle select size - campbell, must replace with nice operator memory */ diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index 46ebc15e165..2d9e5dbfc54 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -104,13 +104,18 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect); void wm_widget_handler_modal_update(bContext *C, wmEvent *event, wmEventHandler *handler); void wm_widgetmap_handler_context(bContext *C, wmEventHandler *handler); -struct wmWidget *wm_widget_find_highlighted_3D(struct wmWidgetMap *wmap, struct bContext *C, const struct wmEvent *event, unsigned char *part); -wmWidget *wm_widget_find_highlighted(struct wmWidgetMap *wmap, bContext *C, const struct wmEvent *event, unsigned char *part); -void wm_widgetmap_set_highlighted_widget(struct wmWidgetMap *wmap, struct bContext *C, struct wmWidget *widget, unsigned char part); -struct wmWidget *wm_widgetmap_get_highlighted_widget(struct wmWidgetMap *wmap); +void wm_widgetgrouptype_keymap_init(wmWidgetGroupType *wgrouptype, wmKeyConfig *keyconf); -void wm_widgetmap_set_active_widget(struct wmWidgetMap *wmap, struct bContext *C, struct wmEvent *event, struct wmWidget *widget, const bool call_op); -struct wmWidget *wm_widgetmap_get_active_widget(struct wmWidgetMap *wmap); +wmWidget *wm_widget_find_highlighted_3D(wmWidgetMap *wmap, bContext *C, const wmEvent *event, unsigned char *part); +wmWidget *wm_widget_find_highlighted(wmWidgetMap *wmap, bContext *C, const wmEvent *event, unsigned char *part); +void wm_widgetmap_set_highlighted_widget(wmWidgetMap *wmap, bContext *C, wmWidget *widget, unsigned char part); +wmWidget *wm_widgetmap_get_highlighted_widget(wmWidgetMap *wmap); + +void wm_widgetmap_set_active_widget(wmWidgetMap *wmap, bContext *C, const wmEvent *event, wmWidget *widget); +wmWidget *wm_widgetmap_get_active_widget(wmWidgetMap *wmap); + +void wm_widgetmap_set_selected_widget(bContext *C, wmWidgetMap *wmap, wmWidget *widget); +wmWidget *wm_widgetmap_get_selected_widget(wmWidgetMap *wmap); #endif /* __WM_EVENT_SYSTEM_H__ */ |