style cleanup: follow style guide for formatting of if/for/while loops, and else...
[blender.git] / source / blender / editors / render / render_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  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/editors/render/render_view.c
26  *  \ingroup edrend
27  */
28
29 #include <string.h>
30 #include <stddef.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_blenlib.h"
35 #include "BLI_utildefines.h"
36
37 #include "DNA_scene_types.h"
38
39 #include "BKE_blender.h"
40 #include "BKE_context.h"
41 #include "BKE_image.h"
42 #include "BKE_global.h"
43 #include "BKE_main.h"
44 #include "BKE_node.h"
45 #include "BKE_report.h"
46 #include "BKE_screen.h"
47
48 #include "WM_api.h"
49 #include "WM_types.h"
50
51 #include "ED_screen.h"
52
53 #include "wm_window.h"
54
55 #include "render_intern.h"
56
57 /*********************** utilities for finding areas *************************/
58
59 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
60 /* window as the last possible alternative.                                                                        */
61 /* would use BKE_screen_find_big_area(...) but this is too specific            */
62 static ScrArea *biggest_non_image_area(bContext *C)
63 {
64         bScreen *sc= CTX_wm_screen(C);
65         ScrArea *sa, *big= NULL;
66         int size, maxsize= 0, bwmaxsize= 0;
67         short foundwin= 0;
68
69         for (sa= sc->areabase.first; sa; sa= sa->next) {
70                 if (sa->winx > 30 && sa->winy > 30) {
71                         size= sa->winx*sa->winy;
72                         if (sa->spacetype == SPACE_BUTS) {
73                                 if (foundwin == 0 && size > bwmaxsize) {
74                                         bwmaxsize= size;
75                                         big= sa;
76                                 }
77                         }
78                         else if (sa->spacetype != SPACE_IMAGE && size > maxsize) {
79                                 maxsize= size;
80                                 big= sa;
81                                 foundwin= 1;
82                         }
83                 }
84         }
85
86         return big;
87 }
88
89 static ScrArea *find_area_showing_r_result(bContext *C, wmWindow **win)
90 {
91         wmWindowManager *wm= CTX_wm_manager(C);
92         ScrArea *sa = NULL;
93         SpaceImage *sima;
94
95         /* find an imagewindow showing render result */
96         for (*win=wm->windows.first; *win; *win= (*win)->next) {
97                 for (sa= (*win)->screen->areabase.first; sa; sa= sa->next) {
98                         if (sa->spacetype==SPACE_IMAGE) {
99                                 sima= sa->spacedata.first;
100                                 if (sima->image && sima->image->type==IMA_TYPE_R_RESULT)
101                                         break;
102                         }
103                 }
104                 if (sa)
105                         break;
106         }
107         
108         return sa;
109 }
110
111 static ScrArea *find_area_image_empty(bContext *C)
112 {
113         bScreen *sc= CTX_wm_screen(C);
114         ScrArea *sa;
115         SpaceImage *sima;
116
117         /* find an imagewindow showing render result */
118         for (sa=sc->areabase.first; sa; sa= sa->next) {
119                 if (sa->spacetype==SPACE_IMAGE) {
120                         sima= sa->spacedata.first;
121                         if (!sima->image)
122                                 break;
123                 }
124         }
125
126         return sa;
127 }
128
129 /********************** open image editor for render *************************/
130
131 /* new window uses x,y to set position */
132 void render_view_open(bContext *C, int mx, int my)
133 {
134         wmWindow *win= CTX_wm_window(C);
135         Scene *scene= CTX_data_scene(C);
136         ScrArea *sa= NULL;
137         SpaceImage *sima;
138         int area_was_image=0;
139
140         if (scene->r.displaymode==R_OUTPUT_NONE)
141                 return;
142         
143         if (scene->r.displaymode==R_OUTPUT_WINDOW) {
144                 rcti rect;
145                 int sizex, sizey;
146
147                 sizex= 10 + (scene->r.xsch*scene->r.size)/100;
148                 sizey= 40 + (scene->r.ysch*scene->r.size)/100;
149
150                 /* arbitrary... miniature image window views don't make much sense */
151                 if (sizex < 320) sizex= 320;
152                 if (sizey < 256) sizey= 256;
153
154                 /* XXX some magic to calculate postition */
155                 rect.xmin = mx + win->posx - sizex/2;
156                 rect.ymin = my + win->posy - sizey/2;
157                 rect.xmax = rect.xmin + sizex;
158                 rect.ymax = rect.ymin + sizey;
159
160                 /* changes context! */
161                 WM_window_open_temp(C, &rect, WM_WINDOW_RENDER);
162
163                 sa= CTX_wm_area(C);
164         }
165         else if (scene->r.displaymode==R_OUTPUT_SCREEN) {
166                 if (CTX_wm_area(C) && CTX_wm_area(C)->spacetype == SPACE_IMAGE)
167                         area_was_image = 1;
168
169                 /* this function returns with changed context */
170                 sa= ED_screen_full_newspace(C, CTX_wm_area(C), SPACE_IMAGE);
171         }
172
173         if (!sa) {
174                 sa= find_area_showing_r_result(C, &win); 
175                 if (sa==NULL)
176                         sa= find_area_image_empty(C);
177                 
178                 /* if area found in other window, we make that one show in front */
179                 if (win && win!=CTX_wm_window(C))
180                         wm_window_raise(win);
181
182                 if (sa==NULL) {
183                         /* find largest open non-image area */
184                         sa= biggest_non_image_area(C);
185                         if (sa) {
186                                 ED_area_newspace(C, sa, SPACE_IMAGE);
187                                 sima= sa->spacedata.first;
188
189                                 /* makes ESC go back to prev space */
190                                 sima->flag |= SI_PREVSPACE;
191                         }
192                         else {
193                                 /* use any area of decent size */
194                                 sa= BKE_screen_find_big_area(CTX_wm_screen(C), -1, 0);
195                                 if (sa->spacetype!=SPACE_IMAGE) {
196                                         // XXX newspace(sa, SPACE_IMAGE);
197                                         sima= sa->spacedata.first;
198
199                                         /* makes ESC go back to prev space */
200                                         sima->flag |= SI_PREVSPACE;
201                                 }
202                         }
203                 }
204         }
205         sima= sa->spacedata.first;
206
207         /* get the correct image, and scale it */
208         sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
209
210
211         /* if we're rendering to full screen, set appropriate hints on image editor
212          * so it can restore properly on pressing esc */
213         if (sa->full) {
214                 sima->flag |= SI_FULLWINDOW;
215
216                 /* Tell the image editor to revert to previous space in space list on close
217                  * _only_ if it wasn't already an image editor when the render was invoked */
218                 if (area_was_image == 0)
219                         sima->flag |= SI_PREVSPACE;
220                 else {
221                         /* Leave it alone so the image editor will just go back from
222                          * full screen to the original tiled setup */
223                         ;
224                 }
225         }
226 }
227
228 /*************************** cancel render viewer **********************/
229
230 static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
231 {
232         wmWindow *win= CTX_wm_window(C);
233         ScrArea *sa= CTX_wm_area(C);
234         SpaceImage *sima= sa->spacedata.first;
235
236         /* test if we have a temp screen in front */
237         if (CTX_wm_window(C)->screen->temp) {
238                 wm_window_lower(CTX_wm_window(C));
239                 return OPERATOR_FINISHED;
240         }
241         /* determine if render already shows */
242         else if (sima->flag & SI_PREVSPACE) {
243                 sima->flag &= ~SI_PREVSPACE;
244
245                 if (sima->flag & SI_FULLWINDOW) {
246                         sima->flag &= ~SI_FULLWINDOW;
247                         ED_screen_full_prevspace(C, sa);
248                 }
249                 else
250                         ED_area_prevspace(C, sa);
251
252                 return OPERATOR_FINISHED;
253         }
254         else if (sima->flag & SI_FULLWINDOW) {
255                 sima->flag &= ~SI_FULLWINDOW;
256                 ED_screen_full_toggle(C, win, sa);
257                 return OPERATOR_FINISHED;
258         }
259
260         return OPERATOR_PASS_THROUGH;
261 }
262
263 void RENDER_OT_view_cancel(struct wmOperatorType *ot)
264 {
265         /* identifiers */
266         ot->name = "Cancel Render View";
267         ot->description = "Cancel show render view";
268         ot->idname = "RENDER_OT_view_cancel";
269
270         /* api callbacks */
271         ot->exec = render_view_cancel_exec;
272         ot->poll = ED_operator_image_active;
273 }
274
275 /************************* show render viewer *****************/
276
277 static int render_view_show_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
278 {
279         wmWindow *wincur = CTX_wm_window(C);
280         
281         /* test if we have currently a temp screen active */
282         if (wincur->screen->temp) {
283                 wm_window_lower(wincur);
284         }
285         else { 
286                 wmWindow *win, *winshow;
287                 ScrArea *sa= find_area_showing_r_result(C, &winshow);
288                 
289                 /* is there another window showing result? */
290                 for (win= CTX_wm_manager(C)->windows.first; win; win= win->next) {
291                         if (win->screen->temp || (win==winshow && winshow!=wincur)) {
292                                 wm_window_raise(win);
293                                 return OPERATOR_FINISHED;
294                         }
295                 }
296                 
297                 /* determine if render already shows */
298                 if (sa) {
299                         /* but don't close it when rendering */
300                         if (!G.rendering) {
301                                 SpaceImage *sima= sa->spacedata.first;
302
303                                 if (sima->flag & SI_PREVSPACE) {
304                                         sima->flag &= ~SI_PREVSPACE;
305
306                                         if (sima->flag & SI_FULLWINDOW) {
307                                                 sima->flag &= ~SI_FULLWINDOW;
308                                                 ED_screen_full_prevspace(C, sa);
309                                         }
310                                         else if (sima->next) {
311                                                 /* workaround for case of double prevspace, render window
312                                                  * with a file browser on top of it (same as in ED_area_prevspace) */
313                                                 if (sima->next->spacetype == SPACE_FILE && sima->next->next)
314                                                         ED_area_newspace(C, sa, sima->next->next->spacetype);
315                                                 else
316                                                         ED_area_newspace(C, sa, sima->next->spacetype);
317                                                 ED_area_tag_redraw(sa);
318                                         }
319                                 }
320                         }
321                 }
322                 else {
323                         render_view_open(C, event->x, event->y);
324                 }
325         }
326
327         return OPERATOR_FINISHED;
328 }
329
330 void RENDER_OT_view_show(struct wmOperatorType *ot)
331 {
332         /* identifiers */
333         ot->name = "Show/Hide Render View";
334         ot->description = "Toggle show render view";
335         ot->idname = "RENDER_OT_view_show";
336
337         /* api callbacks */
338         ot->invoke = render_view_show_invoke;
339         ot->poll = ED_operator_screenactive;
340 }
341