add view selected for node view
[blender.git] / source / blender / editors / space_node / node_view.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation, Nathan Letwory
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_node/node_view.c
28  *  \ingroup spnode
29  */
30
31 #include "DNA_node_types.h"
32
33 #include "BLI_rect.h"
34 #include "BLI_utildefines.h"
35
36 #include "BKE_context.h"
37 #include "BKE_image.h"
38 #include "BKE_screen.h"
39
40 #include "ED_node.h"  /* own include */
41 #include "ED_screen.h"
42 #include "ED_space_api.h"
43 #include "ED_image.h"
44
45 #include "RNA_access.h"
46 #include "RNA_define.h"
47
48 #include "WM_api.h"
49 #include "WM_types.h"
50
51 #include "UI_view2d.h"
52
53 #include "MEM_guardedalloc.h"
54
55 #include "IMB_imbuf.h"
56 #include "IMB_imbuf_types.h"
57
58 #include "node_intern.h"  /* own include */
59
60
61 /* **************** View All Operator ************** */
62
63 static int snode_home(ScrArea *UNUSED(sa), ARegion *ar, SpaceNode *snode, const int node_flag)
64 {
65         bNode *node;
66         rctf cur_new;
67         float oldwidth, oldheight, width, height;
68         int change = FALSE;
69         
70         
71         oldwidth = ar->v2d.cur.xmax - ar->v2d.cur.xmin;
72         oldheight = ar->v2d.cur.ymax - ar->v2d.cur.ymin;
73
74         BLI_rctf_init_minmax(&cur_new);
75
76         if (snode->edittree) {
77                 for (node = snode->edittree->nodes.first; node; node = node->next) {
78                         if ((node->flag & node_flag) == node_flag) {
79                                 BLI_rctf_union(&cur_new, &node->totr);
80                                 change = TRUE;
81                         }
82                 }
83         }
84
85         if (change) {
86                 snode->xof = 0;
87                 snode->yof = 0;
88                 width = cur_new.xmax - cur_new.xmin;
89                 height = cur_new.ymax - cur_new.ymin;
90
91                 if (width > height) {
92                         float newheight;
93                         newheight = oldheight * width / oldwidth;
94                         cur_new.ymin = cur_new.ymin - newheight / 4;
95                         cur_new.ymax = cur_new.ymax + newheight / 4;
96                 }
97                 else {
98                         float newwidth;
99                         newwidth = oldwidth * height / oldheight;
100                         cur_new.xmin = cur_new.xmin - newwidth / 4;
101                         cur_new.xmax = cur_new.xmax + newwidth / 4;
102                 }
103
104                 ar->v2d.tot = ar->v2d.cur = cur_new;
105                 UI_view2d_curRect_validate(&ar->v2d);
106         }
107
108         return change;
109 }
110
111 static int node_view_all_exec(bContext *C, wmOperator *UNUSED(op))
112 {
113         ScrArea *sa = CTX_wm_area(C);
114         ARegion *ar = CTX_wm_region(C);
115         SpaceNode *snode = CTX_wm_space_node(C);
116         
117         if (snode_home(sa, ar, snode, 0)) {
118                 ED_region_tag_redraw(ar);
119
120                 return OPERATOR_FINISHED;
121         }
122         else {
123                 return OPERATOR_CANCELLED;
124         }
125 }
126
127 void NODE_OT_view_all(wmOperatorType *ot)
128 {
129         /* identifiers */
130         ot->name = "View All";
131         ot->idname = "NODE_OT_view_all";
132         ot->description = "Resize view so you can see all nodes";
133         
134         /* api callbacks */
135         ot->exec = node_view_all_exec;
136         ot->poll = ED_operator_node_active;
137         
138         /* flags */
139         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
140 }
141
142 static int node_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
143 {
144         ScrArea *sa = CTX_wm_area(C);
145         ARegion *ar = CTX_wm_region(C);
146         SpaceNode *snode = CTX_wm_space_node(C);
147
148         if (snode_home(sa, ar, snode, NODE_SELECT)) {
149                 ED_region_tag_redraw(ar);
150
151                 return OPERATOR_FINISHED;
152         }
153         else {
154                 return OPERATOR_CANCELLED;
155         }
156 }
157
158 void NODE_OT_view_selected(wmOperatorType *ot)
159 {
160         /* identifiers */
161         ot->name = "View Selected";
162         ot->idname = "NODE_OT_view_selected";
163         ot->description = "Resize view so you can see selected nodes";
164
165         /* api callbacks */
166         ot->exec = node_view_selected_exec;
167         ot->poll = ED_operator_node_active;
168
169         /* flags */
170         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
171 }
172
173 /* **************** Backround Image Operators ************** */
174
175 typedef struct NodeViewMove {
176         int mvalo[2];
177         int xmin, ymin, xmax, ymax;
178 } NodeViewMove;
179
180 static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
181 {
182         SpaceNode *snode = CTX_wm_space_node(C);
183         ARegion *ar = CTX_wm_region(C);
184         NodeViewMove *nvm = op->customdata;
185
186         switch (event->type) {
187                 case MOUSEMOVE:
188
189                         snode->xof -= (nvm->mvalo[0] - event->mval[0]);
190                         snode->yof -= (nvm->mvalo[1] - event->mval[1]);
191                         nvm->mvalo[0] = event->mval[0];
192                         nvm->mvalo[1] = event->mval[1];
193
194                         /* prevent dragging image outside of the window and losing it! */
195                         CLAMP(snode->xof, nvm->xmin, nvm->xmax);
196                         CLAMP(snode->yof, nvm->ymin, nvm->ymax);
197
198                         ED_region_tag_redraw(ar);
199
200                         break;
201
202                 case LEFTMOUSE:
203                 case MIDDLEMOUSE:
204                 case RIGHTMOUSE:
205
206                         MEM_freeN(nvm);
207                         op->customdata = NULL;
208
209                         return OPERATOR_FINISHED;
210         }
211
212         return OPERATOR_RUNNING_MODAL;
213 }
214
215 static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
216 {
217         SpaceNode *snode = CTX_wm_space_node(C);
218         ARegion *ar = CTX_wm_region(C);
219         NodeViewMove *nvm;
220         Image *ima;
221         ImBuf *ibuf;
222         const float pad = 32.0f; /* better be bigger then scrollbars */
223
224         void *lock;
225
226         ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
227         ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
228
229         if (ibuf == NULL) {
230                 BKE_image_release_ibuf(ima, lock);
231                 return OPERATOR_CANCELLED;
232         }
233
234         nvm = MEM_callocN(sizeof(NodeViewMove), "NodeViewMove struct");
235         op->customdata = nvm;
236         nvm->mvalo[0] = event->mval[0];
237         nvm->mvalo[1] = event->mval[1];
238
239         nvm->xmin = -(ar->winx / 2) - (ibuf->x * (0.5f * snode->zoom)) + pad;
240         nvm->xmax =  (ar->winx / 2) + (ibuf->x * (0.5f * snode->zoom)) - pad;
241         nvm->ymin = -(ar->winy / 2) - (ibuf->y * (0.5f * snode->zoom)) + pad;
242         nvm->ymax =  (ar->winy / 2) + (ibuf->y * (0.5f * snode->zoom)) - pad;
243
244         BKE_image_release_ibuf(ima, lock);
245
246         /* add modal handler */
247         WM_event_add_modal_handler(C, op);
248
249         return OPERATOR_RUNNING_MODAL;
250 }
251
252 static int snode_bg_viewmove_cancel(bContext *UNUSED(C), wmOperator *op)
253 {
254         MEM_freeN(op->customdata);
255         op->customdata = NULL;
256
257         return OPERATOR_CANCELLED;
258 }
259
260 void NODE_OT_backimage_move(wmOperatorType *ot)
261 {
262         /* identifiers */
263         ot->name = "Background Image Move";
264         ot->description = "Move Node backdrop";
265         ot->idname = "NODE_OT_backimage_move";
266
267         /* api callbacks */
268         ot->invoke = snode_bg_viewmove_invoke;
269         ot->modal = snode_bg_viewmove_modal;
270         ot->poll = composite_node_active;
271         ot->cancel = snode_bg_viewmove_cancel;
272
273         /* flags */
274         ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
275 }
276
277 static int backimage_zoom(bContext *C, wmOperator *op)
278 {
279         SpaceNode *snode = CTX_wm_space_node(C);
280         ARegion *ar = CTX_wm_region(C);
281         float fac = RNA_float_get(op->ptr, "factor");
282
283         snode->zoom *= fac;
284         ED_region_tag_redraw(ar);
285
286         return OPERATOR_FINISHED;
287 }
288
289
290 void NODE_OT_backimage_zoom(wmOperatorType *ot)
291 {
292
293         /* identifiers */
294         ot->name = "Background Image Zoom";
295         ot->idname = "NODE_OT_backimage_zoom";
296         ot->description = "Zoom in/out the background image";
297
298         /* api callbacks */
299         ot->exec = backimage_zoom;
300         ot->poll = composite_node_active;
301
302         /* flags */
303         ot->flag = OPTYPE_BLOCKING;
304
305         /* internal */
306         RNA_def_float(ot->srna, "factor", 1.2f, 0.0f, 10.0f, "Factor", "", 0.0f, 10.0f);
307 }
308
309 /******************** sample backdrop operator ********************/
310
311 typedef struct ImageSampleInfo {
312         ARegionType *art;
313         void *draw_handle;
314         int x, y;
315         int channels;
316         int color_manage;
317
318         unsigned char col[4];
319         float colf[4];
320
321         int draw;
322 } ImageSampleInfo;
323
324 static void sample_draw(const bContext *C, ARegion *ar, void *arg_info)
325 {
326         Scene *scene = CTX_data_scene(C);
327         ImageSampleInfo *info = arg_info;
328
329         if (info->draw) {
330                 ED_image_draw_info(ar, (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT), info->channels,
331                                    info->x, info->y, info->col, info->colf,
332                                    NULL, NULL /* zbuf - unused for nodes */
333                                    );
334         }
335 }
336
337 static void sample_apply(bContext *C, wmOperator *op, wmEvent *event)
338 {
339         SpaceNode *snode = CTX_wm_space_node(C);
340         ARegion *ar = CTX_wm_region(C);
341         ImageSampleInfo *info = op->customdata;
342         void *lock;
343         Image *ima;
344         ImBuf *ibuf;
345         float fx, fy, bufx, bufy;
346
347         ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
348         ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
349         if (!ibuf) {
350                 info->draw = 0;
351                 return;
352         }
353
354         if (!ibuf->rect) {
355                 if (info->color_manage)
356                         ibuf->profile = IB_PROFILE_LINEAR_RGB;
357                 else
358                         ibuf->profile = IB_PROFILE_NONE;
359                 IMB_rect_from_float(ibuf);
360         }
361
362         /* map the mouse coords to the backdrop image space */
363         bufx = ibuf->x * snode->zoom;
364         bufy = ibuf->y * snode->zoom;
365         fx = (bufx > 0.0f ? ((float)event->mval[0] - 0.5f * ar->winx - snode->xof) / bufx + 0.5f : 0.0f);
366         fy = (bufy > 0.0f ? ((float)event->mval[1] - 0.5f * ar->winy - snode->yof) / bufy + 0.5f : 0.0f);
367
368         if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
369                 float *fp;
370                 char *cp;
371                 int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
372
373                 CLAMP(x, 0, ibuf->x - 1);
374                 CLAMP(y, 0, ibuf->y - 1);
375
376                 info->x = x;
377                 info->y = y;
378                 info->draw = 1;
379                 info->channels = ibuf->channels;
380
381                 if (ibuf->rect) {
382                         cp = (char *)(ibuf->rect + y * ibuf->x + x);
383
384                         info->col[0] = cp[0];
385                         info->col[1] = cp[1];
386                         info->col[2] = cp[2];
387                         info->col[3] = cp[3];
388
389                         info->colf[0] = (float)cp[0] / 255.0f;
390                         info->colf[1] = (float)cp[1] / 255.0f;
391                         info->colf[2] = (float)cp[2] / 255.0f;
392                         info->colf[3] = (float)cp[3] / 255.0f;
393                 }
394                 if (ibuf->rect_float) {
395                         fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
396
397                         info->colf[0] = fp[0];
398                         info->colf[1] = fp[1];
399                         info->colf[2] = fp[2];
400                         info->colf[3] = fp[3];
401                 }
402
403                 ED_node_sample_set(info->colf);
404         }
405         else {
406                 info->draw = 0;
407                 ED_node_sample_set(NULL);
408         }
409
410         BKE_image_release_ibuf(ima, lock);
411
412         ED_area_tag_redraw(CTX_wm_area(C));
413 }
414
415 static void sample_exit(bContext *C, wmOperator *op)
416 {
417         ImageSampleInfo *info = op->customdata;
418
419         ED_node_sample_set(NULL);
420         ED_region_draw_cb_exit(info->art, info->draw_handle);
421         ED_area_tag_redraw(CTX_wm_area(C));
422         MEM_freeN(info);
423 }
424
425 static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
426 {
427         SpaceNode *snode = CTX_wm_space_node(C);
428         ARegion *ar = CTX_wm_region(C);
429         ImageSampleInfo *info;
430
431         if (snode->treetype != NTREE_COMPOSIT || !(snode->flag & SNODE_BACKDRAW))
432                 return OPERATOR_CANCELLED;
433
434         info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
435         info->art = ar->type;
436         info->draw_handle = ED_region_draw_cb_activate(ar->type, sample_draw, info, REGION_DRAW_POST_PIXEL);
437         op->customdata = info;
438
439         sample_apply(C, op, event);
440
441         WM_event_add_modal_handler(C, op);
442
443         return OPERATOR_RUNNING_MODAL;
444 }
445
446 static int sample_modal(bContext *C, wmOperator *op, wmEvent *event)
447 {
448         switch (event->type) {
449                 case LEFTMOUSE:
450                 case RIGHTMOUSE: // XXX hardcoded
451                         sample_exit(C, op);
452                         return OPERATOR_CANCELLED;
453                 case MOUSEMOVE:
454                         sample_apply(C, op, event);
455                         break;
456         }
457
458         return OPERATOR_RUNNING_MODAL;
459 }
460
461 static int sample_cancel(bContext *C, wmOperator *op)
462 {
463         sample_exit(C, op);
464         return OPERATOR_CANCELLED;
465 }
466
467 void NODE_OT_backimage_sample(wmOperatorType *ot)
468 {
469         /* identifiers */
470         ot->name = "Backimage Sample";
471         ot->idname = "NODE_OT_backimage_sample";
472         ot->description = "Use mouse to sample background image";
473
474         /* api callbacks */
475         ot->invoke = sample_invoke;
476         ot->modal = sample_modal;
477         ot->cancel = sample_cancel;
478         ot->poll = ED_operator_node_active;
479
480         /* flags */
481         ot->flag = OPTYPE_BLOCKING;
482 }