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