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