58900e603e36305a9b7a753fec74c99f3c054f39
[blender.git] / source / blender / blenkernel / intern / screen.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) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <string.h>
31 #include <stdio.h>
32 #include <math.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "DNA_scene_types.h"
37 #include "DNA_screen_types.h"
38 #include "DNA_space_types.h"
39 #include "DNA_view3d_types.h"
40
41 #include "BLI_blenlib.h"
42
43 #include "BKE_screen.h"
44
45 /* ************ Spacetype/regiontype handling ************** */
46
47 /* keep global; this has to be accessible outside of windowmanager */
48 static ListBase spacetypes= {NULL, NULL};
49
50 /* not SpaceType itself */
51 static void spacetype_free(SpaceType *st)
52 {
53         ARegionType *art;
54         PanelType *pt;
55         HeaderType *ht;
56         
57         for(art= st->regiontypes.first; art; art= art->next) {
58                 BLI_freelistN(&art->drawcalls);
59
60                 for(pt= art->paneltypes.first; pt; pt= pt->next)
61                         if(pt->ext.free)
62                                 pt->ext.free(pt->ext.data);
63
64                 for(ht= art->headertypes.first; ht; ht= ht->next)
65                         if(ht->ext.free)
66                                 ht->ext.free(ht->ext.data);
67
68                 BLI_freelistN(&art->paneltypes);
69                 BLI_freelistN(&art->headertypes);
70         }
71         
72         BLI_freelistN(&st->regiontypes);
73         BLI_freelistN(&st->toolshelf);
74
75 }
76
77 void BKE_spacetypes_free(void)
78 {
79         SpaceType *st;
80         
81         for(st= spacetypes.first; st; st= st->next) {
82                 spacetype_free(st);
83         }
84         
85         BLI_freelistN(&spacetypes);
86 }
87
88 SpaceType *BKE_spacetype_from_id(int spaceid)
89 {
90         SpaceType *st;
91         
92         for(st= spacetypes.first; st; st= st->next) {
93                 if(st->spaceid==spaceid)
94                         return st;
95         }
96         return NULL;
97 }
98
99 ARegionType *BKE_regiontype_from_id(SpaceType *st, int regionid)
100 {
101         ARegionType *art;
102         
103         for(art= st->regiontypes.first; art; art= art->next)
104                 if(art->regionid==regionid)
105                         return art;
106         
107         printf("Error, region type missing in - name:\"%s\", id:%d\n", st->name, st->spaceid);
108         return st->regiontypes.first;
109 }
110
111
112 const ListBase *BKE_spacetypes_list(void)
113 {
114         return &spacetypes;
115 }
116
117 void BKE_spacetype_register(SpaceType *st)
118 {
119         SpaceType *stype;
120         
121         /* sanity check */
122         stype= BKE_spacetype_from_id(st->spaceid);
123         if(stype) {
124                 printf("error: redefinition of spacetype %s\n", stype->name);
125                 spacetype_free(stype);
126                 MEM_freeN(stype);
127         }
128         
129         BLI_addtail(&spacetypes, st);
130 }
131
132 /* ***************** Space handling ********************** */
133
134 void BKE_spacedata_freelist(ListBase *lb)
135 {
136         SpaceLink *sl;
137         ARegion *ar;
138         
139         for (sl= lb->first; sl; sl= sl->next) {
140                 SpaceType *st= BKE_spacetype_from_id(sl->spacetype);
141                 
142                 /* free regions for pushed spaces */
143                 for(ar=sl->regionbase.first; ar; ar=ar->next)
144                         BKE_area_region_free(st, ar);
145
146                 BLI_freelistN(&sl->regionbase);
147                 
148                 if(st && st->free) 
149                         st->free(sl);
150         }
151         
152         BLI_freelistN(lb);
153 }
154
155 ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
156 {
157         ARegion *newar= MEM_dupallocN(ar);
158         Panel *pa, *newpa, *patab;
159         
160         newar->prev= newar->next= NULL;
161         newar->handlers.first= newar->handlers.last= NULL;
162         newar->uiblocks.first= newar->uiblocks.last= NULL;
163         newar->swinid= 0;
164         
165         /* use optional regiondata callback */
166         if(ar->regiondata) {
167                 ARegionType *art= BKE_regiontype_from_id(st, ar->regiontype);
168
169                 if(art && art->duplicate)
170                         newar->regiondata= art->duplicate(ar->regiondata);
171                 else
172                         newar->regiondata= MEM_dupallocN(ar->regiondata);
173         }
174
175         if(ar->v2d.tab_offset)
176                 newar->v2d.tab_offset= MEM_dupallocN(ar->v2d.tab_offset);
177         
178         newar->panels.first= newar->panels.last= NULL;
179         BLI_duplicatelist(&newar->panels, &ar->panels);
180         
181         /* copy panel pointers */
182         for(newpa= newar->panels.first; newpa; newpa= newpa->next) {
183                 patab= newar->panels.first;
184                 pa= ar->panels.first;
185                 while(patab) {
186                         if(newpa->paneltab == pa) {
187                                 newpa->paneltab = patab;
188                                 break;
189                         }
190                         patab= patab->next;
191                         pa= pa->next;
192                 }
193         }
194         
195         return newar;
196 }
197
198
199 /* from lb2 to lb1, lb1 is supposed to be free'd */
200 static void region_copylist(SpaceType *st, ListBase *lb1, ListBase *lb2)
201 {
202         ARegion *ar;
203         
204         /* to be sure */
205         lb1->first= lb1->last= NULL;
206         
207         for(ar= lb2->first; ar; ar= ar->next) {
208                 ARegion *arnew= BKE_area_region_copy(st, ar);
209                 BLI_addtail(lb1, arnew);
210         }
211 }
212
213
214 /* lb1 should be empty */
215 void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2)
216 {
217         SpaceLink *sl;
218         
219         lb1->first= lb1->last= NULL;    /* to be sure */
220         
221         for (sl= lb2->first; sl; sl= sl->next) {
222                 SpaceType *st= BKE_spacetype_from_id(sl->spacetype);
223                 
224                 if(st && st->duplicate) {
225                         SpaceLink *slnew= st->duplicate(sl);
226                         
227                         BLI_addtail(lb1, slnew);
228                         
229                         region_copylist(st, &slnew->regionbase, &sl->regionbase);
230                 }
231         }
232 }
233
234 /* not region itself */
235 void BKE_area_region_free(SpaceType *st, ARegion *ar)
236 {
237         if(st) {
238                 ARegionType *art= BKE_regiontype_from_id(st, ar->regiontype);
239                 
240                 if(art && art->free)
241                         art->free(ar);
242                 
243                 if(ar->regiondata)
244                         printf("regiondata free error\n");
245         }
246         else if(ar->type && ar->type->free)
247                 ar->type->free(ar);
248         
249         if(ar->v2d.tab_offset) {
250                 MEM_freeN(ar->v2d.tab_offset);
251                 ar->v2d.tab_offset= NULL;
252         }
253
254         if(ar)
255                 BLI_freelistN(&ar->panels);
256 }
257
258 /* not area itself */
259 void BKE_screen_area_free(ScrArea *sa)
260 {
261         SpaceType *st= BKE_spacetype_from_id(sa->spacetype);
262         ARegion *ar;
263         
264         for(ar=sa->regionbase.first; ar; ar=ar->next)
265                 BKE_area_region_free(st, ar);
266
267         BLI_freelistN(&sa->regionbase);
268         
269         BKE_spacedata_freelist(&sa->spacedata);
270         
271         BLI_freelistN(&sa->actionzones);
272 }
273
274 /* don't free screen itself */
275 void free_screen(bScreen *sc)
276 {
277         ScrArea *sa, *san;
278         ARegion *ar;
279         
280         for(ar=sc->regionbase.first; ar; ar=ar->next)
281                 BKE_area_region_free(NULL, ar);
282
283         BLI_freelistN(&sc->regionbase);
284         
285         for(sa= sc->areabase.first; sa; sa= san) {
286                 san= sa->next;
287                 BKE_screen_area_free(sa);
288         }
289         
290         BLI_freelistN(&sc->vertbase);
291         BLI_freelistN(&sc->edgebase);
292         BLI_freelistN(&sc->areabase);
293 }
294
295 /* for depsgraph */
296 unsigned int BKE_screen_visible_layers(bScreen *screen, Scene *scene)
297 {
298         ScrArea *sa;
299         unsigned int layer= 0;
300
301         if(screen) {
302                 /* get all used view3d layers */
303                 for(sa= screen->areabase.first; sa; sa= sa->next)
304                         if(sa->spacetype==SPACE_VIEW3D)
305                                 layer |= ((View3D *)sa->spacedata.first)->lay;
306         }
307
308         if(!layer)
309                 return scene->lay;
310
311         return layer;
312 }
313
314 /* ***************** Utilities ********************** */
315
316 /* Find a region of the specified type from the given area */
317 ARegion *BKE_area_find_region_type(ScrArea *sa, int type)
318 {
319         if (sa) {
320                 ARegion *ar;
321                 
322                 for (ar=sa->regionbase.first; ar; ar= ar->next) {
323                         if (ar->regiontype == type)
324                                 return ar;
325                 }
326         }
327         return NULL;
328 }
329
330 void BKE_screen_view3d_sync(struct View3D *v3d, struct Scene *scene)
331 {
332         int bit;
333
334         if(v3d->scenelock && v3d->localvd==NULL) {
335                 v3d->lay= scene->lay;
336                 v3d->camera= scene->camera;
337
338                 if(v3d->camera==NULL) {
339                         ARegion *ar;
340
341                         for(ar=v3d->regionbase.first; ar; ar= ar->next) {
342                                 if(ar->regiontype == RGN_TYPE_WINDOW) {
343                                         RegionView3D *rv3d= ar->regiondata;
344                                         if(rv3d->persp==RV3D_CAMOB)
345                                                 rv3d->persp= RV3D_PERSP;
346                                 }
347                         }
348                 }
349
350                 if((v3d->lay & v3d->layact) == 0) {
351                         for(bit= 0; bit<32; bit++) {
352                                 if(v3d->lay & (1<<bit)) {
353                                         v3d->layact= 1<<bit;
354                                         break;
355                                 }
356                         }
357                 }
358         }
359 }
360
361 void BKE_screen_view3d_scene_sync(bScreen *sc)
362 {
363         /* are there cameras in the views that are not in the scene? */
364         ScrArea *sa;
365         for(sa= sc->areabase.first; sa; sa= sa->next) {
366                 SpaceLink *sl;
367                 for(sl= sa->spacedata.first; sl; sl= sl->next) {
368                         if(sl->spacetype==SPACE_VIEW3D) {
369                                 View3D *v3d= (View3D*) sl;
370                                 BKE_screen_view3d_sync(v3d, sc->scene);
371                         }
372                 }
373         }
374 }
375
376 void BKE_screen_view3d_main_sync(ListBase *screen_lb, Scene *scene)
377 {
378         bScreen *sc;
379         ScrArea *sa;
380         SpaceLink *sl;
381
382         /* from scene copy to the other views */
383         for(sc=screen_lb->first; sc; sc=sc->id.next) {
384                 if(sc->scene!=scene)
385                         continue;
386
387                 for(sa=sc->areabase.first; sa; sa=sa->next)
388                         for(sl=sa->spacedata.first; sl; sl=sl->next)
389                                 if(sl->spacetype==SPACE_VIEW3D)
390                                         BKE_screen_view3d_sync((View3D*)sl, scene);
391         }
392 }