Various changes made in the process of working on the UI code:
[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         /* XXX floating area region, not handled yet here */
177         else if(ar->alignment == RGN_ALIGN_FLOAT);
178         /* remainder is too small for any usage */
179         else if( rct_fits(remainder, 'v', 1)==0 || rct_fits(remainder, 'h', 1) < 0 ) {
180                 ar->flag |= RGN_FLAG_TOO_SMALL;
181         }
182         else if(ar->alignment==RGN_ALIGN_NONE) {
183                 /* typically last region */
184                 ar->winrct= *remainder;
185                 BLI_init_rcti(remainder, 0, 0, 0, 0);
186         }
187         else if(ar->alignment==RGN_ALIGN_TOP || ar->alignment==RGN_ALIGN_BOTTOM) {
188                 
189                 if( rct_fits(remainder, 'v', ar->minsize) < 0 ) {
190                         ar->flag |= RGN_FLAG_TOO_SMALL;
191                 }
192                 else {
193                         int fac= rct_fits(remainder, 'v', ar->size);
194
195                         if(fac < 0 )
196                                 ar->size += fac;
197                         
198                         ar->winrct= *remainder;
199                         
200                         if(ar->alignment==RGN_ALIGN_TOP) {
201                                 ar->winrct.ymin= ar->winrct.ymax - ar->size;
202                                 remainder->ymax= ar->winrct.ymin-1;
203                         }
204                         else {
205                                 ar->winrct.ymax= ar->winrct.ymin + ar->size;
206                                 remainder->ymin= ar->winrct.ymax+1;
207                         }
208                 }
209         }
210         else if(ar->alignment==RGN_ALIGN_LEFT || ar->alignment==RGN_ALIGN_RIGHT) {
211                 
212                 if( rct_fits(remainder, 'h', ar->minsize) < 0 ) {
213                         ar->flag |= RGN_FLAG_TOO_SMALL;
214                 }
215                 else {
216                         int fac= rct_fits(remainder, 'h', ar->size);
217                         
218                         if(fac < 0 )
219                                 ar->size += fac;
220                         
221                         ar->winrct= *remainder;
222                         
223                         if(ar->alignment==RGN_ALIGN_RIGHT) {
224                                 ar->winrct.xmin= ar->winrct.xmax - ar->size;
225                                 remainder->xmax= ar->winrct.xmin-1;
226                         }
227                         else {
228                                 ar->winrct.xmax= ar->winrct.xmin + ar->size;
229                                 remainder->xmin= ar->winrct.xmax+1;
230                         }
231                 }
232         }
233         else {
234                 /* percentage subdiv*/
235                 ar->winrct= *remainder;
236                 
237                 if(ar->alignment==RGN_ALIGN_HSPLIT) {
238                         ar->winrct.xmax= (remainder->xmin+remainder->xmax)/2;
239                         remainder->xmin= ar->winrct.xmax+1;
240                 }
241                 else {
242                         ar->winrct.ymax= (remainder->ymin+remainder->ymax)/2;
243                         remainder->ymin= ar->winrct.ymax+1;
244                 }
245         }
246         
247         region_rect_recursive(ar->next, remainder);
248 }
249
250 static void area_calc_totrct(ScrArea *sa, int sizex, int sizey)
251 {
252         
253         if(sa->v1->vec.x>0) sa->totrct.xmin= sa->v1->vec.x+1;
254         else sa->totrct.xmin= sa->v1->vec.x;
255         if(sa->v4->vec.x<sizex-1) sa->totrct.xmax= sa->v4->vec.x-1;
256         else sa->totrct.xmax= sa->v4->vec.x;
257         
258         if(sa->v1->vec.y>0) sa->totrct.ymin= sa->v1->vec.y+1;
259         else sa->totrct.ymin= sa->v1->vec.y;
260         if(sa->v2->vec.y<sizey-1) sa->totrct.ymax= sa->v2->vec.y-1;
261         else sa->totrct.ymax= sa->v2->vec.y;
262         
263         /* for speedup */
264         sa->winx= sa->totrct.xmax-sa->totrct.xmin+1;
265         sa->winy= sa->totrct.ymax-sa->totrct.ymin+1;
266 }
267
268 #define AZONESPOT               12
269 void area_azone_initialize(ScrArea *sa) {
270         AZone *az;
271         if(sa->actionzones.first==NULL) {
272                 /* set action zones - should these actually be ARegions? With these we can easier check area hotzones */
273                 az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
274                 BLI_addtail(&(sa->actionzones), az);
275                 az->type= AZONE_TRI;
276                 az->x1= sa->v1->vec.x+1;
277                 az->y1= sa->v1->vec.y+1;
278                 az->x2= sa->v1->vec.x+AZONESPOT;
279                 az->y2= sa->v1->vec.y+AZONESPOT;
280                 az->pos= AZONE_SW;
281                 az->action= AZONE_SPLIT;
282                 
283                 az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
284                 BLI_addtail(&(sa->actionzones), az);
285                 az->type= AZONE_TRI;
286                 az->x1= sa->v3->vec.x-1;
287                 az->y1= sa->v3->vec.y-1;
288                 az->x2= sa->v3->vec.x-AZONESPOT;
289                 az->y2= sa->v3->vec.y-AZONESPOT;
290                 az->pos= AZONE_NE;
291                 az->action= AZONE_DRAG;
292                 
293                 /*az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
294                 BLI_addtail(&sa->azones, az);
295                 az->type= AZONE_TRI;
296                 az->x1= as->v1->vec.x;
297                 az->y1= as->v1->vec.y;
298                 az->x2= as->v1->vec.x+AZONESPOT;
299                 az->y2= as->v1->vec.y+AZONESPOT;
300                 
301                 az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
302                 BLI_addtail(&sa->azones, az);
303                 az->type= AZONE_TRI;
304                 az->x1= as->v1->vec.x;
305                 az->y1= as->v1->vec.y;
306                 az->x2= as->v1->vec.x+AZONESPOT;
307                 az->y2= as->v1->vec.y+AZONESPOT;
308                 
309                 az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
310                 BLI_addtail(&sa->azones, az);
311                 az->type= AZONE_QUAD;
312                 az->x1= as->v1->vec.x;
313                 az->y1= as->v1->vec.y;
314                 az->x2= as->v1->vec.x+AZONESPOT;
315                 az->y2= as->v1->vec.y+AZONESPOT;
316                 
317                 az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
318                 BLI_addtail(&sa->azones, az);
319                 az->type= AZONE_QUAD;
320                 az->x1= as->v1->vec.x;
321                 az->y1= as->v1->vec.y;
322                 az->x2= as->v1->vec.x+AZONESPOT;
323                 az->y2= as->v1->vec.y+AZONESPOT;
324                 
325                 az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
326                 BLI_addtail(&sa->azones, az);
327                 az->type= AZONE_QUAD;
328                 az->x1= as->v1->vec.x;
329                 az->y1= as->v1->vec.y;
330                 az->x2= as->v1->vec.x+AZONESPOT;
331                 az->y2= as->v1->vec.y+AZONESPOT;
332                 
333                 az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
334                 BLI_addtail(&sa->azones, az);
335                 az->type= AZONE_QUAD;
336                 az->x1= as->v1->vec.x;
337                 az->y1= as->v1->vec.y;
338                 az->x2= as->v1->vec.x+AZONESPOT;
339                 az->y2= as->v1->vec.y+AZONESPOT;*/
340         }
341         
342         for(az= sa->actionzones.first; az; az= az->next) {
343                 if(az->pos==AZONE_SW) {
344                         az->x1= sa->v1->vec.x+1;
345                         az->y1= sa->v1->vec.y+1;
346                         az->x2= sa->v1->vec.x+AZONESPOT;
347                         az->y2= sa->v1->vec.y+AZONESPOT;
348                 } else if (az->pos==AZONE_NE) {
349                         az->x1= sa->v3->vec.x-1;
350                         az->y1= sa->v3->vec.y-1;
351                         az->x2= sa->v3->vec.x-AZONESPOT;
352                         az->y2= sa->v3->vec.y-AZONESPOT;
353                 }
354         }
355 }
356
357 /* used for area and screen regions */
358 void ED_region_initialize(wmWindowManager *wm, wmWindow *win, ARegion *ar)
359 {
360         if(ar->flag & (RGN_FLAG_HIDDEN|RGN_FLAG_TOO_SMALL)) {
361                 if(ar->swinid)
362                         wm_subwindow_close(win, ar->swinid);
363                 ar->swinid= 0;
364         }
365         else if(ar->swinid==0)
366                 ar->swinid= wm_subwindow_open(win, &ar->winrct);
367         else 
368                 wm_subwindow_position(win, ar->swinid, &ar->winrct);
369 }
370
371 /* called in screen_refresh, or screens_init */
372 void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
373 {
374         ARegion *ar;
375         rcti rect;
376         
377         /* set typedefinitions */
378         sa->type= BKE_spacetype_from_id(sa->spacetype);
379         if(sa->type==NULL) {
380                 sa->spacetype= SPACE_VIEW3D;
381                 sa->type= BKE_spacetype_from_id(sa->spacetype);
382         }
383         
384         area_calc_totrct(sa, win->sizex, win->sizey);
385         
386         /* regiontype callback, it should create/verify the amount of subregions with minsizes etc */
387         if(sa->type->init)
388                 sa->type->init(wm, sa);
389         
390         /* region rect sizes */
391         rect= sa->totrct;
392         region_rect_recursive(sa->regionbase.first, &rect);
393         
394         /* region windows */
395         for(ar= sa->regionbase.first; ar; ar= ar->next)
396                 ED_region_initialize(wm, win, ar);
397         
398         area_azone_initialize(sa);
399 }
400
401 /* sa2 to sa1, we swap spaces for fullscreen to keep all allocated data */
402 /* area vertices were set */
403
404 void area_copy_data(ScrArea *sa1, ScrArea *sa2, int swap_space)
405 {
406         Panel *pa1, *pa2, *patab;
407         ARegion *ar;
408         AZone *az;
409         
410         sa1->headertype= sa2->headertype;
411         sa1->spacetype= sa2->spacetype;
412         
413         if(swap_space) {
414                 SWAP(ListBase, sa1->spacedata, sa2->spacedata);
415                 /* exception: ensure preview is reset */
416 //              if(sa1->spacetype==SPACE_VIEW3D)
417 // XXX                  BIF_view3d_previewrender_free(sa1->spacedata.first);
418         }
419         else {
420                 BKE_spacedata_freelist(&sa1->spacedata);
421                 BKE_spacedata_copylist(&sa1->spacedata, &sa2->spacedata);
422         }
423         
424         BLI_freelistN(&sa1->panels);
425         BLI_duplicatelist(&sa1->panels, &sa2->panels);
426         
427         /* copy panel pointers */
428         for(pa1= sa1->panels.first; pa1; pa1= pa1->next) {
429                 
430                 patab= sa1->panels.first;
431                 pa2= sa2->panels.first;
432                 while(patab) {
433                         if( pa1->paneltab == pa2) {
434                                 pa1->paneltab = patab;
435                                 break;
436                         }
437                         patab= patab->next;
438                         pa2= pa2->next;
439                 }
440         }
441         
442         /* regions */
443         BLI_freelistN(&sa1->regionbase);
444         BLI_duplicatelist(&sa1->regionbase, &sa2->regionbase);
445         for(ar= sa1->regionbase.first; ar; ar= ar->next) {
446                 ar->handlers.first= ar->handlers.last= NULL;
447                 ar->uiblocks.first= ar->uiblocks.last= NULL;
448                 ar->swinid= 0;
449         }
450                 
451         /* scripts */
452         BPY_free_scriptlink(&sa1->scriptlink);
453         sa1->scriptlink= sa2->scriptlink;
454         BPY_copy_scriptlink(&sa1->scriptlink);  /* copies internal pointers */
455         
456 }
457
458