WIP: Pan and zoom gizmos for compositor backdrop #1

Draft
Habib Gahbiche wants to merge 4 commits from com-backdrop-pan-zoom into node-pan-zoom

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
8 changed files with 321 additions and 58 deletions
Showing only changes of commit 9edfb6345b - Show all commits

View File

@ -837,7 +837,6 @@ class NODE_PT_backdrop(Panel):
col.separator()
col.operator("node.backimage_move", text="Move")
col.operator("node.backimage_fit", text="Fit")

View File

@ -154,3 +154,8 @@ bool ED_space_node_get_position(
*/
bool ED_space_node_color_sample(
Main *bmain, SpaceNode *snode, ARegion *region, const int mval[2], float r_col[3]);
/**
* Returns the size of the compositor backdrop image.
*/
void ED_space_node_get_backdrop_size(Main *bmain, int *r_width, int *r_height);

View File

@ -483,6 +483,7 @@ void UI_view2d_smooth_view(const bContext *C, ARegion *region, const rctf *cur,
* Caller defines the name for gizmo group.
*/
void VIEW2D_GGT_navigate_impl(wmGizmoGroupType *gzgt, const char *idname);
void VIEW2D_GGT_navigate_backdrop_impl(wmGizmoGroupType *gzgt, const char *idname);
/** \} */

View File

@ -91,6 +91,19 @@ static NavigateGizmoInfo g_navigate_params_for_view2d[GZ_INDEX_TOTAL] = {
},
};
static NavigateGizmoInfo g_navigate_params_for_space_node_backdrop[GZ_INDEX_TOTAL] = {
{
"NODE_OT_backimage_move",
"GIZMO_GT_button_2d",
ICON_VIEW_PAN,
},
{
"NODE_OT_backimage_zoom",
"GIZMO_GT_button_2d",
ICON_VIEW_ZOOM,
},
};
static NavigateGizmoInfo *navigate_params_from_space_type(short space_type)
{
switch (space_type) {
@ -106,58 +119,20 @@ static NavigateGizmoInfo *navigate_params_from_space_type(short space_type)
struct NavigateWidgetGroup {
wmGizmo *gz_array[GZ_INDEX_TOTAL];
/* Sets position of first gizmo in group. Needed to avoid overlap with other gizmo groups. */
int slot_offset;
/* Store the view state to check for changes. */
struct {
rcti rect_visible;
} state;
};
static bool WIDGETGROUP_navigate_poll(const bContext *C, wmGizmoGroupType * /*gzgt*/)
static void navigate_setup(const NavigateGizmoInfo *navigate_params,
NavigateWidgetGroup *navgroup,
wmGizmoGroup *gzgroup)
{
if ((U.uiflag & USER_SHOW_GIZMO_NAVIGATE) == 0) {
return false;
}
ScrArea *area = CTX_wm_area(C);
if (area == nullptr) {
return false;
}
switch (area->spacetype) {
case SPACE_SEQ: {
const SpaceSeq *sseq = static_cast<const SpaceSeq *>(area->spacedata.first);
if (sseq->gizmo_flag & (SEQ_GIZMO_HIDE | SEQ_GIZMO_HIDE_NAVIGATE)) {
return false;
}
break;
}
case SPACE_IMAGE: {
const SpaceImage *sima = static_cast<const SpaceImage *>(area->spacedata.first);
if (sima->gizmo_flag & (SI_GIZMO_HIDE | SI_GIZMO_HIDE_NAVIGATE)) {
return false;
}
break;
}
case SPACE_CLIP: {
const SpaceClip *sc = static_cast<const SpaceClip *>(area->spacedata.first);
if (sc->gizmo_flag & (SCLIP_GIZMO_HIDE | SCLIP_GIZMO_HIDE_NAVIGATE)) {
return false;
}
break;
}
case SPACE_NODE: {
const SpaceNode *snode = static_cast<const SpaceNode *>(area->spacedata.first);
if (snode->gizmo_flag & (SNODE_GIZMO_HIDE | SNODE_GIZMO_HIDE_NAVIGATE))
return false;
} break;
}
return true;
}
static void WIDGETGROUP_navigate_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
{
NavigateWidgetGroup *navgroup = MEM_cnew<NavigateWidgetGroup>(__func__);
const NavigateGizmoInfo *navigate_params = navigate_params_from_space_type(
gzgroup->type->gzmap_params.spaceid);
BLI_assert(navigate_params != nullptr);
BLI_assert(navgroup != nullptr);
for (int i = 0; i < GZ_INDEX_TOTAL; i++) {
const NavigateGizmoInfo *info = &navigate_params[i];
@ -211,6 +186,57 @@ static void WIDGETGROUP_navigate_setup(const bContext * /*C*/, wmGizmoGroup *gzg
gzgroup->customdata = navgroup;
}
static bool WIDGETGROUP_navigate_poll(const bContext *C, wmGizmoGroupType * /*gzgt*/)
{
if ((U.uiflag & USER_SHOW_GIZMO_NAVIGATE) == 0) {
return false;
}
ScrArea *area = CTX_wm_area(C);
if (area == nullptr) {
return false;
}
switch (area->spacetype) {
case SPACE_SEQ: {
const SpaceSeq *sseq = static_cast<const SpaceSeq *>(area->spacedata.first);
if (sseq->gizmo_flag & (SEQ_GIZMO_HIDE | SEQ_GIZMO_HIDE_NAVIGATE)) {
return false;
}
break;
}
case SPACE_IMAGE: {
const SpaceImage *sima = static_cast<const SpaceImage *>(area->spacedata.first);
if (sima->gizmo_flag & (SI_GIZMO_HIDE | SI_GIZMO_HIDE_NAVIGATE)) {
return false;
}
break;
}
case SPACE_CLIP: {
const SpaceClip *sc = static_cast<const SpaceClip *>(area->spacedata.first);
if (sc->gizmo_flag & (SCLIP_GIZMO_HIDE | SCLIP_GIZMO_HIDE_NAVIGATE)) {
return false;
}
break;
}
case SPACE_NODE: {
const SpaceNode *snode = static_cast<const SpaceNode *>(area->spacedata.first);
if (snode->gizmo_flag & (SNODE_GIZMO_HIDE | SNODE_GIZMO_HIDE_NAVIGATE))
return false;
} break;
}
return true;
}
static void WIDGETGROUP_navigate_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
{
NavigateWidgetGroup *navgroup = MEM_cnew<NavigateWidgetGroup>(__func__);
navgroup->slot_offset = 0;
const NavigateGizmoInfo *navigate_params = navigate_params_from_space_type(
gzgroup->type->gzmap_params.spaceid);
navigate_setup(navigate_params, navgroup, gzgroup);
}
static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
NavigateWidgetGroup *navgroup = static_cast<NavigateWidgetGroup *>(gzgroup->customdata);
@ -240,7 +266,7 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
int icon_mini_slot = 0;
int icon_mini_slot = navgroup->slot_offset;
gz = navgroup->gz_array[GZ_INDEX_ZOOM];
gz->matrix_basis[3][0] = roundf(co[0]);
@ -267,3 +293,46 @@ void VIEW2D_GGT_navigate_impl(wmGizmoGroupType *gzgt, const char *idname)
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Compositor Backdrop Navigation Gizmo Group
* \{ */
static bool WIDGETGROUP_navigate_backdrop_poll(const bContext *C, wmGizmoGroupType * /*gzgt*/)
{
ScrArea *area = CTX_wm_area(C);
const SpaceNode *snode = static_cast<const SpaceNode *>(area->spacedata.first);
if (snode->gizmo_flag & (SNODE_GIZMO_HIDE | SNODE_GIZMO_HIDE_NAVIGATE) ||
(snode->flag & SNODE_BACKDRAW) == 0)
{
return false;
}
return true;
}
static void WIDGETGROUP_navigate_backdrop_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
{
NavigateWidgetGroup *navgroup = MEM_cnew<NavigateWidgetGroup>(__func__);
/* 2D views occupy 2 Gizmos for pan and zoom. Backdrop gizmos come right after. */
navgroup->slot_offset = 3;
const NavigateGizmoInfo *navigate_params = g_navigate_params_for_space_node_backdrop;
navigate_setup(navigate_params, navgroup, gzgroup);
}
void VIEW2D_GGT_navigate_backdrop_impl(wmGizmoGroupType *gzgt, const char *idname)
{
gzgt->name = "2D View Backdrop Navigate";
gzgt->idname = idname;
gzgt->flag |= (WM_GIZMOGROUPTYPE_PERSISTENT | WM_GIZMOGROUPTYPE_SCALE |
WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL);
gzgt->poll = WIDGETGROUP_navigate_backdrop_poll;
gzgt->setup = WIDGETGROUP_navigate_backdrop_setup;
gzgt->draw_prepare = WIDGETGROUP_navigate_draw_prepare;
}
/** \} */

View File

@ -637,4 +637,15 @@ void NODE_GGT_navigate(wmGizmoGroupType *gzgt)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Compositor backdrop navigate
* \{ */
void VIEW2D_GGT_navigate_backdrop(wmGizmoGroupType *gzgt)
{
VIEW2D_GGT_navigate_backdrop_impl(gzgt, "VIEW2D_GGT_navigate_backdrop");
}
/** \} */
} // namespace blender::ed::space_node

View File

@ -401,6 +401,7 @@ void NODE_GGT_backdrop_crop(wmGizmoGroupType *gzgt);
void NODE_GGT_backdrop_sun_beams(wmGizmoGroupType *gzgt);
void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt);
void NODE_GGT_navigate(wmGizmoGroupType *gzgt);
void VIEW2D_GGT_navigate_backdrop(wmGizmoGroupType *gzgt);
/* `node_geometry_attribute_search.cc` */

View File

@ -10,6 +10,7 @@
#include "BLI_rect.h"
#include "BLI_string_ref.hh"
#include "BLI_time.h"
#include "BLI_utildefines.h"
#include "BKE_context.hh"
@ -330,20 +331,174 @@ void NODE_OT_backimage_move(wmOperatorType *ot)
/** \name Background Image Zoom
* \{ */
static int backimage_zoom_exec(bContext *C, wmOperator *op)
static void snode_zoom_set(
SpaceNode *snode, ARegion *region, float zoom, const int width, const int height)
{
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
float fac = RNA_float_get(op->ptr, "factor");
float oldzoom = snode->zoom;
snode->zoom = zoom;
snode->zoom *= fac;
ED_region_tag_redraw(region);
WM_main_add_notifier(NC_NODE | ND_DISPLAY, nullptr);
WM_main_add_notifier(NC_SPACE | ND_SPACE_NODE_VIEW, nullptr);
if (snode->zoom < 0.1f || snode->zoom > 4.0f) {
return OPERATOR_FINISHED;
/* Multiply with width and height to get the same zoom speed for all image sizes. */
int width_fac = width * snode->zoom;
int height_fac = height * snode->zoom;
if ((width_fac < 4) && (height_fac < 4) && snode->zoom < oldzoom) {
snode->zoom = oldzoom;
}
else if (BLI_rcti_size_x(&region->winrct) <= snode->zoom) {
snode->zoom = oldzoom;
}
else if (BLI_rcti_size_y(&region->winrct) <= snode->zoom) {
snode->zoom = oldzoom;
}
}
}
struct ViewZoomData {
float origx, origy;
float zoom;
int launch_event;
float location[2];
/* Needed for continuous zoom. */
wmTimer *timer;
double timer_lastdraw;
bool own_cursor;
SpaceNode *snode;
ARegion *region;
};
static void snode_bg_viewzoom_init(bContext *C, wmOperator *op, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
ViewZoomData *vpd;
op->customdata = vpd = static_cast<ViewZoomData *>(
MEM_callocN(sizeof(ViewZoomData), "ImageViewZoomData"));
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
vpd->origx = event->xy[0];
vpd->origy = event->xy[1];
vpd->zoom = snode->zoom;
vpd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
if (U.viewzoom == USER_ZOOM_CONTINUE) {
/* needs a timer to continue redrawing */
vpd->timer = WM_event_timer_add(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
vpd->timer_lastdraw = BLI_time_now_seconds();
}
vpd->snode = snode;
vpd->region = region;
WM_event_add_modal_handler(C, op);
}
static int snode_bg_viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
snode_bg_viewzoom_init(C, op, event);
return OPERATOR_RUNNING_MODAL;
}
static void snode_bg_viewzoom_apply(
ViewZoomData *vpd, wmOperator *op, const int x, const int y, const int width, const int height)
{
float delta, factor;
delta = x - vpd->origx + y - vpd->origy;
delta /= U.pixelsize;
factor = 1.0f + delta / 300.0f;
RNA_float_set(op->ptr, "factor", factor);
snode_zoom_set(vpd->snode, vpd->region, vpd->zoom * factor, width, height);
ED_region_tag_redraw(vpd->region);
WM_main_add_notifier(NC_NODE | ND_DISPLAY, nullptr);
WM_main_add_notifier(NC_SPACE | ND_SPACE_NODE_VIEW, nullptr);
}
enum {
VIEW_PASS = 0,
VIEW_APPLY,
VIEW_CONFIRM,
};
static void snode_bg_viewzoom_exit(bContext *C, wmOperator *op, bool cancel)
{
SpaceNode *snode = CTX_wm_space_node(C);
ViewZoomData *vpd = static_cast<ViewZoomData *>(op->customdata);
if (cancel) {
snode->zoom = vpd->zoom;
ED_region_tag_redraw(CTX_wm_region(C));
}
if (vpd->timer) {
WM_event_timer_remove(CTX_wm_manager(C), vpd->timer->win, vpd->timer);
}
if (vpd->own_cursor) {
WM_cursor_modal_restore(CTX_wm_window(C));
}
MEM_freeN(op->customdata);
}
static int snode_bg_viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
ViewZoomData *vpd = static_cast<ViewZoomData *>(op->customdata);
short event_code = VIEW_PASS;
int ret = OPERATOR_RUNNING_MODAL;
/* Execute the events. */
if (event->type == MOUSEMOVE) {
event_code = VIEW_APPLY;
}
else if (event->type == TIMER) {
/* Continuous zoom. */
if (event->customdata == vpd->timer) {
event_code = VIEW_APPLY;
}
}
else if (event->type == vpd->launch_event) {
if (event->val == KM_RELEASE) {
event_code = VIEW_CONFIRM;
}
}
int width, height;
ED_space_node_get_backdrop_size(bmain, &width, &height);
switch (event_code) {
case VIEW_APPLY: {
snode_bg_viewzoom_apply(vpd, op, event->xy[0], event->xy[1], width, height);
break;
}
case VIEW_CONFIRM: {
ret = OPERATOR_FINISHED;
break;
}
}
if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
snode_bg_viewzoom_exit(C, op, false);
}
return ret;
}
/* Similar in functionality to IMAGE_OT_view_zoom. */
void NODE_OT_backimage_zoom(wmOperatorType *ot)
{
@ -353,11 +508,12 @@ void NODE_OT_backimage_zoom(wmOperatorType *ot)
ot->description = "Zoom in/out the background image";
/* api callbacks */
ot->exec = backimage_zoom_exec;
ot->poll = space_node_composite_active_view_poll;
ot->invoke = snode_bg_viewzoom_invoke;
ot->modal = snode_bg_viewzoom_modal;
/* flags */
ot->flag = OPTYPE_BLOCKING;
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY | OPTYPE_LOCK_BYPASS;
/* internal */
RNA_def_float(ot->srna, "factor", 1.2f, 0.0f, 10.0f, "Factor", "", 0.0f, 10.0f);
@ -548,6 +704,26 @@ bool ED_space_node_color_sample(
return ret;
}
void ED_space_node_get_backdrop_size(Main *bmain, int *r_width, int *r_height)
{
Image *ima;
ImBuf *ibuf;
void *lock;
ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
if (ibuf == nullptr) {
BKE_image_release_ibuf(ima, ibuf, lock);
return;
}
BKE_image_release_ibuf(ima, ibuf, lock);
*r_width = ibuf->x;
*r_height = ibuf->y;
}
namespace blender::ed::space_node {
static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)

View File

@ -1138,6 +1138,7 @@ static void node_widgets()
WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_sun_beams);
WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_corner_pin);
WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_navigate);
WM_gizmogrouptype_append_and_link(gzmap_type, VIEW2D_GGT_navigate_backdrop);
}
static void node_id_remap(ID *old_id, ID *new_id, SpaceNode *snode)