diff options
author | Julian Eisel <eiseljulian@gmail.com> | 2015-10-22 20:25:02 +0300 |
---|---|---|
committer | Julian Eisel <eiseljulian@gmail.com> | 2015-10-22 20:25:02 +0300 |
commit | 0fd7310b5133aa57a4307c4cb19e44531d723ec1 (patch) | |
tree | e7f53b574f38102916bbb09cb403b472bc4373a9 | |
parent | 83a2d3dcf5a73f907c741038d5c55cb9f7aff1f9 (diff) | |
parent | 6ec01dcbf29104a6f323b54f8afb2adfd2163ada (diff) |
Merge branch 'wiggly-widgets' into UI-experimentsUI-experiments
Conflicts:
source/blender/blenkernel/intern/customdata.c
source/blender/blenloader/intern/versioning_270.c
source/blender/editors/interface/resources.c
source/blender/editors/transform/transform_manipulator.c
25 files changed, 1310 insertions, 511 deletions
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 46b74c58965..2d1f8ef664d 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -399,6 +399,7 @@ void BKE_camera_params_compute_matrix(CameraParams *params) /***************************** Camera View Frame *****************************/ +/* keep logic in sync with WIDGETGROUP_camera_create */ void BKE_camera_view_frame_ex( const Scene *scene, const Camera *camera, const float drawsize, const bool do_clip, const float scale[3], diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 3b86c42d8c9..54ee5c373c6 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -1572,6 +1572,63 @@ static void cdDM_buffer_copy_uvedge( } } +static void cdDM_buffer_copy_facemap(DerivedMesh *dm, unsigned int *varray) +{ + GPUDrawObject *gdo = dm->drawObject; + int *facemap_iter, *facemap = DM_get_poly_data_layer(dm, CD_FACEMAP); + int i, totpoly, offset = 0; + MPoly *mp_iter, *mp = dm->getPolyArray(dm); + const MLoopTri *ltri = dm->getLoopTriArray(dm); + MLoop *mloop = dm->getLoopArray(dm); + int *facemap_offset; + + totpoly = dm->getNumPolys(dm); + + gdo->totfacemaps = 0; + + facemap_iter = facemap; + + /* pretty crappy to iterate so many times but it's only being done on creation */ + for (i = 0; i < totpoly; i++, facemap_iter++) { + gdo->totfacemaps = max_ii(*facemap_iter, gdo->totfacemaps); + } + /* account for 0 - n -1 range */ + gdo->totfacemaps++; + + gdo->facemap_start = MEM_callocN(gdo->totfacemaps * sizeof(*gdo->facemap_start), "GDO_facemap_start"); + gdo->facemap_count = MEM_callocN(gdo->totfacemaps * sizeof(*gdo->facemap_count), "GDO_facemap_count"); + facemap_offset = MEM_callocN(gdo->totfacemaps * sizeof(*facemap_offset), "facemap_offset"); + + facemap_iter = facemap; + mp_iter = mp; + for (i = 0; i < totpoly; i++, facemap_iter++, mp_iter++) { + gdo->facemap_count[*facemap_iter] += ME_POLY_TRI_TOT(mp_iter); + } + + for (i = 0; i < gdo->totfacemaps; i++) { + gdo->facemap_start[i] = offset; + offset += gdo->facemap_count[i]; + } + + facemap_iter = facemap; + mp_iter = mp; + for (i = 0; i < totpoly; i++, facemap_iter++, mp_iter++) { + int numtri = ME_POLY_TRI_TOT(mp_iter); + int fmap_offset = (gdo->facemap_start[*facemap_iter] + facemap_offset[*facemap_iter]) * 3; + const MLoopTri *ltri_iter = ltri + poly_to_tri_count(i, mp_iter->loopstart); + + facemap_offset[*facemap_iter] += numtri; + + for (; numtri > 0; numtri--) { + varray[fmap_offset++] = gdo->vert_points[mloop[ltri_iter->tri[0]].v].point_index; + varray[fmap_offset++] = gdo->vert_points[mloop[ltri_iter->tri[1]].v].point_index; + varray[fmap_offset++] = gdo->vert_points[mloop[ltri_iter->tri[2]].v].point_index; + } + } + + MEM_freeN(facemap_offset); +} + static void cdDM_copy_gpu_data( DerivedMesh *dm, int type, void *varray_p, const int *mat_orig_to_new, const void *user_data) @@ -1602,6 +1659,9 @@ static void cdDM_copy_gpu_data( case GPU_BUFFER_TRIANGLES: cdDM_buffer_copy_triangles(dm, (unsigned int *)varray_p, mat_orig_to_new); break; + case GPU_BUFFER_FACEMAP: + cdDM_buffer_copy_facemap(dm, (unsigned int *)varray_p); + break; default: break; } diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index c9b059e259e..1525087e9af 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1378,7 +1378,7 @@ const CustomDataMask CD_MASK_BMESH = CD_MASK_PROP_STR | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_MDISPS | CD_MASK_CREASE | CD_MASK_BWEIGHT | CD_MASK_RECAST | CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE | - CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP; + CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP; /** * cover values copied by #BKE_mesh_loops_to_tessdata */ diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 05a55a8996b..6913710b9f9 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -2101,8 +2101,9 @@ static int object_widget_add_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob = ED_object_active_context((bContext *)C); wmWidgetGroupType *wgrouptype = WM_widgetgrouptype_new(WIDGETGROUP_object_manipulator_poll, WIDGETGROUP_object_manipulator_create, - CTX_data_main(C), "View3D", SPACE_VIEW3D, - RGN_TYPE_WINDOW, true); + WM_widgetgroup_keymap_common, + CTX_data_main(C), "View3D", "Object Widgets", + SPACE_VIEW3D, RGN_TYPE_WINDOW, true); /* assign the objects id name to the widget */ strcpy(wgrouptype->idname, ob->id.name); diff --git a/source/blender/editors/object/object_lamp.c b/source/blender/editors/object/object_lamp.c index 922762695be..cb0e5784cc5 100644 --- a/source/blender/editors/object/object_lamp.c +++ b/source/blender/editors/object/object_lamp.c @@ -216,8 +216,6 @@ int WIDGETGROUP_lamp_poll(const struct bContext *C, struct wmWidgetGroupType *UN void WIDGETGROUP_lamp_create(const struct bContext *C, struct wmWidgetGroup *wgroup) { - float color_lamp[4] = {0.5f, 0.5f, 1.0f, 1.0f}; - float color_hi_lamp[4] = {0.8f, 0.8f, 0.45f, 1.0f}; Object *ob = CTX_data_active_object(C); Lamp *la = ob->data; wmWidget *widget; @@ -225,13 +223,18 @@ void WIDGETGROUP_lamp_create(const struct bContext *C, struct wmWidgetGroup *wgr float dir[3]; const char *propname = "spot_size"; + const float color[4] = {0.5f, 0.5f, 1.0f, 1.0f}; + const float color_hi[4] = {0.8f, 0.8f, 0.45f, 1.0f}; + + + negate_v3_v3(dir, ob->obmat[2]); + widget = WIDGET_arrow_new(wgroup, propname, WIDGET_ARROW_STYLE_INVERTED); - WM_widget_set_colors(widget, color_lamp, color_hi_lamp); - RNA_pointer_create(&la->id, &RNA_Lamp, la, &ptr); - WM_widget_set_origin(widget, ob->obmat[3]); - WM_widget_property(widget, ARROW_SLOT_OFFSET_WORLD_SPACE, &ptr, propname); - negate_v3_v3(dir, ob->obmat[2]); + WIDGET_arrow_set_range_fac(widget, 4.0f); WIDGET_arrow_set_direction(widget, dir); + WM_widget_set_origin(widget, ob->obmat[3]); + WM_widget_set_colors(widget, color, color_hi); + WM_widget_set_property(widget, ARROW_SLOT_OFFSET_WORLD_SPACE, &ptr, propname); } diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index faf32161323..ca962d2147a 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -2507,7 +2507,8 @@ static int graph_widget_backdrop_transform_poll(bContext *C) SpaceIpo *sipo = CTX_wm_space_graph(C); ARegion *ar = CTX_wm_region(C); - return ((ar->type->regionid == RGN_TYPE_WINDOW) && + return ((sipo != NULL) && + (ar->type->regionid == RGN_TYPE_WINDOW) && (sipo->flag & SIPO_DRAW_BACKDROP) && (sipo->backdrop_camera)); } @@ -2525,8 +2526,8 @@ static void widgetgroup_backdrop_create(const struct bContext *C, struct wmWidge wgroup, "backdrop_cage", WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM | WIDGET_RECT_TRANSFORM_STYLE_TRANSLATE, width, height); - WM_widget_property(cage, RECT_TRANSFORM_SLOT_OFFSET, op->ptr, "offset"); - WM_widget_property(cage, RECT_TRANSFORM_SLOT_SCALE, op->ptr, "scale"); + WM_widget_set_property(cage, RECT_TRANSFORM_SLOT_OFFSET, op->ptr, "offset"); + WM_widget_set_property(cage, RECT_TRANSFORM_SLOT_SCALE, op->ptr, "scale"); origin[0] = BLI_rcti_size_x(&ar->winrct) / 2.0f; origin[1] = BLI_rcti_size_y(&ar->winrct) / 2.0f; @@ -2539,7 +2540,10 @@ static int graph_widget_backdrop_transform_invoke(bContext *C, wmOperator *op, c ScrArea *sa = CTX_wm_area(C); SpaceIpo *sipo = CTX_wm_space_graph(C); /* no poll, lives always for the duration of the operator */ - wmWidgetGroupType *cagetype = WM_widgetgrouptype_new(NULL, widgetgroup_backdrop_create, CTX_data_main(C), "Graph_Canvas", SPACE_IPO, RGN_TYPE_WINDOW, false); + wmWidgetGroupType *cagetype = WM_widgetgrouptype_new(NULL, widgetgroup_backdrop_create, + WM_widgetgroup_keymap_common, CTX_data_main(C), + "Graph_Canvas", "Backdrop Transform Widgets", + SPACE_IPO, RGN_TYPE_WINDOW, false); struct wmEventHandler *handler = WM_event_add_modal_handler(C, op); BackDropTransformData *data = MEM_mallocN(sizeof(BackDropTransformData), "overdrop transform data"); WM_modal_handler_attach_widgetgroup(C, handler, cagetype, op); @@ -2583,7 +2587,9 @@ static int graph_widget_backdrop_transform_modal(bContext *C, wmOperator *op, co } switch (event->type) { - case EVT_WIDGET_UPDATE: { + case EVT_WIDGET_UPDATE: + case EVT_WIDGET_RELEASED: + { SpaceIpo *sipo = CTX_wm_space_graph(C); RNA_float_get_array(op->ptr, "offset", sipo->backdrop_offset); sipo->backdrop_zoom = RNA_float_get(op->ptr, "scale"); @@ -2613,12 +2619,18 @@ static int graph_widget_backdrop_transform_modal(bContext *C, wmOperator *op, co case ESCKEY: case RIGHTMOUSE: { + ARegion *ar = CTX_wm_region(C); + wmWidgetMap *wmap = ar->widgetmaps.first; SpaceIpo *sipo = CTX_wm_space_graph(C); - copy_v2_v2(sipo->backdrop_offset, data->init_offset); - sipo->backdrop_zoom = data->init_zoom; - graph_widget_backdrop_transform_finish(C, data); - return OPERATOR_CANCELLED; + /* only end modal if we're not dragging a widget */ + if (!wmap->active_widget && event->val == KM_PRESS) { + copy_v2_v2(sipo->backdrop_offset, data->init_offset); + sipo->backdrop_zoom = data->init_zoom; + + graph_widget_backdrop_transform_finish(C, data); + return OPERATOR_CANCELLED; + } } } diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 2c26b784776..08231da5993 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -877,8 +877,8 @@ static void WIDGETGROUP_node_transform_create(const struct bContext *C, struct w RNA_pointer_create(snode->id, &RNA_SpaceNodeEditor, snode, &nodeptr); WM_widget_set_origin(cage, origin); - WM_widget_property(cage, RECT_TRANSFORM_SLOT_OFFSET, &nodeptr, "backdrop_offset"); - WM_widget_property(cage, RECT_TRANSFORM_SLOT_SCALE, &nodeptr, "backdrop_zoom"); + WM_widget_set_property(cage, RECT_TRANSFORM_SLOT_OFFSET, &nodeptr, "backdrop_offset"); + WM_widget_set_property(cage, RECT_TRANSFORM_SLOT_SCALE, &nodeptr, "backdrop_zoom"); } BKE_image_release_ibuf(ima, ibuf, lock); } @@ -888,7 +888,11 @@ static void node_widgets(void) /* create the widgetmap for the area here */ WM_widgetmaptype_find("Node_Canvas", SPACE_NODE, RGN_TYPE_WINDOW, false, true); - WM_widgetgrouptype_new(WIDGETGROUP_node_transform_poll, WIDGETGROUP_node_transform_create, NULL, "Node_Canvas", SPACE_NODE, RGN_TYPE_WINDOW, false); + WM_widgetgrouptype_new(WIDGETGROUP_node_transform_poll, + WIDGETGROUP_node_transform_create, + WM_widgetgroup_keymap_common, + NULL, "Node_Canvas", "Backdrop Transform Widgets", + SPACE_NODE, RGN_TYPE_WINDOW, false); } /* only called once, from space/spacetypes.c */ diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c index d3292db7160..3208a115b18 100644 --- a/source/blender/editors/space_sequencer/sequencer_view.c +++ b/source/blender/editors/space_sequencer/sequencer_view.c @@ -279,8 +279,8 @@ static void widgetgroup_overdrop_create(const struct bContext *C, struct wmWidge wgroup, "overdrop_cage", WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM | WIDGET_RECT_TRANSFORM_STYLE_TRANSLATE, sizex, sizey); - WM_widget_property(cage, RECT_TRANSFORM_SLOT_OFFSET, op->ptr, "offset"); - WM_widget_property(cage, RECT_TRANSFORM_SLOT_SCALE, op->ptr, "scale"); + WM_widget_set_property(cage, RECT_TRANSFORM_SLOT_OFFSET, op->ptr, "offset"); + WM_widget_set_property(cage, RECT_TRANSFORM_SLOT_SCALE, op->ptr, "scale"); origin[0] = BLI_rcti_size_x(&ar->winrct)/2.0f; origin[1] = BLI_rcti_size_y(&ar->winrct)/2.0f; @@ -293,7 +293,10 @@ static int sequencer_overdrop_transform_invoke(bContext *C, wmOperator *op, cons ScrArea *sa = CTX_wm_area(C); SpaceSeq *sseq = CTX_wm_space_seq(C); /* no poll, lives always for the duration of the operator */ - wmWidgetGroupType *cagetype = WM_widgetgrouptype_new(NULL, widgetgroup_overdrop_create, CTX_data_main(C), "Seq_Canvas", SPACE_SEQ, RGN_TYPE_WINDOW, false); + wmWidgetGroupType *cagetype = WM_widgetgrouptype_new(NULL, widgetgroup_overdrop_create, + WM_widgetgroup_keymap_common, CTX_data_main(C), + "Seq_Canvas", "Backdrop Transform Widgets", + SPACE_SEQ, RGN_TYPE_WINDOW, false); struct wmEventHandler *handler = WM_event_add_modal_handler(C, op); OverDropTransformData *data = MEM_mallocN(sizeof(OverDropTransformData), "overdrop transform data"); WM_modal_handler_attach_widgetgroup(C, handler, cagetype, op); @@ -337,14 +340,15 @@ static int sequencer_overdrop_transform_modal(bContext *C, wmOperator *op, const } switch (event->type) { - case EVT_WIDGET_UPDATE: { + case EVT_WIDGET_UPDATE: + case EVT_WIDGET_RELEASED: + { SpaceSeq *sseq = CTX_wm_space_seq(C); RNA_float_get_array(op->ptr, "offset", sseq->overdrop_offset); sseq->overdrop_zoom = RNA_float_get(op->ptr, "scale"); break; } - - case RKEY: + case RKEY: { SpaceSeq *sseq = CTX_wm_space_seq(C); ARegion *ar = CTX_wm_region(C); @@ -369,12 +373,18 @@ static int sequencer_overdrop_transform_modal(bContext *C, wmOperator *op, const case ESCKEY: case RIGHTMOUSE: { + ARegion *ar = CTX_wm_region(C); + wmWidgetMap *wmap = ar->widgetmaps.first; SpaceSeq *sseq = CTX_wm_space_seq(C); - copy_v2_v2(sseq->overdrop_offset, data->init_offset); - sseq->overdrop_zoom = data->init_zoom; - - sequencer_overdrop_finish(C, data); - return OPERATOR_CANCELLED; + + /* only end modal if we're not dragging a widget */ + if (!wmap->active_widget && event->val == KM_PRESS) { + copy_v2_v2(sseq->overdrop_offset, data->init_offset); + sseq->overdrop_zoom = data->init_zoom; + + sequencer_overdrop_finish(C, data); + return OPERATOR_CANCELLED; + } } } @@ -437,7 +447,7 @@ static void widgetgroup_image_transform_create(const struct bContext *C, struct wgroup, "image_cage", WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM | WIDGET_RECT_TRANSFORM_STYLE_TRANSLATE, viewrect[0] * scale[0], viewrect[1] * scale[1]); - WM_widget_property(cage, RECT_TRANSFORM_SLOT_SCALE, op->ptr, "scale"); + WM_widget_set_property(cage, RECT_TRANSFORM_SLOT_SCALE, op->ptr, "scale"); origin[0] = -(v2d->cur.xmin * scale[0]); origin[1] = -(v2d->cur.ymin * scale[1]); @@ -450,8 +460,10 @@ static int sequencer_image_transform_widget_invoke(bContext *C, wmOperator *op, SpaceSeq *sseq = CTX_wm_space_seq(C); Scene *scene = CTX_data_scene(C); /* no poll, lives always for the duration of the operator */ - wmWidgetGroupType *cagetype = WM_widgetgrouptype_new(NULL, widgetgroup_image_transform_create, CTX_data_main(C), - "Seq_Canvas", SPACE_SEQ, RGN_TYPE_PREVIEW, false); + wmWidgetGroupType *cagetype = WM_widgetgrouptype_new(NULL, widgetgroup_image_transform_create, + WM_widgetgroup_keymap_common, CTX_data_main(C), + "Seq_Canvas", "Image Transform Widgets", + SPACE_SEQ, RGN_TYPE_PREVIEW, false); struct wmEventHandler *handler = WM_event_add_modal_handler(C, op); ImageTransformData *data = MEM_mallocN(sizeof(ImageTransformData), "overdrop transform data"); ImBuf *ibuf = sequencer_ibuf_get(CTX_data_main(C), scene, sseq, CFRA, 0, NULL); @@ -519,7 +531,7 @@ static int sequencer_image_transform_widget_modal(bContext *C, wmOperator *op, c /* no offset needed in this case */ offset[0] = offset[1] = 0; - WIDGET_rect_transform_set_offset(wmap->active_widget, offset); + WM_widget_set_offset(wmap->active_widget, offset); break; } diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 7f038a13fd0..1b46040adc1 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -36,6 +36,7 @@ #include "DNA_material_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" +#include "DNA_object_force.h" #include "DNA_scene_types.h" #include "DNA_camera_types.h" #include "DNA_key_types.h" @@ -47,6 +48,7 @@ #include "BLI_utildefines.h" #include "BKE_action.h" +#include "BKE_camera.h" #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_icons.h" @@ -732,36 +734,131 @@ static int WIDGETGROUP_camera_poll(const struct bContext *C, struct wmWidgetGrou { Object *ob = CTX_data_active_object(C); - if (ob && ob->type == OB_CAMERA) { - Camera *ca = ob->data; - return (ca->flag & CAM_SHOWLIMITS) != 0; - } - return false; + return (ob && ob->type == OB_CAMERA); } static void WIDGETGROUP_camera_create(const struct bContext *C, struct wmWidgetGroup *wgroup) { - float color_camera[4] = {1.0f, 0.3f, 0.0f, 1.0f}; - float color_hi_camera[4] = {1.0f, 0.3f, 0.0f, 1.0f}; Object *ob = CTX_data_active_object(C); Camera *ca = ob->data; wmWidget *widget; PointerRNA cameraptr; float dir[3]; - const char *propname = "dof_distance"; - - widget = WIDGET_arrow_new(wgroup, propname, WIDGET_ARROW_STYLE_CROSS); - WM_widget_set_draw_on_hover_only(widget, true); - WM_widget_set_3d_scale(widget, false); - WM_widget_set_colors(widget, color_camera, color_hi_camera); + const bool focallen_widget = true; /* TODO make optional */ RNA_pointer_create(&ca->id, &RNA_Camera, ca, &cameraptr); - WM_widget_set_origin(widget, ob->obmat[3]); - WM_widget_property(widget, ARROW_SLOT_OFFSET_WORLD_SPACE, &cameraptr, propname); negate_v3_v3(dir, ob->obmat[2]); - WIDGET_arrow_set_direction(widget, dir); - WIDGET_arrow_set_up_vector(widget, ob->obmat[1]); - WM_widget_set_scale(widget, ca->drawsize); + + /* dof distance */ + if (ca->flag & CAM_SHOWLIMITS) { + const float color[4] = {1.0f, 0.3f, 0.0f, 1.0f}; + const float color_hi[4] = {1.0f, 0.3f, 0.0f, 1.0f}; + const char *propname = "dof_distance"; + + widget = WIDGET_arrow_new(wgroup, propname, WIDGET_ARROW_STYLE_CROSS); + WIDGET_arrow_set_direction(widget, dir); + WIDGET_arrow_set_up_vector(widget, ob->obmat[1]); + WM_widget_set_flag(widget, WM_WIDGET_DRAW_HOVER, true); + WM_widget_set_flag(widget, WM_WIDGET_SCALE_3D, false); + WM_widget_set_colors(widget, color, color_hi); + WM_widget_set_origin(widget, ob->obmat[3]); + WM_widget_set_property(widget, ARROW_SLOT_OFFSET_WORLD_SPACE, &cameraptr, propname); + WM_widget_set_scale(widget, ca->drawsize); + } + + /* focal length + * - logic/calculations are similar to BKE_camera_view_frame_ex, better keep in sync */ + if (focallen_widget) { + const Scene *scene = CTX_data_scene(C); + const bool is_ortho = (ca->type == CAM_ORTHO); + const float scale_fac = ca->drawsize; + const float half_sensor = 0.5f * ((ca->sensor_fit == CAMERA_SENSOR_FIT_VERT) ? ca->sensor_y : ca->sensor_x); + const float scale[3] = {1.0f / len_v3(ob->obmat[0]), 1.0f / len_v3(ob->obmat[1]), 1.0f / len_v3(ob->obmat[2])}; + const float drawsize = is_ortho ? (0.5f * ca->ortho_scale) : + (scale_fac / ((scale[0] + scale[1] + scale[2]) / 3.0f)); + const float aspx = (float)scene->r.xsch * scene->r.xasp; + const float aspy = (float)scene->r.ysch * scene->r.yasp; + const int sensor_fit = BKE_camera_sensor_fit(ca->sensor_fit, aspx, aspy); + const char *propname = is_ortho ? "ortho_scale" : "lens"; + const bool fit_hor = (sensor_fit == CAMERA_SENSOR_FIT_HOR); + + const float color[4] = {1.0f, 1.0, 0.27f, 0.5f}; + const float color_hi[4] = {1.0f, 1.0, 0.27f, 1.0f}; + + PropertyRNA *prop; + float offset[3], asp[2]; + float min, max, range; + float step, precision; /* dummys, unused */ + + + /* get aspect */ + asp[0] = fit_hor ? 1.0 : aspx / aspy; + asp[1] = fit_hor ? aspy / aspx : 1.0f; + + /* account for lens shifting */ + offset[0] = ((ob->size[0] > 0.0f) ? -2.0f : 2.0f) * ca->shiftx; + offset[1] = 2.0f * ca->shifty; + offset[2] = 0.0f; + + /* get property range */ + prop = RNA_struct_find_property(&cameraptr, propname); + RNA_property_float_ui_range(&cameraptr, prop, &min, &max, &step, &precision); + range = max - min; + + + /* *** actual widget stuff *** */ + + widget = WIDGET_arrow_new(wgroup, propname, (WIDGET_ARROW_STYLE_CONE | WIDGET_ARROW_STYLE_CONSTRAINED)); + + WIDGET_arrow_set_range_fac(widget, is_ortho ? (scale_fac * range) : (drawsize * range / half_sensor)); + WIDGET_arrow_set_direction(widget, dir); + WIDGET_arrow_set_up_vector(widget, ob->obmat[1]); + WIDGET_arrow_cone_set_aspect(widget, asp); + WM_widget_set_property(widget, ARROW_SLOT_OFFSET_WORLD_SPACE, &cameraptr, propname); + WM_widget_set_origin(widget, ob->obmat[3]); + WM_widget_set_offset(widget, offset); + WM_widget_set_scale(widget, drawsize); + WM_widget_set_flag(widget, WM_WIDGET_SCALE_3D, false); + WM_widget_set_colors(widget, color, color_hi); + + } +} + +static int WIDGETGROUP_forcefield_poll(const struct bContext *C, struct wmWidgetGroupType *UNUSED(wgrouptype)) +{ + Object *ob = CTX_data_active_object(C); + + return ob && ob->pd && ob->pd->forcefield; +} + +static void WIDGETGROUP_forcefield_create(const struct bContext *C, struct wmWidgetGroup *wgroup) +{ + Object *ob = CTX_data_active_object(C); + PartDeflect *pd = ob->pd; + PointerRNA ptr; + wmWidget *widget; + + const float size = (ob->type == OB_EMPTY) ? ob->empty_drawsize : 1.0f; + const float ofs[3] = {0.0f, -size, 0.0f}; + + const float col[4] = {0.8f, 0.8f, 0.45f, 0.5f}; + const float col_hi[4] = {0.8f, 0.8f, 0.45f, 1.0f}; + + + /* only wind effector for now */ + if (pd->forcefield == PFIELD_WIND) { + widget = WIDGET_arrow_new(wgroup, "field_strength", WIDGET_ARROW_STYLE_CONSTRAINED); + + RNA_pointer_create(&ob->id, &RNA_FieldSettings, pd, &ptr); + WIDGET_arrow_set_direction(widget, ob->obmat[2]); + WIDGET_arrow_set_ui_range(widget, -200.0f, 200.0f); + WIDGET_arrow_set_range_fac(widget, 6.0f); + WM_widget_set_colors(widget, col, col_hi); + WM_widget_set_origin(widget, ob->obmat[3]); + WM_widget_set_offset(widget, ofs); + WM_widget_set_flag(widget, WM_WIDGET_SCALE_3D, false); + WM_widget_set_property(widget, ARROW_SLOT_OFFSET_WORLD_SPACE, &ptr, "strength"); + } } #if 0 @@ -799,7 +896,7 @@ static void WIDGETGROUP_shapekey_draw(const struct bContext *C, struct wmWidgetG WIDGET_arrow_set_color(widget, color_shape); RNA_pointer_create(&key->id, &RNA_ShapeKey, kb, &shapeptr); WM_widget_set_origin(widget, ob->obmat[3]); - WM_widget_property(widget, ARROW_SLOT_OFFSET_WORLD_SPACE, &shapeptr, "value"); + WM_widget_set_property(widget, ARROW_SLOT_OFFSET_WORLD_SPACE, &shapeptr, "value"); negate_v3_v3(dir, ob->obmat[2]); WIDGET_arrow_set_direction(widget, dir); } @@ -829,7 +926,6 @@ static int WIDGETGROUP_armature_facemap_poll(const struct bContext *C, struct wm static void WIDGETGROUP_armature_facemap_create(const struct bContext *C, struct wmWidgetGroup *wgroup) { - float color_shape[4] = {1.0f, 0.3f, 0.0f, 1.0f}; Object *ob = CTX_data_active_object(C); wmWidget *widget; Object *armature; @@ -839,7 +935,10 @@ static void WIDGETGROUP_armature_facemap_create(const struct bContext *C, struct VirtualModifierData virtualModifierData; int index = 0; bFaceMap *fmap = ob->fmaps.first; - + + const float color_shape[4] = {1.0f, 0.3f, 0.0f, 1.0f}; + + md = modifiers_getVirtualModifierList(ob, &virtualModifierData); /* exception for shape keys because we can edit those */ @@ -857,15 +956,17 @@ static void WIDGETGROUP_armature_facemap_create(const struct bContext *C, struct for (; fmap; fmap = fmap->next, index++) { if (BKE_pose_channel_find_name(armature->pose, fmap->name)) { PointerRNA *opptr; + widget = WIDGET_facemap_new(wgroup, fmap->name, 0, ob, index); + RNA_pointer_create(&ob->id, &RNA_FaceMap, fmap, &famapptr); - WM_widget_property(widget, FACEMAP_SLOT_FACEMAP, &famapptr, "name"); - opptr = WM_widget_operator(widget, "TRANSFORM_OT_translate"); + WM_widget_set_property(widget, FACEMAP_SLOT_FACEMAP, &famapptr, "name"); + WM_widget_set_colors(widget, color_shape, color_shape); + WM_widget_set_flag(widget, WM_WIDGET_DRAW_HOVER, true); + opptr = WM_widget_set_operator(widget, "TRANSFORM_OT_translate"); if ((prop = RNA_struct_find_property(opptr, "release_confirm"))) { RNA_property_boolean_set(opptr, prop, true); } - WM_widget_set_colors(widget, color_shape, color_shape); - WM_widget_set_draw_on_hover_only(widget, true); } } } @@ -875,10 +976,26 @@ static void view3d_widgets(void) { WM_widgetmaptype_find("View3D", SPACE_VIEW3D, RGN_TYPE_WINDOW, true, true); - WM_widgetgrouptype_new(WIDGETGROUP_manipulator_poll, WIDGETGROUP_manipulator_create, NULL, "View3D", SPACE_VIEW3D, RGN_TYPE_WINDOW, true); - WM_widgetgrouptype_new(WIDGETGROUP_lamp_poll, WIDGETGROUP_lamp_create, NULL, "View3D", SPACE_VIEW3D, RGN_TYPE_WINDOW, true); - WM_widgetgrouptype_new(WIDGETGROUP_camera_poll, WIDGETGROUP_camera_create, NULL, "View3D", SPACE_VIEW3D, RGN_TYPE_WINDOW, true); - WM_widgetgrouptype_new(WIDGETGROUP_armature_facemap_poll, WIDGETGROUP_armature_facemap_create, NULL, "View3D", SPACE_VIEW3D, RGN_TYPE_WINDOW, true); + WM_widgetgrouptype_new(WIDGETGROUP_armature_facemap_poll, + WIDGETGROUP_armature_facemap_create, + WM_widgetgroup_keymap_common, + NULL, "View3D", "Face Map Widgets", SPACE_VIEW3D, RGN_TYPE_WINDOW, true); + WM_widgetgrouptype_new(WIDGETGROUP_lamp_poll, + WIDGETGROUP_lamp_create, + WM_widgetgroup_keymap_common, + NULL, "View3D", "Lamp Widgets", SPACE_VIEW3D, RGN_TYPE_WINDOW, true); + WM_widgetgrouptype_new(WIDGETGROUP_forcefield_poll, + WIDGETGROUP_forcefield_create, + WM_widgetgroup_keymap_common, + NULL, "View3D", "Force Field Widgets", SPACE_VIEW3D, RGN_TYPE_WINDOW, true); + WM_widgetgrouptype_new(WIDGETGROUP_camera_poll, + WIDGETGROUP_camera_create, + WM_widgetgroup_keymap_common, + NULL, "View3D", "Camera Widgets", SPACE_VIEW3D, RGN_TYPE_WINDOW, true); + WM_widgetgrouptype_new(WIDGETGROUP_manipulator_poll, + WIDGETGROUP_manipulator_create, + WM_widgetgroup_keymap_common, + NULL, "View3D", "Manipulator Widgets", SPACE_VIEW3D, RGN_TYPE_WINDOW, true); } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 25fa3085596..125246fd05c 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -3774,6 +3774,11 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3 /* main drawing call */ view3d_draw_objects(C, scene, v3d, ar, grid_unit, true, false, do_compositing ? rv3d->compositor : NULL); + /* widgets need to be updated *after* view matrix was set up + * XXX since we do 2 draw calls (with and without depth culling), + * it might be better to have 2 update calls, too */ + WM_widgets_update(C, ar->widgetmaps.first); + /* draw depth culled widgets */ WM_widgets_draw(C, ar->widgetmaps.first, true); /* post process */ @@ -3918,18 +3923,18 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar) const char *grid_unit = NULL; rcti border_rect; bool render_border, clip_border; + bool update_widgets = true; /* if we only redraw render border area, skip opengl draw and also * don't do scissor because it's already set */ render_border = ED_view3d_calc_render_border(scene, v3d, ar, &border_rect); clip_border = (render_border && !BLI_rcti_compare(&ar->drawrct, &border_rect)); - WM_widgets_update(C, ar->widgetmaps.first); - /* draw viewport using opengl */ if (v3d->drawtype != OB_RENDER || !view3d_main_area_do_render_draw(scene) || clip_border) { view3d_main_area_draw_objects(C, scene, v3d, ar, &grid_unit); - + update_widgets = false; /* widgets were updated in view3d_main_area_draw_objects */ + #ifdef DEBUG_DRAW bl_debug_draw(); #endif @@ -3945,7 +3950,12 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar) view3d_main_area_setup_view(scene, v3d, ar, NULL, NULL); glClear(GL_DEPTH_BUFFER_BIT); + + if (update_widgets) { + WM_widgets_update(C, ar->widgetmaps.first); + } WM_widgets_draw(C, ar->widgetmaps.first, false); + ED_region_pixelspace(ar); view3d_main_area_draw_info(C, scene, ar, v3d, grid_unit, render_border); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index a735801ff47..e77ebfc4532 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -484,8 +484,6 @@ typedef struct TransInfo { /* alternative transformation. used to add offset to tracking markers */ #define T_ALT_TRANSFORM (1 << 24) -#define T_USE_WIDGET (1 << 24) - /* TransInfo->modifiers */ #define MOD_CONSTRAINT_SELECT 0x01 #define MOD_PRECISION 0x02 diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index f3009ba0068..f5fc34ff5fd 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1192,15 +1192,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->view = v3d; t->animtimer = (animscreen) ? animscreen->animtimer : NULL; - if (op && ((prop = RNA_struct_find_property(op->ptr, "use_widget_input")) && - RNA_property_is_set(op->ptr, prop))) - { - if (RNA_property_boolean_get(op->ptr, prop)) - t->flag |= T_USE_WIDGET; - } - /* turn manipulator off during transform */ - if ((t->flag & T_MODAL) && !(t->flag & T_USE_WIDGET)) { + if (t->flag & T_MODAL) { t->twtype = v3d->twtype; v3d->twtype = 0; } @@ -1480,7 +1473,7 @@ void postTrans(bContext *C, TransInfo *t) else if (t->spacetype == SPACE_VIEW3D) { View3D *v3d = t->sa->spacedata.first; /* restore manipulator */ - if ((t->flag & T_MODAL) && !(t->flag & T_USE_WIDGET)) { + if (t->flag & T_MODAL) { v3d->twtype = t->twtype; } } diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 522cf15eb10..436e44b4f9c 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -462,7 +462,7 @@ static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], con mul_qt_v3(quat, gmat[0]); /* Y-axis */ - axis_angle_to_quat(quat, axis, M_PI / 2.0); + axis_angle_to_quat(quat, axis, M_PI_2); copy_v3_v3(gmat[1], gmat[0]); mul_qt_v3(quat, gmat[1]); @@ -847,8 +847,6 @@ static int calc_manipulator_stats(const bContext *C) } } else { - float loc[3]; - /* we need the one selected object, if its not active */ ob = OBACT; if (ob && !(ob->flag & SELECT)) @@ -859,9 +857,7 @@ static int calc_manipulator_stats(const bContext *C) if (ob == NULL) ob = base->object; - /* updated object matrix after transform */ - add_v3_v3v3(loc, base->object->loc, base->object->dloc); - calc_tw_center(scene, loc); + calc_tw_center(scene, base->object->loc); protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); totsel++; } @@ -889,8 +885,7 @@ static int calc_manipulator_stats(const bContext *C) /* fall-through */ case V3D_MANIP_NORMAL: if (obedit || ob->mode & OB_MODE_POSE) { - float mat[3][3]; - ED_getTransformOrientationMatrix(C, mat, (v3d->around == V3D_ACTIVE)); + ED_getTransformOrientationMatrix(C, mat, v3d->around); copy_m4_m3(rv3d->twmat, mat); break; } @@ -902,8 +897,7 @@ static int calc_manipulator_stats(const bContext *C) * use the active pones axis for display [#33575], this works as expected on a single bone * and users who select many bones will understand whats going on and what local means * when they start transforming */ - float mat[3][3]; - ED_getTransformOrientationMatrix(C, mat, (v3d->around == V3D_ACTIVE)); + ED_getTransformOrientationMatrix(C, mat, v3d->around); copy_m4_m3(rv3d->twmat, mat); break; } @@ -916,13 +910,10 @@ static int calc_manipulator_stats(const bContext *C) copy_m4_m3(rv3d->twmat, mat); break; default: /* V3D_MANIP_CUSTOM */ - { - float mat[3][3]; if (applyTransformOrientation(C, mat, NULL, v3d->twmode - V3D_MANIP_CUSTOM)) { copy_m4_m3(rv3d->twmat, mat); } break; - } } } @@ -961,11 +952,7 @@ static void manipulator_prepare_mat(Scene *scene, View3D *v3d, RegionView3D *rv3 { Object *ob = OBACT; if ((v3d->around == V3D_ACTIVE) && !scene->obedit && !(ob->mode & OB_MODE_POSE)) { - float loc[3]; - - /* updated object matrix after transform */ - add_v3_v3v3(loc, ob->loc, ob->dloc); - copy_v3_v3(rv3d->twmat[3], loc); + copy_v3_v3(rv3d->twmat[3], ob->obmat[3]); } else { mid_v3_v3v3(rv3d->twmat[3], scene->twmin, scene->twmax); @@ -985,32 +972,33 @@ static void manipulator_prepare_mat(Scene *scene, View3D *v3d, RegionView3D *rv3 } /** - * Sets up \a r_vec for custom arrow widget line drawing. Needed to - * adjust line drawing for combined manipulator axis types. + * Sets up \a r_start and \a r_len to define arrow line range. + * Needed to adjust line drawing for combined manipulator axis types. */ -static void manipulator_line_vec(const View3D *v3d, float r_vec[2][3], const short axis_type) +static void manipulator_line_range(const View3D *v3d, const short axis_type, float *r_start, float *r_len) { const float ofs = 0.2f; - float start[3] = {0.0f, 0.0f, 0.2f}; - float end[3] = {0.0f, 0.0f, 1.0f}; + + *r_start = 0.2f; + *r_len = 1.0f; switch (axis_type) { case MAN_AXES_TRANSLATE: if (v3d->twtype & V3D_MANIP_SCALE) { - start[2] = end[2] - ofs + 0.025f; + *r_start = *r_len - ofs + 0.075f; } if (v3d->twtype & V3D_MANIP_ROTATE) { - end[2] += ofs; + *r_len += ofs; } break; case MAN_AXES_SCALE: if (v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE)) { - end[2] -= ofs + 0.025f; + *r_len -= ofs + 0.025f; } break; } - copy_v3_v3(r_vec[0], start); - copy_v3_v3(r_vec[1], end); + + *r_len -= *r_start; } @@ -1087,7 +1075,7 @@ void WIDGETGROUP_manipulator_create(const struct bContext *C, struct wmWidgetGro const bool trans_visble = (any_visible && (v3d->twtype & V3D_MANIP_TRANSLATE)); const bool rot_visble = (any_visible && (v3d->twtype & V3D_MANIP_ROTATE)); const bool scale_visible = (any_visible && (v3d->twtype & V3D_MANIP_SCALE)); - const ManipulatorGroup *man = manipulatorgroup_init(wgroup, trans_visble, rot_visble, scale_visible); + ManipulatorGroup *man = manipulatorgroup_init(wgroup, trans_visble, rot_visble, scale_visible); if (!man) return; @@ -1101,7 +1089,7 @@ void WIDGETGROUP_manipulator_create(const struct bContext *C, struct wmWidgetGro if (fabsf(mat4_to_scale(rv3d->twmat)) < 1e-7f) { MAN_ITER_AXES_BEGIN { - WM_widget_flag_set(axis, WM_WIDGET_HIDDEN, true); + WM_widget_set_flag(axis, WM_WIDGET_HIDDEN, true); } MAN_ITER_AXES_END; @@ -1118,11 +1106,10 @@ void WIDGETGROUP_manipulator_create(const struct bContext *C, struct wmWidgetGro int constraint_axis[3] = {1, 0, 0}; PointerRNA *ptr; - float line_vec[2][3]; float col[4], col_hi[4]; if (manipulator_is_axis_visible(v3d, rv3d, axis_idx) == false) { - WM_widget_flag_set(axis, WM_WIDGET_HIDDEN, true); + WM_widget_set_flag(axis, WM_WIDGET_HIDDEN, true); continue; } @@ -1141,17 +1128,23 @@ void WIDGETGROUP_manipulator_create(const struct bContext *C, struct wmWidgetGro case MAN_AXIS_SCALE_X: case MAN_AXIS_SCALE_Y: case MAN_AXIS_SCALE_Z: - manipulator_line_vec(v3d, line_vec, axis_type); + { + float start_co[3] = {0.0f, 0.0f, 0.0f}; + float len; + + manipulator_line_range(v3d, axis_type, &start_co[2], &len); WIDGET_arrow_set_direction(axis, rv3d->twmat[aidx_norm]); - WIDGET_arrow_set_line_vec(axis, (const float (*)[3])line_vec, ARRAY_SIZE(line_vec)); + WIDGET_arrow_set_line_len(axis, len); + WM_widget_set_offset(axis, start_co); WM_widget_set_line_width(axis, MAN_AXIS_LINE_WIDTH); break; + } case MAN_AXIS_ROT_X: case MAN_AXIS_ROT_Y: case MAN_AXIS_ROT_Z: + WIDGET_dial_set_up_vector(axis, rv3d->twmat[aidx_norm]); WM_widget_set_line_width(axis, MAN_AXIS_LINE_WIDTH); - WIDGET_dial_set_direction(axis, rv3d->twmat[aidx_norm]); break; case MAN_AXIS_TRANS_XY: case MAN_AXIS_TRANS_YZ: @@ -1167,38 +1160,40 @@ void WIDGETGROUP_manipulator_create(const struct bContext *C, struct wmWidgetGro ofs[1] = ofs_ax; ofs[2] = 0.0f; - WM_widget_set_scale(axis, 0.07f); - WM_widget_set_origin(axis, rv3d->twmat[3]); - WIDGET_plane_set_offset(axis, ofs); WIDGET_plane_set_direction(axis, rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1]); WIDGET_plane_set_up_vector(axis, rv3d->twmat[aidx_norm + 1 > 2 ? 0 : aidx_norm + 1]); + WM_widget_set_scale(axis, 0.07f); + WM_widget_set_origin(axis, rv3d->twmat[3]); + WM_widget_set_offset(axis, ofs); break; } case MAN_AXIS_TRANS_C: case MAN_AXIS_ROT_C: case MAN_AXIS_SCALE_C: + WIDGET_dial_set_up_vector(axis, rv3d->viewinv[2]); if (axis_idx != MAN_AXIS_ROT_C) { WM_widget_set_scale(axis, 0.2f); } - WIDGET_dial_set_direction(axis, rv3d->viewinv[2]); break; } switch (axis_type) { case MAN_AXES_TRANSLATE: - ptr = WM_widget_operator(axis, "TRANSFORM_OT_translate"); + ptr = WM_widget_set_operator(axis, "TRANSFORM_OT_translate"); break; case MAN_AXES_ROTATE: - ptr = WM_widget_operator(axis, "TRANSFORM_OT_rotate"); + ptr = WM_widget_set_operator(axis, "TRANSFORM_OT_rotate"); break; case MAN_AXES_SCALE: - ptr = WM_widget_operator(axis, "TRANSFORM_OT_resize"); + ptr = WM_widget_set_operator(axis, "TRANSFORM_OT_resize"); break; } RNA_boolean_set_array(ptr, "constraint_axis", constraint_axis); RNA_boolean_set(ptr, "release_confirm", 1); } MAN_ITER_AXES_END; + + MEM_freeN(man); } void WIDGETGROUP_object_manipulator_create(const struct bContext *C, struct wmWidgetGroup *wgroup) diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 2c434fb405e..d354cc30f3c 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -95,6 +95,8 @@ const GPUBufferTypeSettings gpu_buffer_type_settings[] = { {GL_ELEMENT_ARRAY_BUFFER_ARB, 4}, /* triangles, 1 point since we are allocating from tottriangle points, which account for all points */ {GL_ELEMENT_ARRAY_BUFFER_ARB, 1}, + /* facemap */ + {GL_ELEMENT_ARRAY_BUFFER_ARB, 3}, }; #define MAX_GPU_ATTRIB_DATA 32 @@ -489,6 +491,10 @@ void GPU_drawobject_free(DerivedMesh *dm) #ifdef USE_GPU_POINT_LINK MEM_freeN(gdo->vert_points_mem); #endif + if (gdo->facemap_start) + MEM_freeN(gdo->facemap_start); + if (gdo->facemap_count) + MEM_freeN(gdo->facemap_count); GPU_buffer_free(gdo->points); GPU_buffer_free(gdo->normals); GPU_buffer_free(gdo->uv); @@ -657,7 +663,7 @@ static size_t gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type) case GPU_BUFFER_TRIANGLES: return sizeof(int) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_triangle_point; case GPU_BUFFER_FACEMAP: - return sizeof(int) * 3 * dm->drawObject->tot_triangle_point; + return sizeof(int) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_triangle_point; default: return -1; } diff --git a/source/blender/makesdna/DNA_widget_types.h b/source/blender/makesdna/DNA_widget_types.h index 6d9c5c02c01..5fa2cd813f8 100644 --- a/source/blender/makesdna/DNA_widget_types.h +++ b/source/blender/makesdna/DNA_widget_types.h @@ -55,8 +55,6 @@ struct wmWidgetGroup { int flag; int pad; - - void *customdata; }; #endif diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 37550b1eaed..a77e41c15af 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -1568,7 +1568,7 @@ static StructRNA *rna_WidgetGroup_register(Main *bmain, ReportList *reports, voi dummywgt.poll = (have_function[0]) ? widgetgroup_poll : NULL; dummywgt.create = (have_function[1]) ? widgetgroup_draw : NULL; - wgrouptype = WM_widgetgrouptype_new(dummywgt.poll, dummywgt.create, bmain, dummywgt.mapidname, dummywgt.spaceid, dummywgt.regionid, dummywgt.is_3d); + wgrouptype = WM_widgetgrouptype_new(dummywgt.poll, dummywgt.create, NULL, bmain, dummywgt.mapidname, NULL, dummywgt.spaceid, dummywgt.regionid, dummywgt.is_3d); memcpy(wgrouptype, &dummywgt, sizeof(dummywgt)); /* update while blender is running */ 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__ */ |