diff options
-rw-r--r-- | source/blender/editors/include/ED_uvedit.h | 1 | ||||
-rw-r--r-- | source/blender/editors/space_image/space_image.c | 41 | ||||
-rw-r--r-- | source/blender/editors/transform/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_manipulator2d.c | 271 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_ops.c | 8 |
5 files changed, 317 insertions, 5 deletions
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index cba2a440959..918489b1159 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -52,6 +52,7 @@ void ED_keymap_uvedit(struct wmKeyConfig *keyconf); void ED_uvedit_assign_image(struct Main *bmain, struct Scene *scene, struct Object *obedit, struct Image *ima, struct Image *previma); bool ED_uvedit_minmax(struct Scene *scene, struct Image *ima, struct Object *obedit, float min[2], float max[2]); +bool ED_uvedit_center(Scene *scene, Image *ima, struct Object *obedit, float cent[2], char mode); void ED_uvedit_select_all(struct BMesh *bm); bool ED_object_get_active_image(struct Object *ob, int mat_nr, diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 56afdce7bb1..4b06cbe6b33 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -64,6 +64,7 @@ #include "ED_space_api.h" #include "ED_screen.h" #include "ED_uvedit.h" +#include "ED_transform.h" #include "BIF_gl.h" @@ -588,6 +589,27 @@ static int image_context(const bContext *C, const char *member, bContextDataResu return 0; } +static void IMAGE_WGT_manipulator2d(wmManipulatorGroupType *wgt) +{ + wgt->name = "UV Transform Manipulator"; + wgt->idname = "IMAGE_WGT_manipulator2d"; + + wgt->flag |= WM_MANIPULATORGROUPTYPE_PERSISTENT; + + wgt->poll = ED_widgetgroup_manipulator2d_poll; + wgt->setup = ED_widgetgroup_manipulator2d_setup; + wgt->refresh = ED_widgetgroup_manipulator2d_refresh; + wgt->draw_prepare = ED_widgetgroup_manipulator2d_draw_prepare; +} + +static void image_widgets(void) +{ + wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure( + &(const struct wmManipulatorMapType_Params){SPACE_IMAGE, RGN_TYPE_WINDOW}); + + WM_manipulatorgrouptype_append_and_link(mmap_type, IMAGE_WGT_manipulator2d); +} + /************************** main region ***************************/ /* sets up the fields of the View2D from zoom and offset */ @@ -651,6 +673,16 @@ static void image_main_region_init(wmWindowManager *wm, ARegion *ar) // image space manages own v2d // UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_STANDARD, ar->winx, ar->winy); + /* manipulators */ + if (ar->manipulator_map == NULL) { + const struct wmManipulatorMapType_Params wmap_params = { + .spaceid = SPACE_IMAGE, + .regionid = RGN_TYPE_WINDOW, + }; + ar->manipulator_map = WM_manipulatormap_new_from_type(&wmap_params); + } + WM_manipulatormap_add_handlers(ar, ar->manipulator_map); + /* mask polls mode */ keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); @@ -676,7 +708,6 @@ static void image_main_region_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); keymap = WM_keymap_find(wm->defaultconf, "Image", SPACE_IMAGE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - } static void image_main_region_draw(const bContext *C, ARegion *ar) @@ -794,6 +825,8 @@ static void image_main_region_draw(const bContext *C, ARegion *ar) UI_view2d_view_restore(C); } + WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_2D); + draw_image_cache(C, ar); /* scrollers? */ @@ -810,6 +843,10 @@ static void image_main_region_listener( { /* context changes */ switch (wmn->category) { + case NC_GEOM: + if (ELEM(wmn->data, ND_DATA, ND_SELECT)) + WM_manipulatormap_tag_refresh(ar->manipulator_map); + break; case NC_GPENCIL: if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) ED_region_tag_redraw(ar); @@ -819,6 +856,7 @@ static void image_main_region_listener( case NC_IMAGE: if (wmn->action == NA_PAINTING) ED_region_tag_redraw(ar); + WM_manipulatormap_tag_refresh(ar->manipulator_map); break; case NC_MATERIAL: if (wmn->data == ND_SHADING_LINKS) { @@ -1049,6 +1087,7 @@ void ED_spacetype_image(void) st->refresh = image_refresh; st->listener = image_listener; st->context = image_context; + st->manipulators = image_widgets; st->id_remap = image_id_remap; /* regions: main window */ diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 1a41d9ac95a..fda15545ead 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -46,6 +46,7 @@ set(SRC transform_generics.c transform_input.c transform_manipulator.c + transform_manipulator2d.c transform_ops.c transform_orientations.c transform_snap.c diff --git a/source/blender/editors/transform/transform_manipulator2d.c b/source/blender/editors/transform/transform_manipulator2d.c new file mode 100644 index 00000000000..7990834ed8c --- /dev/null +++ b/source/blender/editors/transform/transform_manipulator2d.c @@ -0,0 +1,271 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * 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) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/transform/transform_manipulator2d.c + * \ingroup edtransform + * + * \name 2D Transform Manipulator + * + * Used for UV/Image Editor + */ + +#include "BKE_context.h" +#include "BKE_editmesh.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" + +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" + +#include "ED_image.h" +#include "ED_screen.h" +#include "ED_uvedit.h" +#include "ED_manipulator_library.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "wm.h" /* XXX */ + +#include "transform.h" /* own include */ + +/* axes as index */ +enum { + MAN2D_AXIS_TRANS_X = 0, + MAN2D_AXIS_TRANS_Y, + + MAN2D_AXIS_LAST, +}; + +typedef struct ManipulatorGroup2D { + wmManipulator *translate_x, + *translate_y; + + /* Current origin in view space, used to update widget origin for possible view changes */ + float origin[2]; +} ManipulatorGroup2D; + + +/* **************** Utilities **************** */ + +/* loop over axes */ +#define MAN2D_ITER_AXES_BEGIN(axis, axis_idx) \ + { \ + wmManipulator *axis; \ + int axis_idx; \ + for (axis_idx = 0; axis_idx < MAN2D_AXIS_LAST; axis_idx++) { \ + axis = manipulator2d_get_axis_from_index(man, axis_idx); + +#define MAN2D_ITER_AXES_END \ + } \ + } ((void)0) + +static wmManipulator *manipulator2d_get_axis_from_index(const ManipulatorGroup2D *man, const short axis_idx) +{ + BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN2D_AXIS_TRANS_X, (float)MAN2D_AXIS_TRANS_Y)); + + switch (axis_idx) { + case MAN2D_AXIS_TRANS_X: + return man->translate_x; + case MAN2D_AXIS_TRANS_Y: + return man->translate_y; + } + + return NULL; +} + +static void manipulator2d_get_axis_color(const int axis_idx, float *r_col, float *r_col_hi) +{ + const float alpha = 0.6f; + const float alpha_hi = 1.0f; + int col_id; + + switch (axis_idx) { + case MAN2D_AXIS_TRANS_X: + col_id = TH_AXIS_X; + break; + case MAN2D_AXIS_TRANS_Y: + col_id = TH_AXIS_Y; + break; + } + + UI_GetThemeColor4fv(col_id, r_col); + + copy_v4_v4(r_col_hi, r_col); + r_col[3] *= alpha; + r_col_hi[3] *= alpha_hi; +} + +static ManipulatorGroup2D *manipulatorgroup2d_init(wmManipulatorGroup *mgroup) +{ + ManipulatorGroup2D *man = MEM_callocN(sizeof(ManipulatorGroup2D), __func__); + + man->translate_x = ED_manipulator_arrow2d_new(mgroup, "translate_x"); + man->translate_y = ED_manipulator_arrow2d_new(mgroup, "translate_y"); + + return man; +} + +/** + * Calculates origin in view space, use with #manipulator2d_origin_to_region. + */ +static void manipulator2d_calc_origin(const bContext *C, float *r_origin) +{ + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = ED_space_image(sima); + + if (sima->around == V3D_AROUND_CURSOR) { + copy_v2_v2(r_origin, sima->cursor); + } + else { + ED_uvedit_center(CTX_data_scene(C), ima, CTX_data_edit_object(C), r_origin, sima->around); + } +} + +/** + * Convert origin (or any other point) from view to region space. + */ +BLI_INLINE void manipulator2d_origin_to_region(ARegion *ar, float *r_origin) +{ + UI_view2d_view_to_region_fl(&ar->v2d, r_origin[0], r_origin[1], &r_origin[0], &r_origin[1]); +} + +/** + * Custom handler for manipulator widgets + */ +static void manipulator2d_modal( + bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event), const int UNUSED(flag)) +{ + ARegion *ar = CTX_wm_region(C); + float origin[3]; + + manipulator2d_calc_origin(C, origin); + manipulator2d_origin_to_region(ar, origin); + WM_manipulator_set_origin(widget, origin); + + ED_region_tag_redraw(ar); +} + +void ED_widgetgroup_manipulator2d_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + ManipulatorGroup2D *man = manipulatorgroup2d_init(mgroup); + mgroup->customdata = man; + + MAN2D_ITER_AXES_BEGIN(axis, axis_idx) + { + const float offset[3] = {0.0f, 0.2f}; + + float col[4], col_hi[4]; + manipulator2d_get_axis_color(axis_idx, col, col_hi); + + /* custom handler! */ + WM_manipulator_set_fn_custom_modal(axis, manipulator2d_modal); + /* set up widget data */ + ED_manipulator_arrow2d_set_angle(axis, -M_PI_2 * axis_idx); + ED_manipulator_arrow2d_set_line_len(axis, 0.8f); + WM_manipulator_set_offset(axis, offset); + WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH); + WM_manipulator_set_scale(axis, U.manipulator_scale); + WM_manipulator_set_color(axis, col); + WM_manipulator_set_color_highlight(axis, col_hi); + + /* assign operator */ + PointerRNA *ptr = WM_manipulator_set_operator(axis, "TRANSFORM_OT_translate"); + int constraint[3] = {0.0f}; + constraint[(axis_idx + 1) % 2] = 1; + if (RNA_struct_find_property(ptr, "constraint_axis")) + RNA_boolean_set_array(ptr, "constraint_axis", constraint); + RNA_boolean_set(ptr, "release_confirm", 1); + } + MAN2D_ITER_AXES_END; +} + +void ED_widgetgroup_manipulator2d_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + ManipulatorGroup2D *man = mgroup->customdata; + float origin[3]; + + manipulator2d_calc_origin(C, origin); + copy_v2_v2(man->origin, origin); +} + +void ED_widgetgroup_manipulator2d_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + ManipulatorGroup2D *man = mgroup->customdata; + float origin[3] = {UNPACK2(man->origin), 0.0f}; + + manipulator2d_origin_to_region(CTX_wm_region(C), origin); + + MAN2D_ITER_AXES_BEGIN(axis, axis_idx) + { + WM_manipulator_set_origin(axis, origin); + } + MAN2D_ITER_AXES_END; +} + +/* TODO (Julian) + * - Called on every redraw, better to do a more simple poll and check for selection in _refresh + * - UV editing only, could be expanded for other things. + */ +bool ED_widgetgroup_manipulator2d_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) +{ + SpaceImage *sima = CTX_wm_space_image(C); + Object *obedit = CTX_data_edit_object(C); + + if (ED_space_image_show_uvedit(sima, obedit)) { + Image *ima = ED_space_image(sima); + Scene *scene = CTX_data_scene(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* check if there's a selected poly */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, ima, efa)) + continue; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + return true; + } + } + } + } + + return false; +} diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index ced84e04f25..0e33525ceff 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -670,7 +670,7 @@ static bool ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[ return (sel != 0); } -static bool uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], char mode) +bool ED_uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], char mode) { bool changed = false; @@ -1427,7 +1427,7 @@ static void uv_weld_align(bContext *C, int tool) tool = (max[0] - min[0] >= max[1] - min[1]) ? 'y' : 'x'; } - uvedit_center(scene, ima, obedit, cent, 0); + ED_uvedit_center(scene, ima, obedit, cent, 0); if (tool == 'x' || tool == 'w') { BMIter iter, liter; @@ -3124,7 +3124,7 @@ static void uv_snap_cursor_to_pixels(SpaceImage *sima) static bool uv_snap_cursor_to_selection(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima) { - return uvedit_center(scene, ima, obedit, sima->cursor, sima->around); + return ED_uvedit_center(scene, ima, obedit, sima->cursor, sima->around); } static int uv_snap_cursor_exec(bContext *C, wmOperator *op) @@ -3338,7 +3338,7 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op) case 2: { float center[2]; - if (uvedit_center(scene, ima, obedit, center, sima->around)) { + if (ED_uvedit_center(scene, ima, obedit, center, sima->around)) { float offset[2]; sub_v2_v2v2(offset, sima->cursor, center); changed = uv_snap_uvs_offset(scene, ima, obedit, offset); |