Merge branch 'master' into blender2.8
[blender.git] / source / blender / blenkernel / intern / screen.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/blenkernel/intern/screen.c
29  *  \ingroup bke
30  */
31
32 #ifdef WIN32
33 #  include "BLI_winstuff.h"
34 #endif
35
36 #include <string.h>
37 #include <stdio.h>
38 #include <math.h>
39
40 #include "MEM_guardedalloc.h"
41
42 #include "DNA_scene_types.h"
43 #include "DNA_screen_types.h"
44 #include "DNA_space_types.h"
45 #include "DNA_view3d_types.h"
46 #include "DNA_workspace_types.h"
47
48 #include "BLI_math_vector.h"
49 #include "BLI_listbase.h"
50 #include "BLI_rect.h"
51 #include "BLI_utildefines.h"
52
53 #include "BKE_icons.h"
54 #include "BKE_idprop.h"
55 #include "BKE_screen.h"
56 #include "BKE_workspace.h"
57
58 /* ************ Spacetype/regiontype handling ************** */
59
60 /* keep global; this has to be accessible outside of windowmanager */
61 static ListBase spacetypes = {NULL, NULL};
62
63 /* not SpaceType itself */
64 static void spacetype_free(SpaceType *st)
65 {
66         ARegionType *art;
67         PanelType *pt;
68         HeaderType *ht;
69
70         for (art = st->regiontypes.first; art; art = art->next) {
71                 BLI_freelistN(&art->drawcalls);
72
73                 for (pt = art->paneltypes.first; pt; pt = pt->next) {
74                         if (pt->ext.free) {
75                                 pt->ext.free(pt->ext.data);
76                         }
77
78                         BLI_freelistN(&pt->children);
79                 }
80
81                 for (ht = art->headertypes.first; ht; ht = ht->next) {
82                         if (ht->ext.free) {
83                                 ht->ext.free(ht->ext.data);
84                         }
85                 }
86
87                 BLI_freelistN(&art->paneltypes);
88                 BLI_freelistN(&art->headertypes);
89         }
90
91         BLI_freelistN(&st->regiontypes);
92 }
93
94 void BKE_spacetypes_free(void)
95 {
96         SpaceType *st;
97
98         for (st = spacetypes.first; st; st = st->next) {
99                 spacetype_free(st);
100         }
101
102         BLI_freelistN(&spacetypes);
103 }
104
105 SpaceType *BKE_spacetype_from_id(int spaceid)
106 {
107         SpaceType *st;
108
109         for (st = spacetypes.first; st; st = st->next) {
110                 if (st->spaceid == spaceid)
111                         return st;
112         }
113         return NULL;
114 }
115
116 ARegionType *BKE_regiontype_from_id_or_first(SpaceType *st, int regionid)
117 {
118         ARegionType *art;
119
120         for (art = st->regiontypes.first; art; art = art->next)
121                 if (art->regionid == regionid)
122                         return art;
123
124         printf("Error, region type %d missing in - name:\"%s\", id:%d\n", regionid, st->name, st->spaceid);
125         return st->regiontypes.first;
126 }
127
128 ARegionType *BKE_regiontype_from_id(SpaceType *st, int regionid)
129 {
130         ARegionType *art;
131
132         for (art = st->regiontypes.first; art; art = art->next) {
133                 if (art->regionid == regionid) {
134                         return art;
135                 }
136         }
137         return NULL;
138 }
139
140
141 const ListBase *BKE_spacetypes_list(void)
142 {
143         return &spacetypes;
144 }
145
146 void BKE_spacetype_register(SpaceType *st)
147 {
148         SpaceType *stype;
149
150         /* sanity check */
151         stype = BKE_spacetype_from_id(st->spaceid);
152         if (stype) {
153                 printf("error: redefinition of spacetype %s\n", stype->name);
154                 spacetype_free(stype);
155                 MEM_freeN(stype);
156         }
157
158         BLI_addtail(&spacetypes, st);
159 }
160
161 bool BKE_spacetype_exists(int spaceid)
162 {
163         return BKE_spacetype_from_id(spaceid) != NULL;
164 }
165
166 /* ***************** Space handling ********************** */
167
168 void BKE_spacedata_freelist(ListBase *lb)
169 {
170         SpaceLink *sl;
171         ARegion *ar;
172
173         for (sl = lb->first; sl; sl = sl->next) {
174                 SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
175
176                 /* free regions for pushed spaces */
177                 for (ar = sl->regionbase.first; ar; ar = ar->next)
178                         BKE_area_region_free(st, ar);
179
180                 BLI_freelistN(&sl->regionbase);
181
182                 if (st && st->free)
183                         st->free(sl);
184         }
185
186         BLI_freelistN(lb);
187 }
188
189 static void panel_list_copy(ListBase *newlb, const ListBase *lb)
190 {
191         BLI_listbase_clear(newlb);
192         BLI_duplicatelist(newlb, lb);
193
194         /* copy panel pointers */
195         Panel *newpa = newlb->first;
196         Panel *pa = lb->first;
197         for (; newpa; newpa = newpa->next, pa = pa->next) {
198                 newpa->activedata = NULL;
199
200                 Panel *newpatab = newlb->first;
201                 Panel *patab = lb->first;
202                 while (newpatab) {
203                         if (newpa->paneltab == patab) {
204                                 newpa->paneltab = newpatab;
205                                 break;
206                         }
207                         newpatab = newpatab->next;
208                         patab = patab->next;
209                 }
210
211                 panel_list_copy(&newpa->children, &pa->children);
212         }
213 }
214
215 ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
216 {
217         ARegion *newar = MEM_dupallocN(ar);
218
219         newar->prev = newar->next = NULL;
220         BLI_listbase_clear(&newar->handlers);
221         BLI_listbase_clear(&newar->uiblocks);
222         BLI_listbase_clear(&newar->panels_category);
223         BLI_listbase_clear(&newar->panels_category_active);
224         BLI_listbase_clear(&newar->ui_lists);
225         newar->visible = 0;
226         newar->gizmo_map = NULL;
227         newar->regiontimer = NULL;
228         newar->headerstr = NULL;
229         newar->draw_buffer = NULL;
230
231         /* use optional regiondata callback */
232         if (ar->regiondata) {
233                 ARegionType *art = BKE_regiontype_from_id(st, ar->regiontype);
234
235                 if (art && art->duplicate) {
236                         newar->regiondata = art->duplicate(ar->regiondata);
237                 }
238                 else if (ar->flag & RGN_FLAG_TEMP_REGIONDATA) {
239                         newar->regiondata = NULL;
240                 }
241                 else {
242                         newar->regiondata = MEM_dupallocN(ar->regiondata);
243                 }
244         }
245
246         if (ar->v2d.tab_offset)
247                 newar->v2d.tab_offset = MEM_dupallocN(ar->v2d.tab_offset);
248
249         panel_list_copy(&newar->panels, &ar->panels);
250
251         BLI_listbase_clear(&newar->ui_previews);
252         BLI_duplicatelist(&newar->ui_previews, &ar->ui_previews);
253
254         return newar;
255 }
256
257
258 /* from lb2 to lb1, lb1 is supposed to be freed */
259 static void region_copylist(SpaceType *st, ListBase *lb1, ListBase *lb2)
260 {
261         ARegion *ar;
262
263         /* to be sure */
264         BLI_listbase_clear(lb1);
265
266         for (ar = lb2->first; ar; ar = ar->next) {
267                 ARegion *arnew = BKE_area_region_copy(st, ar);
268                 BLI_addtail(lb1, arnew);
269         }
270 }
271
272
273 /* lb1 should be empty */
274 void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2)
275 {
276         SpaceLink *sl;
277
278         BLI_listbase_clear(lb1);  /* to be sure */
279
280         for (sl = lb2->first; sl; sl = sl->next) {
281                 SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
282
283                 if (st && st->duplicate) {
284                         SpaceLink *slnew = st->duplicate(sl);
285
286                         BLI_addtail(lb1, slnew);
287
288                         region_copylist(st, &slnew->regionbase, &sl->regionbase);
289                 }
290         }
291 }
292
293 /* facility to set locks for drawing to survive (render) threads accessing drawing data */
294 /* lock can become bitflag too */
295 /* should be replaced in future by better local data handling for threads */
296 void BKE_spacedata_draw_locks(int set)
297 {
298         SpaceType *st;
299
300         for (st = spacetypes.first; st; st = st->next) {
301                 ARegionType *art;
302
303                 for (art = st->regiontypes.first; art; art = art->next) {
304                         if (set)
305                                 art->do_lock = art->lock;
306                         else
307                                 art->do_lock = false;
308                 }
309         }
310 }
311
312 /**
313  * Version of #BKE_area_find_region_type that also works if \a slink is not the active space of \a sa.
314  */
315 ARegion *BKE_spacedata_find_region_type(const SpaceLink *slink, const ScrArea *sa, int region_type)
316 {
317         const bool is_slink_active = slink == sa->spacedata.first;
318         const ListBase *regionbase = (is_slink_active) ?
319                                    &sa->regionbase : &slink->regionbase;
320         ARegion *ar = NULL;
321
322         BLI_assert(BLI_findindex(&sa->spacedata, slink) != -1);
323         for (ar = regionbase->first; ar; ar = ar->next) {
324                 if (ar->regiontype == region_type) {
325                         break;
326                 }
327         }
328
329         /* Should really unit test this instead. */
330         BLI_assert(!is_slink_active || ar == BKE_area_find_region_type(sa, region_type));
331
332         return ar;
333 }
334
335
336 static void (*spacedata_id_remap_cb)(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id) = NULL;
337
338 void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *sa, SpaceLink *sl, ID *, ID *))
339 {
340         spacedata_id_remap_cb = func;
341 }
342
343 /* UNUSED!!! */
344 void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id)
345 {
346         if (spacedata_id_remap_cb) {
347                 spacedata_id_remap_cb(sa, sl, id, NULL);
348         }
349 }
350
351 /**
352  * Avoid bad-level calls to #WM_gizmomap_tag_refresh.
353  */
354 static void (*region_refresh_tag_gizmomap_callback)(struct wmGizmoMap *) = NULL;
355
356 void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizmoMap *))
357 {
358         region_refresh_tag_gizmomap_callback = callback;
359 }
360
361 void BKE_screen_gizmo_tag_refresh(struct bScreen *sc)
362 {
363         if (region_refresh_tag_gizmomap_callback == NULL) {
364                 return;
365         }
366
367         ScrArea *sa;
368         ARegion *ar;
369         for (sa = sc->areabase.first; sa; sa = sa->next) {
370                 for (ar = sa->regionbase.first; ar; ar = ar->next) {
371                         if (ar->gizmo_map != NULL) {
372                                 region_refresh_tag_gizmomap_callback(ar->gizmo_map);
373                         }
374                 }
375         }
376 }
377
378 /**
379  * Avoid bad-level calls to #WM_gizmomap_delete.
380  */
381 static void (*region_free_gizmomap_callback)(struct wmGizmoMap *) = NULL;
382
383 void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *))
384 {
385         region_free_gizmomap_callback = callback;
386 }
387
388 void BKE_area_region_panels_free(ListBase *lb)
389 {
390         Panel *pa, *pa_next;
391         for (pa = lb->first; pa; pa = pa_next) {
392                 pa_next = pa->next;
393                 if (pa->activedata) {
394                         MEM_freeN(pa->activedata);
395                 }
396                 BKE_area_region_panels_free(&pa->children);
397         }
398
399         BLI_freelistN(lb);
400 }
401
402 /* not region itself */
403 void BKE_area_region_free(SpaceType *st, ARegion *ar)
404 {
405         uiList *uilst;
406
407         if (st) {
408                 ARegionType *art = BKE_regiontype_from_id(st, ar->regiontype);
409
410                 if (art && art->free)
411                         art->free(ar);
412
413                 if (ar->regiondata)
414                         printf("regiondata free error\n");
415         }
416         else if (ar->type && ar->type->free)
417                 ar->type->free(ar);
418
419         if (ar->v2d.tab_offset) {
420                 MEM_freeN(ar->v2d.tab_offset);
421                 ar->v2d.tab_offset = NULL;
422         }
423
424         BKE_area_region_panels_free(&ar->panels);
425
426         for (uilst = ar->ui_lists.first; uilst; uilst = uilst->next) {
427                 if (uilst->dyn_data) {
428                         uiListDyn *dyn_data = uilst->dyn_data;
429                         if (dyn_data->items_filter_flags) {
430                                 MEM_freeN(dyn_data->items_filter_flags);
431                         }
432                         if (dyn_data->items_filter_neworder) {
433                                 MEM_freeN(dyn_data->items_filter_neworder);
434                         }
435                         MEM_freeN(dyn_data);
436                 }
437                 if (uilst->properties) {
438                         IDP_FreeProperty(uilst->properties);
439                         MEM_freeN(uilst->properties);
440                 }
441         }
442
443         if (ar->gizmo_map != NULL) {
444                 region_free_gizmomap_callback(ar->gizmo_map);
445         }
446
447         BLI_freelistN(&ar->ui_lists);
448         BLI_freelistN(&ar->ui_previews);
449         BLI_freelistN(&ar->panels_category);
450         BLI_freelistN(&ar->panels_category_active);
451 }
452
453 /* not area itself */
454 void BKE_screen_area_free(ScrArea *sa)
455 {
456         SpaceType *st = BKE_spacetype_from_id(sa->spacetype);
457         ARegion *ar;
458
459         for (ar = sa->regionbase.first; ar; ar = ar->next)
460                 BKE_area_region_free(st, ar);
461
462         MEM_SAFE_FREE(sa->global);
463         BLI_freelistN(&sa->regionbase);
464
465         BKE_spacedata_freelist(&sa->spacedata);
466
467         BLI_freelistN(&sa->actionzones);
468 }
469
470 void BKE_screen_area_map_free(ScrAreaMap *area_map)
471 {
472         for (ScrArea *area = area_map->areabase.first, *area_next; area; area = area_next) {
473                 area_next = area->next;
474                 BKE_screen_area_free(area);
475         }
476
477         BLI_freelistN(&area_map->vertbase);
478         BLI_freelistN(&area_map->edgebase);
479         BLI_freelistN(&area_map->areabase);
480 }
481
482 /** Free (or release) any data used by this screen (does not free the screen itself). */
483 void BKE_screen_free(bScreen *sc)
484 {
485         ARegion *ar;
486
487         /* No animdata here. */
488
489         for (ar = sc->regionbase.first; ar; ar = ar->next)
490                 BKE_area_region_free(NULL, ar);
491
492         BLI_freelistN(&sc->regionbase);
493
494         BKE_screen_area_map_free(AREAMAP_FROM_SCREEN(sc));
495
496         BKE_previewimg_free(&sc->preview);
497
498         /* Region and timer are freed by the window manager. */
499         MEM_SAFE_FREE(sc->tool_tip);
500 }
501
502 /* ***************** Screen edges & verts ***************** */
503
504 ScrEdge *BKE_screen_find_edge(bScreen *sc, ScrVert *v1, ScrVert *v2)
505 {
506         ScrEdge *se;
507
508         BKE_screen_sort_scrvert(&v1, &v2);
509         for (se = sc->edgebase.first; se; se = se->next) {
510                 if (se->v1 == v1 && se->v2 == v2) {
511                         return se;
512                 }
513         }
514
515         return NULL;
516 }
517
518 void BKE_screen_sort_scrvert(ScrVert **v1, ScrVert **v2)
519 {
520         ScrVert *tmp;
521
522         if (*v1 > *v2) {
523                 tmp = *v1;
524                 *v1 = *v2;
525                 *v2 = tmp;
526         }
527 }
528
529 void BKE_screen_remove_double_scrverts(bScreen *sc)
530 {
531         ScrVert *v1, *verg;
532         ScrEdge *se;
533         ScrArea *sa;
534
535         verg = sc->vertbase.first;
536         while (verg) {
537                 if (verg->newv == NULL) { /* !!! */
538                         v1 = verg->next;
539                         while (v1) {
540                                 if (v1->newv == NULL) {   /* !?! */
541                                         if (v1->vec.x == verg->vec.x && v1->vec.y == verg->vec.y) {
542                                                 /* printf("doublevert\n"); */
543                                                 v1->newv = verg;
544                                         }
545                                 }
546                                 v1 = v1->next;
547                         }
548                 }
549                 verg = verg->next;
550         }
551
552         /* replace pointers in edges and faces */
553         se = sc->edgebase.first;
554         while (se) {
555                 if (se->v1->newv) se->v1 = se->v1->newv;
556                 if (se->v2->newv) se->v2 = se->v2->newv;
557                 /* edges changed: so.... */
558                 BKE_screen_sort_scrvert(&(se->v1), &(se->v2));
559                 se = se->next;
560         }
561         sa = sc->areabase.first;
562         while (sa) {
563                 if (sa->v1->newv) sa->v1 = sa->v1->newv;
564                 if (sa->v2->newv) sa->v2 = sa->v2->newv;
565                 if (sa->v3->newv) sa->v3 = sa->v3->newv;
566                 if (sa->v4->newv) sa->v4 = sa->v4->newv;
567                 sa = sa->next;
568         }
569
570         /* remove */
571         verg = sc->vertbase.first;
572         while (verg) {
573                 v1 = verg->next;
574                 if (verg->newv) {
575                         BLI_remlink(&sc->vertbase, verg);
576                         MEM_freeN(verg);
577                 }
578                 verg = v1;
579         }
580
581 }
582
583 void BKE_screen_remove_double_scredges(bScreen *sc)
584 {
585         ScrEdge *verg, *se, *sn;
586
587         /* compare */
588         verg = sc->edgebase.first;
589         while (verg) {
590                 se = verg->next;
591                 while (se) {
592                         sn = se->next;
593                         if (verg->v1 == se->v1 && verg->v2 == se->v2) {
594                                 BLI_remlink(&sc->edgebase, se);
595                                 MEM_freeN(se);
596                         }
597                         se = sn;
598                 }
599                 verg = verg->next;
600         }
601 }
602
603 void BKE_screen_remove_unused_scredges(bScreen *sc)
604 {
605         ScrEdge *se, *sen;
606         ScrArea *sa;
607         int a = 0;
608
609         /* sets flags when edge is used in area */
610         sa = sc->areabase.first;
611         while (sa) {
612                 se = BKE_screen_find_edge(sc, sa->v1, sa->v2);
613                 if (se == NULL) printf("error: area %d edge 1 doesn't exist\n", a);
614                 else se->flag = 1;
615                 se = BKE_screen_find_edge(sc, sa->v2, sa->v3);
616                 if (se == NULL) printf("error: area %d edge 2 doesn't exist\n", a);
617                 else se->flag = 1;
618                 se = BKE_screen_find_edge(sc, sa->v3, sa->v4);
619                 if (se == NULL) printf("error: area %d edge 3 doesn't exist\n", a);
620                 else se->flag = 1;
621                 se = BKE_screen_find_edge(sc, sa->v4, sa->v1);
622                 if (se == NULL) printf("error: area %d edge 4 doesn't exist\n", a);
623                 else se->flag = 1;
624                 sa = sa->next;
625                 a++;
626         }
627         se = sc->edgebase.first;
628         while (se) {
629                 sen = se->next;
630                 if (se->flag == 0) {
631                         BLI_remlink(&sc->edgebase, se);
632                         MEM_freeN(se);
633                 }
634                 else {
635                         se->flag = 0;
636                 }
637                 se = sen;
638         }
639 }
640
641 void BKE_screen_remove_unused_scrverts(bScreen *sc)
642 {
643         ScrVert *sv, *svn;
644         ScrEdge *se;
645
646         /* we assume edges are ok */
647
648         se = sc->edgebase.first;
649         while (se) {
650                 se->v1->flag = 1;
651                 se->v2->flag = 1;
652                 se = se->next;
653         }
654
655         sv = sc->vertbase.first;
656         while (sv) {
657                 svn = sv->next;
658                 if (sv->flag == 0) {
659                         BLI_remlink(&sc->vertbase, sv);
660                         MEM_freeN(sv);
661                 }
662                 else {
663                         sv->flag = 0;
664                 }
665                 sv = svn;
666         }
667 }
668
669 /* ***************** Utilities ********************** */
670
671 /**
672  * Find a region of type \a region_type in the currently active space of \a sa.
673  *
674  * \note This does _not_ work if the region to look up is not in the active
675  *       space. Use #BKE_spacedata_find_region_type if that may be the case.
676  */
677 ARegion *BKE_area_find_region_type(const ScrArea *sa, int region_type)
678 {
679         if (sa) {
680                 for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
681                         if (ar->regiontype == region_type)
682                                 return ar;
683                 }
684         }
685
686         return NULL;
687 }
688
689 ARegion *BKE_area_find_region_active_win(ScrArea *sa)
690 {
691         if (sa) {
692                 ARegion *ar = BLI_findlink(&sa->regionbase, sa->region_active_win);
693                 if (ar && (ar->regiontype == RGN_TYPE_WINDOW)) {
694                         return ar;
695                 }
696
697                 /* fallback to any */
698                 return BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
699         }
700         return NULL;
701 }
702
703 ARegion *BKE_area_find_region_xy(ScrArea *sa, const int regiontype, int x, int y)
704 {
705         ARegion *ar_found = NULL;
706         if (sa) {
707                 ARegion *ar;
708                 for (ar = sa->regionbase.first; ar; ar = ar->next) {
709                         if ((regiontype == RGN_TYPE_ANY) || (ar->regiontype == regiontype)) {
710                                 if (BLI_rcti_isect_pt(&ar->winrct, x, y)) {
711                                         ar_found = ar;
712                                         break;
713                                 }
714                         }
715                 }
716         }
717         return ar_found;
718 }
719
720 /**
721  * \note, ideally we can get the area from the context,
722  * there are a few places however where this isn't practical.
723  */
724 ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, SpaceLink *sl)
725 {
726         ScrArea *sa;
727
728         for (sa = sc->areabase.first; sa; sa = sa->next) {
729                 if (BLI_findindex(&sa->spacedata, sl) != -1) {
730                         break;
731                 }
732         }
733
734         return sa;
735 }
736
737 /**
738  * \note Using this function is generally a last resort, you really want to be
739  * using the context when you can - campbell
740  */
741 ScrArea *BKE_screen_find_big_area(bScreen *sc, const int spacetype, const short min)
742 {
743         ScrArea *sa, *big = NULL;
744         int size, maxsize = 0;
745
746         for (sa = sc->areabase.first; sa; sa = sa->next) {
747                 if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) {
748                         if (min <= sa->winx && min <= sa->winy) {
749                                 size = sa->winx * sa->winy;
750                                 if (size > maxsize) {
751                                         maxsize = size;
752                                         big = sa;
753                                 }
754                         }
755                 }
756         }
757
758         return big;
759 }
760
761 ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap, const int spacetype, int x, int y)
762 {
763         for (ScrArea *sa = areamap->areabase.first; sa; sa = sa->next) {
764                 if (BLI_rcti_isect_pt(&sa->totrct, x, y)) {
765                         if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) {
766                                 return sa;
767                         }
768                         break;
769                 }
770         }
771         return NULL;
772 }
773 ScrArea *BKE_screen_find_area_xy(bScreen *sc, const int spacetype, int x, int y)
774 {
775         return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(sc), spacetype, x, y);
776 }
777
778 void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
779 {
780         if (v3d->scenelock && v3d->localvd == NULL) {
781                 v3d->camera = scene->camera;
782
783                 if (v3d->camera == NULL) {
784                         ARegion *ar;
785
786                         for (ar = v3d->regionbase.first; ar; ar = ar->next) {
787                                 if (ar->regiontype == RGN_TYPE_WINDOW) {
788                                         RegionView3D *rv3d = ar->regiondata;
789                                         if (rv3d->persp == RV3D_CAMOB)
790                                                 rv3d->persp = RV3D_PERSP;
791                                 }
792                         }
793                 }
794         }
795 }
796
797 void BKE_screen_view3d_scene_sync(bScreen *sc, Scene *scene)
798 {
799         /* are there cameras in the views that are not in the scene? */
800         ScrArea *sa;
801         for (sa = sc->areabase.first; sa; sa = sa->next) {
802                 SpaceLink *sl;
803                 for (sl = sa->spacedata.first; sl; sl = sl->next) {
804                         if (sl->spacetype == SPACE_VIEW3D) {
805                                 View3D *v3d = (View3D *) sl;
806                                 BKE_screen_view3d_sync(v3d, scene);
807                         }
808                 }
809         }
810 }
811
812 void BKE_screen_view3d_shading_init(View3DShading *shading)
813 {
814         memset(shading, 0, sizeof(*shading));
815
816         shading->type = OB_SOLID;
817         shading->prev_type = OB_SOLID;
818         shading->flag = V3D_SHADING_SPECULAR_HIGHLIGHT | V3D_SHADING_XRAY_BONE;
819         shading->light = V3D_LIGHTING_STUDIO;
820         shading->shadow_intensity = 0.5f;
821         shading->xray_alpha = 0.5f;
822         shading->xray_alpha_wire = 0.5f;
823         shading->cavity_valley_factor = 1.0f;
824         shading->cavity_ridge_factor = 1.0f;
825         copy_v3_fl(shading->single_color, 0.8f);
826         copy_v3_fl(shading->background_color, 0.05f);
827 }
828
829 /* magic zoom calculation, no idea what
830  * it signifies, if you find out, tell me! -zr
831  */
832
833 /* simple, its magic dude!
834  * well, to be honest, this gives a natural feeling zooming
835  * with multiple keypad presses (ton)
836  */
837 float BKE_screen_view3d_zoom_to_fac(float camzoom)
838 {
839         return powf(((float)M_SQRT2 + camzoom / 50.0f), 2.0f) / 4.0f;
840 }
841
842 float BKE_screen_view3d_zoom_from_fac(float zoomfac)
843 {
844         return ((sqrtf(4.0f * zoomfac) - (float)M_SQRT2) * 50.0f);
845 }
846
847 bool BKE_screen_is_fullscreen_area(const bScreen *screen)
848 {
849         return ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL);
850 }
851
852 bool BKE_screen_is_used(const bScreen *screen)
853 {
854         return (screen->winid != 0);
855 }