ac6058a0c5ca6f325481110a152247730b5acaab
[blender.git] / source / blender / editors / screen / area.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_blenlib.h"
35 #include "BLI_arithb.h"
36 #include "BLI_rand.h"
37
38 #include "BKE_global.h"
39 #include "BKE_screen.h"
40 #include "BKE_utildefines.h"
41
42 #include "ED_area.h"
43 #include "ED_screen.h"
44 #include "ED_screen_types.h"
45
46 #include "WM_api.h"
47 #include "WM_types.h"
48 #include "wm_subwindow.h"
49
50 #include "BIF_resources.h"
51 #include "BIF_gl.h"
52 #include "BIF_glutil.h"
53
54 #include "BPY_extern.h"
55
56 #include "screen_intern.h"
57
58 /* general area and region code */
59
60 static void region_draw_emboss(ARegion *ar)
61 {
62         short winx, winy;
63         
64         winx= ar->winrct.xmax-ar->winrct.xmin;
65         winy= ar->winrct.ymax-ar->winrct.ymin;
66         
67         /* set transp line */
68         glEnable( GL_BLEND );
69         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
70         
71         /* right  */
72         glColor4ub(0,0,0, 50);
73         sdrawline(winx, 0, winx, winy);
74         
75         /* bottom  */
76         glColor4ub(0,0,0, 80);
77         sdrawline(0, 0, winx, 0);
78         
79         /* top  */
80         glColor4ub(255,255,255, 60);
81         sdrawline(0, winy, winx, winy);
82
83         /* left  */
84         glColor4ub(255,255,255, 50);
85         sdrawline(0, 0, 0, winy);
86         
87         glDisable( GL_BLEND );
88 }
89
90
91 void ED_region_do_listen(ARegion *ar, wmNotifier *note)
92 {
93         
94         /* generic notes first */
95         switch(note->type) {
96                 case WM_NOTE_WINDOW_REDRAW:
97                         ar->do_draw= 1;
98                         break;
99                 case WM_NOTE_SCREEN_CHANGED:
100                         ar->do_draw= ar->do_refresh= 1;
101                         break;
102                 default:
103                         if(ar->type->listener)
104                                 ar->type->listener(ar, note);
105         }
106 }
107
108 void ED_region_do_draw(bContext *C, ARegion *ar)
109 {
110         ARegionType *at= ar->type;
111         
112         wm_subwindow_set(C->window, ar->swinid);
113         
114         if(ar->swinid && at->draw) {
115                 BIF_SetTheme(C->area);
116                 at->draw(C, ar);
117                 BIF_SetTheme(NULL);
118         }
119         else {
120                 float fac= 0.1*ar->swinid;
121                 
122                 glClearColor(0.5, fac, 1.0f-fac, 0.0); 
123                 glClear(GL_COLOR_BUFFER_BIT);
124                 
125                 fac= BLI_frand();
126                 glColor3f(fac, fac, fac);
127                 glRecti(2,  2,  12,  12);
128                 
129                 region_draw_emboss(ar);
130         }
131         
132         ar->do_draw= 0;
133 }
134
135 void ED_region_do_refresh(bContext *C, ARegion *ar)
136 {
137         ARegionType *at= ar->type;
138
139         /* refresh can be called before window opened */
140         if(ar->swinid)
141                 wm_subwindow_set(C->window, ar->swinid);
142         
143         if (at->refresh) {
144                 at->refresh(C, ar);
145         }
146         
147         ar->do_refresh= 0;
148 }
149
150 /* *************************************************************** */
151
152
153 static int rct_fits(rcti *rect, char dir, int size)
154 {
155         if(dir=='h') {
156                 return rect->xmax-rect->xmin - size;
157         }
158         else { // 'v'
159                 return rect->ymax-rect->ymin - size;
160         }
161 }
162
163 static void region_rect_recursive(ARegion *ar, rcti *remainder)
164 {
165         if(ar==NULL)
166                 return;
167         
168         /* clear state flag first */
169         ar->flag &= ~RGN_FLAG_TOO_SMALL;
170         
171         if(ar->size<ar->minsize)
172                 ar->size= ar->minsize;
173         
174         /* hidden is user flag */
175         if(ar->flag & RGN_FLAG_HIDDEN);
176         /* remainder is too small for any usage */
177         else if( rct_fits(remainder, 'v', 1)==0 || rct_fits(remainder, 'h', 1) < 0 ) {
178                 ar->flag |= RGN_FLAG_TOO_SMALL;
179         }
180         else if(ar->alignment==RGN_ALIGN_NONE) {
181                 /* typically last region */
182                 ar->winrct= *remainder;
183                 BLI_init_rcti(remainder, 0, 0, 0, 0);
184         }
185         else if(ar->alignment==RGN_ALIGN_TOP || ar->alignment==RGN_ALIGN_BOTTOM) {
186                 
187                 if( rct_fits(remainder, 'v', ar->minsize) < 0 ) {
188                         ar->flag |= RGN_FLAG_TOO_SMALL;
189                 }
190                 else {
191                         int fac= rct_fits(remainder, 'v', ar->size);
192                         
193                         if(fac < 0 )
194                                 ar->size += fac;
195                         
196                         ar->winrct= *remainder;
197                         
198                         if(ar->alignment==RGN_ALIGN_TOP) {
199                                 ar->winrct.ymin= ar->winrct.ymax - ar->size;
200                                 remainder->ymax= ar->winrct.ymin-1;
201                         }
202                         else {
203                                 ar->winrct.ymax= ar->winrct.ymin + ar->size;
204                                 remainder->ymin= ar->winrct.ymax+1;
205                         }
206                 }
207         }
208         else if(ar->alignment==RGN_ALIGN_LEFT || ar->alignment==RGN_ALIGN_RIGHT) {
209                 
210                 if( rct_fits(remainder, 'h', ar->minsize) < 0 ) {
211                         ar->flag |= RGN_FLAG_TOO_SMALL;
212                 }
213                 else {
214                         int fac= rct_fits(remainder, 'h', ar->size);
215                         
216                         if(fac < 0 )
217                                 ar->size += fac;
218                         
219                         ar->winrct= *remainder;
220                         
221                         if(ar->alignment==RGN_ALIGN_RIGHT) {
222                                 ar->winrct.xmin= ar->winrct.xmax - ar->size;
223                                 remainder->xmax= ar->winrct.xmin-1;
224                         }
225                         else {
226                                 ar->winrct.xmax= ar->winrct.xmin + ar->size;
227                                 remainder->xmin= ar->winrct.xmax+1;
228                         }
229                 }
230         }
231         else {
232                 /* percentage subdiv*/
233                 ar->winrct= *remainder;
234                 
235                 if(ar->alignment==RGN_ALIGN_HSPLIT) {
236                         ar->winrct.xmax= (remainder->xmin+remainder->xmax)/2;
237                         remainder->xmin= ar->winrct.xmax+1;
238                 }
239                 else {
240                         ar->winrct.ymax= (remainder->ymin+remainder->ymax)/2;
241                         remainder->ymin= ar->winrct.ymax+1;
242                 }
243         }
244         
245         region_rect_recursive(ar->next, remainder);
246 }
247
248 static void area_calc_totrct(ScrArea *sa, int sizex, int sizey)
249 {
250         
251         if(sa->v1->vec.x>0) sa->totrct.xmin= sa->v1->vec.x+1;
252         else sa->totrct.xmin= sa->v1->vec.x;
253         if(sa->v4->vec.x<sizex-1) sa->totrct.xmax= sa->v4->vec.x-1;
254         else sa->totrct.xmax= sa->v4->vec.x;
255         
256         if(sa->v1->vec.y>0) sa->totrct.ymin= sa->v1->vec.y+1;
257         else sa->totrct.ymin= sa->v1->vec.y;
258         if(sa->v2->vec.y<sizey-1) sa->totrct.ymax= sa->v2->vec.y-1;
259         else sa->totrct.ymax= sa->v2->vec.y;
260         
261         /* for speedup */
262         sa->winx= sa->totrct.xmax-sa->totrct.xmin+1;
263         sa->winy= sa->totrct.ymax-sa->totrct.ymin+1;
264 }
265
266 #define AZONESPOT               12
267 void area_azone_initialize(ScrArea *sa) {
268         AZone *az;
269         if(sa->actionzones.first==NULL) {
270                 /* set action zones - should these actually be ARegions? With these we can easier check area hotzones */
271                 az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
272                 BLI_addtail(&(sa->actionzones), az);
273                 az->type= AZONE_TRI;
274                 az->x1= sa->v1->vec.x+1;
275                 az->y1= sa->v1->vec.y+1;
276                 az->x2= sa->v1->vec.x+AZONESPOT;
277                 az->y2= sa->v1->vec.y+AZONESPOT;
278                 az->pos= AZONE_SW;
279                 az->action= AZONE_SPLIT;
280                 
281                 az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
282                 BLI_addtail(&(sa->actionzones), az);
283                 az->type= AZONE_TRI;
284                 az->x1= sa->v3->vec.x-1;
285                 az->y1= sa->v3->vec.y-1;
286                 az->x2= sa->v3->vec.x-AZONESPOT;
287                 az->y2= sa->v3->vec.y-AZONESPOT;
288                 az->pos= AZONE_NE;
289                 az->action= AZONE_DRAG;
290                 
291                 /*az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
292                 BLI_addtail(&sa->azones, az);
293                 az->type= AZONE_TRI;
294                 az->x1= as->v1->vec.x;
295                 az->y1= as->v1->vec.y;
296                 az->x2= as->v1->vec.x+AZONESPOT;
297                 az->y2= as->v1->vec.y+AZONESPOT;
298                 
299                 az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
300                 BLI_addtail(&sa->azones, az);
301                 az->type= AZONE_TRI;
302                 az->x1= as->v1->vec.x;
303                 az->y1= as->v1->vec.y;
304                 az->x2= as->v1->vec.x+AZONESPOT;
305                 az->y2= as->v1->vec.y+AZONESPOT;
306                 
307                 az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
308                 BLI_addtail(&sa->azones, az);
309                 az->type= AZONE_QUAD;
310                 az->x1= as->v1->vec.x;
311                 az->y1= as->v1->vec.y;
312                 az->x2= as->v1->vec.x+AZONESPOT;
313                 az->y2= as->v1->vec.y+AZONESPOT;
314                 
315                 az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
316                 BLI_addtail(&sa->azones, az);
317                 az->type= AZONE_QUAD;
318                 az->x1= as->v1->vec.x;
319                 az->y1= as->v1->vec.y;
320                 az->x2= as->v1->vec.x+AZONESPOT;
321                 az->y2= as->v1->vec.y+AZONESPOT;
322                 
323                 az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
324                 BLI_addtail(&sa->azones, az);
325                 az->type= AZONE_QUAD;
326                 az->x1= as->v1->vec.x;
327                 az->y1= as->v1->vec.y;
328                 az->x2= as->v1->vec.x+AZONESPOT;
329                 az->y2= as->v1->vec.y+AZONESPOT;
330                 
331                 az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
332                 BLI_addtail(&sa->azones, az);
333                 az->type= AZONE_QUAD;
334                 az->x1= as->v1->vec.x;
335                 az->y1= as->v1->vec.y;
336                 az->x2= as->v1->vec.x+AZONESPOT;
337                 az->y2= as->v1->vec.y+AZONESPOT;*/
338         }
339         
340         for(az= sa->actionzones.first; az; az= az->next) {
341                 if(az->pos==AZONE_SW) {
342                         az->x1= sa->v1->vec.x+1;
343                         az->y1= sa->v1->vec.y+1;
344                         az->x2= sa->v1->vec.x+AZONESPOT;
345                         az->y2= sa->v1->vec.y+AZONESPOT;
346                 } else if (az->pos==AZONE_NE) {
347                         az->x1= sa->v3->vec.x-1;
348                         az->y1= sa->v3->vec.y-1;
349                         az->x2= sa->v3->vec.x-AZONESPOT;
350                         az->y2= sa->v3->vec.y-AZONESPOT;
351                 }
352         }
353 }
354
355 /* called in screen_refresh, or screens_init */
356 void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
357 {
358         ARegion *ar;
359         rcti rect;
360         
361         /* set typedefinitions */
362         sa->type= BKE_spacetype_from_id(sa->spacetype);
363         if(sa->type==NULL) {
364                 sa->spacetype= SPACE_VIEW3D;
365                 sa->type= BKE_spacetype_from_id(sa->spacetype);
366         }
367         
368         area_calc_totrct(sa, win->sizex, win->sizey);
369         
370         /* regiontype callback, it should create/verify the amount of subregions with minsizes etc */
371         if(sa->type->init)
372                 sa->type->init(wm, sa);
373         
374         /* region rect sizes */
375         rect= sa->totrct;
376         region_rect_recursive(sa->regionbase.first, &rect);
377         
378         /* region windows */
379         for(ar= sa->regionbase.first; ar; ar= ar->next) {
380                 if(ar->flag & (RGN_FLAG_HIDDEN|RGN_FLAG_TOO_SMALL)) {
381                         if(ar->swinid)
382                                 wm_subwindow_close(win, ar->swinid);
383                         ar->swinid= 0;
384                 }
385                 else if(ar->swinid==0)
386                         ar->swinid= wm_subwindow_open(win, &ar->winrct);
387                 else 
388                         wm_subwindow_position(win, ar->swinid, &ar->winrct);
389         }
390         
391         area_azone_initialize(sa);
392 }
393
394 /* sa2 to sa1, we swap spaces for fullscreen to keep all allocated data */
395 /* area vertices were set */
396
397 void area_copy_data(ScrArea *sa1, ScrArea *sa2, int swap_space)
398 {
399         Panel *pa1, *pa2, *patab;
400         ARegion *ar;
401         AZone *az;
402         
403         sa1->headertype= sa2->headertype;
404         sa1->spacetype= sa2->spacetype;
405         
406         if(swap_space) {
407                 SWAP(ListBase, sa1->spacedata, sa2->spacedata);
408                 /* exception: ensure preview is reset */
409 //              if(sa1->spacetype==SPACE_VIEW3D)
410 // XXX                  BIF_view3d_previewrender_free(sa1->spacedata.first);
411         }
412         else {
413                 BKE_spacedata_freelist(&sa1->spacedata);
414                 BKE_spacedata_copylist(&sa1->spacedata, &sa2->spacedata);
415         }
416         
417         BLI_freelistN(&sa1->panels);
418         BLI_duplicatelist(&sa1->panels, &sa2->panels);
419         
420         /* copy panel pointers */
421         for(pa1= sa1->panels.first; pa1; pa1= pa1->next) {
422                 
423                 patab= sa1->panels.first;
424                 pa2= sa2->panels.first;
425                 while(patab) {
426                         if( pa1->paneltab == pa2) {
427                                 pa1->paneltab = patab;
428                                 break;
429                         }
430                         patab= patab->next;
431                         pa2= pa2->next;
432                 }
433         }
434         
435         /* regions */
436         BLI_freelistN(&sa1->regionbase);
437         BLI_duplicatelist(&sa1->regionbase, &sa2->regionbase);
438         for(ar= sa1->regionbase.first; ar; ar= ar->next)
439                 ar->swinid= 0;
440                 
441         /* scripts */
442         BPY_free_scriptlink(&sa1->scriptlink);
443         sa1->scriptlink= sa2->scriptlink;
444         BPY_copy_scriptlink(&sa1->scriptlink);  /* copies internal pointers */
445         
446 }
447
448