1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup bke
22 */
23
24 #ifdef WIN32
25 # include "BLI_winstuff.h"
26 #endif
27
28 #include <math.h>
29 #include <stdio.h>
30 #include <string.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_defaults.h"
35 #include "DNA_gpencil_types.h"
36 #include "DNA_mask_types.h"
37 #include "DNA_scene_types.h"
38 #include "DNA_screen_types.h"
39 #include "DNA_space_types.h"
40 #include "DNA_text_types.h"
41 #include "DNA_view3d_types.h"
42 #include "DNA_workspace_types.h"
43
44 #include "BLI_listbase.h"
45 #include "BLI_math_vector.h"
46 #include "BLI_mempool.h"
47 #include "BLI_rect.h"
48 #include "BLI_utildefines.h"
49
50 #include "BLT_translation.h"
51
52 #include "BKE_icons.h"
53 #include "BKE_idprop.h"
54 #include "BKE_idtype.h"
55 #include "BKE_lib_query.h"
56 #include "BKE_node.h"
57 #include "BKE_screen.h"
58 #include "BKE_workspace.h"
59
screen_free_data(ID * id)60 static void screen_free_data(ID *id)
61 {
62 bScreen *screen = (bScreen *)id;
63 ARegion *region;
64
65 /* No animdata here. */
66
67 for (region = screen->regionbase.first; region; region = region->next) {
68 BKE_area_region_free(NULL, region);
69 }
70
71 BLI_freelistN(&screen->regionbase);
72
73 BKE_screen_area_map_free(AREAMAP_FROM_SCREEN(screen));
74
75 BKE_previewimg_free(&screen->preview);
76
77 /* Region and timer are freed by the window manager. */
78 MEM_SAFE_FREE(screen->tool_tip);
79 }
80
screen_foreach_id_dopesheet(LibraryForeachIDData * data,bDopeSheet * ads)81 static void screen_foreach_id_dopesheet(LibraryForeachIDData *data, bDopeSheet *ads)
82 {
83 if (ads != NULL) {
84 BKE_LIB_FOREACHID_PROCESS_ID(data, ads->source, IDWALK_CB_NOP);
85 BKE_LIB_FOREACHID_PROCESS(data, ads->filter_grp, IDWALK_CB_NOP);
86 }
87 }
88
BKE_screen_foreach_id_screen_area(LibraryForeachIDData * data,ScrArea * area)89 void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area)
90 {
91 BKE_LIB_FOREACHID_PROCESS(data, area->full, IDWALK_CB_NOP);
92
93 /* TODO this should be moved to a callback in `SpaceType`, defined in each editor's own code.
94 * Will be for a later round of cleanup though... */
95 LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
96 switch (sl->spacetype) {
97 case SPACE_VIEW3D: {
98 View3D *v3d = (View3D *)sl;
99
100 BKE_LIB_FOREACHID_PROCESS(data, v3d->camera, IDWALK_CB_NOP);
101 BKE_LIB_FOREACHID_PROCESS(data, v3d->ob_center, IDWALK_CB_NOP);
102
103 if (v3d->localvd) {
104 BKE_LIB_FOREACHID_PROCESS(data, v3d->localvd->camera, IDWALK_CB_NOP);
105 }
106 break;
107 }
108 case SPACE_GRAPH: {
109 SpaceGraph *sipo = (SpaceGraph *)sl;
110
111 screen_foreach_id_dopesheet(data, sipo->ads);
112 break;
113 }
114 case SPACE_PROPERTIES: {
115 SpaceProperties *sbuts = (SpaceProperties *)sl;
116
117 BKE_LIB_FOREACHID_PROCESS_ID(data, sbuts->pinid, IDWALK_CB_NOP);
118 break;
119 }
120 case SPACE_FILE:
121 break;
122 case SPACE_ACTION: {
123 SpaceAction *saction = (SpaceAction *)sl;
124
125 screen_foreach_id_dopesheet(data, &saction->ads);
126 BKE_LIB_FOREACHID_PROCESS(data, saction->action, IDWALK_CB_NOP);
127 break;
128 }
129 case SPACE_IMAGE: {
130 SpaceImage *sima = (SpaceImage *)sl;
131
132 BKE_LIB_FOREACHID_PROCESS(data, sima->image, IDWALK_CB_USER_ONE);
133 BKE_LIB_FOREACHID_PROCESS(data, sima->mask_info.mask, IDWALK_CB_USER_ONE);
134 BKE_LIB_FOREACHID_PROCESS(data, sima->gpd, IDWALK_CB_USER);
135 break;
136 }
137 case SPACE_SEQ: {
138 SpaceSeq *sseq = (SpaceSeq *)sl;
139
140 BKE_LIB_FOREACHID_PROCESS(data, sseq->gpd, IDWALK_CB_USER);
141 break;
142 }
143 case SPACE_NLA: {
144 SpaceNla *snla = (SpaceNla *)sl;
145
146 screen_foreach_id_dopesheet(data, snla->ads);
147 break;
148 }
149 case SPACE_TEXT: {
150 SpaceText *st = (SpaceText *)sl;
151
152 BKE_LIB_FOREACHID_PROCESS(data, st->text, IDWALK_CB_NOP);
153 break;
154 }
155 case SPACE_SCRIPT: {
156 SpaceScript *scpt = (SpaceScript *)sl;
157
158 BKE_LIB_FOREACHID_PROCESS(data, scpt->script, IDWALK_CB_NOP);
159 break;
160 }
161 case SPACE_OUTLINER: {
162 SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
163
164 BKE_LIB_FOREACHID_PROCESS_ID(data, space_outliner->search_tse.id, IDWALK_CB_NOP);
165
166 if (space_outliner->treestore != NULL) {
167 TreeStoreElem *tselem;
168 BLI_mempool_iter iter;
169
170 BLI_mempool_iternew(space_outliner->treestore, &iter);
171 while ((tselem = BLI_mempool_iterstep(&iter))) {
172 BKE_LIB_FOREACHID_PROCESS_ID(data, tselem->id, IDWALK_CB_NOP);
173 }
174 }
175 break;
176 }
177 case SPACE_NODE: {
178 SpaceNode *snode = (SpaceNode *)sl;
179
180 const bool is_private_nodetree = snode->id != NULL &&
181 ntreeFromID(snode->id) == snode->nodetree;
182
183 BKE_LIB_FOREACHID_PROCESS_ID(data, snode->id, IDWALK_CB_NOP);
184 BKE_LIB_FOREACHID_PROCESS_ID(data, snode->from, IDWALK_CB_NOP);
185
186 BKE_LIB_FOREACHID_PROCESS(
187 data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE);
188
189 LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) {
190 if (path == snode->treepath.first) {
191 /* first nodetree in path is same as snode->nodetree */
192 BKE_LIB_FOREACHID_PROCESS(data,
193 path->nodetree,
194 is_private_nodetree ? IDWALK_CB_EMBEDDED :
195 IDWALK_CB_USER_ONE);
196 }
197 else {
198 BKE_LIB_FOREACHID_PROCESS(data, path->nodetree, IDWALK_CB_USER_ONE);
199 }
200
201 if (path->nodetree == NULL) {
202 break;
203 }
204 }
205
206 BKE_LIB_FOREACHID_PROCESS(data, snode->edittree, IDWALK_CB_NOP);
207 break;
208 }
209 case SPACE_CLIP: {
210 SpaceClip *sclip = (SpaceClip *)sl;
211
212 BKE_LIB_FOREACHID_PROCESS(data, sclip->clip, IDWALK_CB_USER_ONE);
213 BKE_LIB_FOREACHID_PROCESS(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE);
214 break;
215 }
216 default:
217 break;
218 }
219 }
220 }
221
screen_foreach_id(ID * id,LibraryForeachIDData * data)222 static void screen_foreach_id(ID *id, LibraryForeachIDData *data)
223 {
224 if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) {
225 bScreen *screen = (bScreen *)id;
226
227 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
228 BKE_screen_foreach_id_screen_area(data, area);
229 }
230 }
231 }
232
233 IDTypeInfo IDType_ID_SCR = {
234 .id_code = ID_SCR,
235 .id_filter = 0,
236 .main_listbase_index = INDEX_ID_SCR,
237 .struct_size = sizeof(bScreen),
238 .name = "Screen",
239 .name_plural = "screens",
240 .translation_context = BLT_I18NCONTEXT_ID_SCREEN,
241 .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_MAKELOCAL | IDTYPE_FLAGS_NO_ANIMDATA,
242
243 .init_data = NULL,
244 .copy_data = NULL,
245 .free_data = screen_free_data,
246 .make_local = NULL,
247 .foreach_id = screen_foreach_id,
248 .foreach_cache = NULL,
249
250 .blend_write = NULL,
251 .blend_read_data = NULL,
252 .blend_read_lib = NULL,
253 .blend_read_expand = NULL,
254 };
255
256 /* ************ Spacetype/regiontype handling ************** */
257
258 /* keep global; this has to be accessible outside of windowmanager */
259 static ListBase spacetypes = {NULL, NULL};
260
261 /* not SpaceType itself */
spacetype_free(SpaceType * st)262 static void spacetype_free(SpaceType *st)
263 {
264 ARegionType *art;
265 PanelType *pt;
266 HeaderType *ht;
267
268 for (art = st->regiontypes.first; art; art = art->next) {
269 BLI_freelistN(&art->drawcalls);
270
271 for (pt = art->paneltypes.first; pt; pt = pt->next) {
272 if (pt->rna_ext.free) {
273 pt->rna_ext.free(pt->rna_ext.data);
274 }
275
276 BLI_freelistN(&pt->children);
277 }
278
279 for (ht = art->headertypes.first; ht; ht = ht->next) {
280 if (ht->rna_ext.free) {
281 ht->rna_ext.free(ht->rna_ext.data);
282 }
283 }
284
285 BLI_freelistN(&art->paneltypes);
286 BLI_freelistN(&art->headertypes);
287 }
288
289 BLI_freelistN(&st->regiontypes);
290 }
291
BKE_spacetypes_free(void)292 void BKE_spacetypes_free(void)
293 {
294 SpaceType *st;
295
296 for (st = spacetypes.first; st; st = st->next) {
297 spacetype_free(st);
298 }
299
300 BLI_freelistN(&spacetypes);
301 }
302
BKE_spacetype_from_id(int spaceid)303 SpaceType *BKE_spacetype_from_id(int spaceid)
304 {
305 SpaceType *st;
306
307 for (st = spacetypes.first; st; st = st->next) {
308 if (st->spaceid == spaceid) {
309 return st;
310 }
311 }
312 return NULL;
313 }
314
BKE_regiontype_from_id_or_first(SpaceType * st,int regionid)315 ARegionType *BKE_regiontype_from_id_or_first(SpaceType *st, int regionid)
316 {
317 ARegionType *art;
318
319 for (art = st->regiontypes.first; art; art = art->next) {
320 if (art->regionid == regionid) {
321 return art;
322 }
323 }
324
325 printf(
326 "Error, region type %d missing in - name:\"%s\", id:%d\n", regionid, st->name, st->spaceid);
327 return st->regiontypes.first;
328 }
329
BKE_regiontype_from_id(SpaceType * st,int regionid)330 ARegionType *BKE_regiontype_from_id(SpaceType *st, int regionid)
331 {
332 ARegionType *art;
333
334 for (art = st->regiontypes.first; art; art = art->next) {
335 if (art->regionid == regionid) {
336 return art;
337 }
338 }
339 return NULL;
340 }
341
BKE_spacetypes_list(void)342 const ListBase *BKE_spacetypes_list(void)
343 {
344 return &spacetypes;
345 }
346
BKE_spacetype_register(SpaceType * st)347 void BKE_spacetype_register(SpaceType *st)
348 {
349 SpaceType *stype;
350
351 /* sanity check */
352 stype = BKE_spacetype_from_id(st->spaceid);
353 if (stype) {
354 printf("error: redefinition of spacetype %s\n", stype->name);
355 spacetype_free(stype);
356 MEM_freeN(stype);
357 }
358
359 BLI_addtail(&spacetypes, st);
360 }
361
BKE_spacetype_exists(int spaceid)362 bool BKE_spacetype_exists(int spaceid)
363 {
364 return BKE_spacetype_from_id(spaceid) != NULL;
365 }
366
367 /* ***************** Space handling ********************** */
368
BKE_spacedata_freelist(ListBase * lb)369 void BKE_spacedata_freelist(ListBase *lb)
370 {
371 SpaceLink *sl;
372 ARegion *region;
373
374 for (sl = lb->first; sl; sl = sl->next) {
375 SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
376
377 /* free regions for pushed spaces */
378 for (region = sl->regionbase.first; region; region = region->next) {
379 BKE_area_region_free(st, region);
380 }
381
382 BLI_freelistN(&sl->regionbase);
383
384 if (st && st->free) {
385 st->free(sl);
386 }
387 }
388
389 BLI_freelistN(lb);
390 }
391
panel_list_copy(ListBase * newlb,const ListBase * lb)392 static void panel_list_copy(ListBase *newlb, const ListBase *lb)
393 {
394 BLI_listbase_clear(newlb);
395 BLI_duplicatelist(newlb, lb);
396
397 /* copy panel pointers */
398 Panel *new_panel = newlb->first;
399 Panel *panel = lb->first;
400 for (; new_panel; new_panel = new_panel->next, panel = panel->next) {
401 new_panel->activedata = NULL;
402 new_panel->runtime.custom_data_ptr = NULL;
403 panel_list_copy(&new_panel->children, &panel->children);
404 }
405 }
406
BKE_area_region_copy(SpaceType * st,ARegion * region)407 ARegion *BKE_area_region_copy(SpaceType *st, ARegion *region)
408 {
409 ARegion *newar = MEM_dupallocN(region);
410
411 newar->prev = newar->next = NULL;
412 BLI_listbase_clear(&newar->handlers);
413 BLI_listbase_clear(&newar->uiblocks);
414 BLI_listbase_clear(&newar->panels_category);
415 BLI_listbase_clear(&newar->panels_category_active);
416 BLI_listbase_clear(&newar->ui_lists);
417 newar->visible = 0;
418 newar->gizmo_map = NULL;
419 newar->regiontimer = NULL;
420 newar->headerstr = NULL;
421 newar->draw_buffer = NULL;
422
423 /* use optional regiondata callback */
424 if (region->regiondata) {
425 ARegionType *art = BKE_regiontype_from_id(st, region->regiontype);
426
427 if (art && art->duplicate) {
428 newar->regiondata = art->duplicate(region->regiondata);
429 }
430 else if (region->flag & RGN_FLAG_TEMP_REGIONDATA) {
431 newar->regiondata = NULL;
432 }
433 else {
434 newar->regiondata = MEM_dupallocN(region->regiondata);
435 }
436 }
437
438 panel_list_copy(&newar->panels, ®ion->panels);
439
440 BLI_listbase_clear(&newar->ui_previews);
441 BLI_duplicatelist(&newar->ui_previews, ®ion->ui_previews);
442
443 return newar;
444 }
445
446 /* from lb2 to lb1, lb1 is supposed to be freed */
region_copylist(SpaceType * st,ListBase * lb1,ListBase * lb2)447 static void region_copylist(SpaceType *st, ListBase *lb1, ListBase *lb2)
448 {
449 ARegion *region;
450
451 /* to be sure */
452 BLI_listbase_clear(lb1);
453
454 for (region = lb2->first; region; region = region->next) {
455 ARegion *arnew = BKE_area_region_copy(st, region);
456 BLI_addtail(lb1, arnew);
457 }
458 }
459
460 /* lb1 should be empty */
BKE_spacedata_copylist(ListBase * lb1,ListBase * lb2)461 void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2)
462 {
463 SpaceLink *sl;
464
465 BLI_listbase_clear(lb1); /* to be sure */
466
467 for (sl = lb2->first; sl; sl = sl->next) {
468 SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
469
470 if (st && st->duplicate) {
471 SpaceLink *slnew = st->duplicate(sl);
472
473 BLI_addtail(lb1, slnew);
474
475 region_copylist(st, &slnew->regionbase, &sl->regionbase);
476 }
477 }
478 }
479
480 /* facility to set locks for drawing to survive (render) threads accessing drawing data */
481 /* lock can become bitflag too */
482 /* should be replaced in future by better local data handling for threads */
BKE_spacedata_draw_locks(int set)483 void BKE_spacedata_draw_locks(int set)
484 {
485 SpaceType *st;
486
487 for (st = spacetypes.first; st; st = st->next) {
488 ARegionType *art;
489
490 for (art = st->regiontypes.first; art; art = art->next) {
491 if (set) {
492 art->do_lock = art->lock;
493 }
494 else {
495 art->do_lock = false;
496 }
497 }
498 }
499 }
500
501 /**
502 * Version of #BKE_area_find_region_type that also works if \a slink
503 * is not the active space of \a area.
504 */
BKE_spacedata_find_region_type(const SpaceLink * slink,const ScrArea * area,int region_type)505 ARegion *BKE_spacedata_find_region_type(const SpaceLink *slink,
506 const ScrArea *area,
507 int region_type)
508 {
509 const bool is_slink_active = slink == area->spacedata.first;
510 const ListBase *regionbase = (is_slink_active) ? &area->regionbase : &slink->regionbase;
511 ARegion *region = NULL;
512
513 BLI_assert(BLI_findindex(&area->spacedata, slink) != -1);
514 for (region = regionbase->first; region; region = region->next) {
515 if (region->regiontype == region_type) {
516 break;
517 }
518 }
519
520 /* Should really unit test this instead. */
521 BLI_assert(!is_slink_active || region == BKE_area_find_region_type(area, region_type));
522
523 return region;
524 }
525
526 static void (*spacedata_id_remap_cb)(struct ScrArea *area,
527 struct SpaceLink *sl,
528 ID *old_id,
529 ID *new_id) = NULL;
530
BKE_spacedata_callback_id_remap_set(void (* func)(ScrArea * area,SpaceLink * sl,ID *,ID *))531 void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *area, SpaceLink *sl, ID *, ID *))
532 {
533 spacedata_id_remap_cb = func;
534 }
535
536 /* UNUSED!!! */
BKE_spacedata_id_unref(struct ScrArea * area,struct SpaceLink * sl,struct ID * id)537 void BKE_spacedata_id_unref(struct ScrArea *area, struct SpaceLink *sl, struct ID *id)
538 {
539 if (spacedata_id_remap_cb) {
540 spacedata_id_remap_cb(area, sl, id, NULL);
541 }
542 }
543
544 /**
545 * Avoid bad-level calls to #WM_gizmomap_tag_refresh.
546 */
547 static void (*region_refresh_tag_gizmomap_callback)(struct wmGizmoMap *) = NULL;
548
BKE_region_callback_refresh_tag_gizmomap_set(void (* callback)(struct wmGizmoMap *))549 void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizmoMap *))
550 {
551 region_refresh_tag_gizmomap_callback = callback;
552 }
553
BKE_screen_gizmo_tag_refresh(struct bScreen * screen)554 void BKE_screen_gizmo_tag_refresh(struct bScreen *screen)
555 {
556 if (region_refresh_tag_gizmomap_callback == NULL) {
557 return;
558 }
559
560 ScrArea *area;
561 ARegion *region;
562 for (area = screen->areabase.first; area; area = area->next) {
563 for (region = area->regionbase.first; region; region = region->next) {
564 if (region->gizmo_map != NULL) {
565 region_refresh_tag_gizmomap_callback(region->gizmo_map);
566 }
567 }
568 }
569 }
570
571 /**
572 * Avoid bad-level calls to #WM_gizmomap_delete.
573 */
574 static void (*region_free_gizmomap_callback)(struct wmGizmoMap *) = NULL;
575
BKE_region_callback_free_gizmomap_set(void (* callback)(struct wmGizmoMap *))576 void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *))
577 {
578 region_free_gizmomap_callback = callback;
579 }
580
area_region_panels_free_recursive(Panel * panel)581 static void area_region_panels_free_recursive(Panel *panel)
582 {
583 MEM_SAFE_FREE(panel->activedata);
584
585 LISTBASE_FOREACH_MUTABLE (Panel *, child_panel, &panel->children) {
586 area_region_panels_free_recursive(child_panel);
587 }
588
589 MEM_freeN(panel);
590 }
591
BKE_area_region_panels_free(ListBase * panels)592 void BKE_area_region_panels_free(ListBase *panels)
593 {
594 LISTBASE_FOREACH_MUTABLE (Panel *, panel, panels) {
595 /* Free custom data just for parent panels to avoid a double free. */
596 MEM_SAFE_FREE(panel->runtime.custom_data_ptr);
597 area_region_panels_free_recursive(panel);
598 }
599 BLI_listbase_clear(panels);
600 }
601
602 /* not region itself */
BKE_area_region_free(SpaceType * st,ARegion * region)603 void BKE_area_region_free(SpaceType *st, ARegion *region)
604 {
605 uiList *uilst;
606
607 if (st) {
608 ARegionType *art = BKE_regiontype_from_id(st, region->regiontype);
609
610 if (art && art->free) {
611 art->free(region);
612 }
613
614 if (region->regiondata) {
615 printf("regiondata free error\n");
616 }
617 }
618 else if (region->type && region->type->free) {
619 region->type->free(region);
620 }
621
622 BKE_area_region_panels_free(®ion->panels);
623
624 for (uilst = region->ui_lists.first; uilst; uilst = uilst->next) {
625 if (uilst->dyn_data) {
626 uiListDyn *dyn_data = uilst->dyn_data;
627 if (dyn_data->items_filter_flags) {
628 MEM_freeN(dyn_data->items_filter_flags);
629 }
630 if (dyn_data->items_filter_neworder) {
631 MEM_freeN(dyn_data->items_filter_neworder);
632 }
633 MEM_freeN(dyn_data);
634 }
635 if (uilst->properties) {
636 IDP_FreeProperty(uilst->properties);
637 }
638 }
639
640 if (region->gizmo_map != NULL) {
641 region_free_gizmomap_callback(region->gizmo_map);
642 }
643
644 BLI_freelistN(®ion->ui_lists);
645 BLI_freelistN(®ion->ui_previews);
646 BLI_freelistN(®ion->panels_category);
647 BLI_freelistN(®ion->panels_category_active);
648 }
649
650 /* not area itself */
BKE_screen_area_free(ScrArea * area)651 void BKE_screen_area_free(ScrArea *area)
652 {
653 SpaceType *st = BKE_spacetype_from_id(area->spacetype);
654 ARegion *region;
655
656 for (region = area->regionbase.first; region; region = region->next) {
657 BKE_area_region_free(st, region);
658 }
659
660 MEM_SAFE_FREE(area->global);
661 BLI_freelistN(&area->regionbase);
662
663 BKE_spacedata_freelist(&area->spacedata);
664
665 BLI_freelistN(&area->actionzones);
666 }
667
BKE_screen_area_map_free(ScrAreaMap * area_map)668 void BKE_screen_area_map_free(ScrAreaMap *area_map)
669 {
670 for (ScrArea *area = area_map->areabase.first, *area_next; area; area = area_next) {
671 area_next = area->next;
672 BKE_screen_area_free(area);
673 }
674
675 BLI_freelistN(&area_map->vertbase);
676 BLI_freelistN(&area_map->edgebase);
677 BLI_freelistN(&area_map->areabase);
678 }
679
680 /** Free (or release) any data used by this screen (does not free the screen itself). */
BKE_screen_free(bScreen * screen)681 void BKE_screen_free(bScreen *screen)
682 {
683 screen_free_data(&screen->id);
684 }
685
686 /* ***************** Screen edges & verts ***************** */
687
BKE_screen_find_edge(const bScreen * screen,ScrVert * v1,ScrVert * v2)688 ScrEdge *BKE_screen_find_edge(const bScreen *screen, ScrVert *v1, ScrVert *v2)
689 {
690 ScrEdge *se;
691
692 BKE_screen_sort_scrvert(&v1, &v2);
693 for (se = screen->edgebase.first; se; se = se->next) {
694 if (se->v1 == v1 && se->v2 == v2) {
695 return se;
696 }
697 }
698
699 return NULL;
700 }
701
BKE_screen_sort_scrvert(ScrVert ** v1,ScrVert ** v2)702 void BKE_screen_sort_scrvert(ScrVert **v1, ScrVert **v2)
703 {
704 ScrVert *tmp;
705
706 if (*v1 > *v2) {
707 tmp = *v1;
708 *v1 = *v2;
709 *v2 = tmp;
710 }
711 }
712
BKE_screen_remove_double_scrverts(bScreen * screen)713 void BKE_screen_remove_double_scrverts(bScreen *screen)
714 {
715 ScrVert *v1, *verg;
716 ScrEdge *se;
717 ScrArea *area;
718
719 verg = screen->vertbase.first;
720 while (verg) {
721 if (verg->newv == NULL) { /* !!! */
722 v1 = verg->next;
723 while (v1) {
724 if (v1->newv == NULL) { /* !?! */
725 if (v1->vec.x == verg->vec.x && v1->vec.y == verg->vec.y) {
726 /* printf("doublevert\n"); */
727 v1->newv = verg;
728 }
729 }
730 v1 = v1->next;
731 }
732 }
733 verg = verg->next;
734 }
735
736 /* replace pointers in edges and faces */
737 se = screen->edgebase.first;
738 while (se) {
739 if (se->v1->newv) {
740 se->v1 = se->v1->newv;
741 }
742 if (se->v2->newv) {
743 se->v2 = se->v2->newv;
744 }
745 /* edges changed: so.... */
746 BKE_screen_sort_scrvert(&(se->v1), &(se->v2));
747 se = se->next;
748 }
749 area = screen->areabase.first;
750 while (area) {
751 if (area->v1->newv) {
752 area->v1 = area->v1->newv;
753 }
754 if (area->v2->newv) {
755 area->v2 = area->v2->newv;
756 }
757 if (area->v3->newv) {
758 area->v3 = area->v3->newv;
759 }
760 if (area->v4->newv) {
761 area->v4 = area->v4->newv;
762 }
763 area = area->next;
764 }
765
766 /* remove */
767 verg = screen->vertbase.first;
768 while (verg) {
769 v1 = verg->next;
770 if (verg->newv) {
771 BLI_remlink(&screen->vertbase, verg);
772 MEM_freeN(verg);
773 }
774 verg = v1;
775 }
776 }
777
BKE_screen_remove_double_scredges(bScreen * screen)778 void BKE_screen_remove_double_scredges(bScreen *screen)
779 {
780 ScrEdge *verg, *se, *sn;
781
782 /* compare */
783 verg = screen->edgebase.first;
784 while (verg) {
785 se = verg->next;
786 while (se) {
787 sn = se->next;
788 if (verg->v1 == se->v1 && verg->v2 == se->v2) {
789 BLI_remlink(&screen->edgebase, se);
790 MEM_freeN(se);
791 }
792 se = sn;
793 }
794 verg = verg->next;
795 }
796 }
797
BKE_screen_remove_unused_scredges(bScreen * screen)798 void BKE_screen_remove_unused_scredges(bScreen *screen)
799 {
800 ScrEdge *se, *sen;
801 ScrArea *area;
802 int a = 0;
803
804 /* sets flags when edge is used in area */
805 area = screen->areabase.first;
806 while (area) {
807 se = BKE_screen_find_edge(screen, area->v1, area->v2);
808 if (se == NULL) {
809 printf("error: area %d edge 1 doesn't exist\n", a);
810 }
811 else {
812 se->flag = 1;
813 }
814 se = BKE_screen_find_edge(screen, area->v2, area->v3);
815 if (se == NULL) {
816 printf("error: area %d edge 2 doesn't exist\n", a);
817 }
818 else {
819 se->flag = 1;
820 }
821 se = BKE_screen_find_edge(screen, area->v3, area->v4);
822 if (se == NULL) {
823 printf("error: area %d edge 3 doesn't exist\n", a);
824 }
825 else {
826 se->flag = 1;
827 }
828 se = BKE_screen_find_edge(screen, area->v4, area->v1);
829 if (se == NULL) {
830 printf("error: area %d edge 4 doesn't exist\n", a);
831 }
832 else {
833 se->flag = 1;
834 }
835 area = area->next;
836 a++;
837 }
838 se = screen->edgebase.first;
839 while (se) {
840 sen = se->next;
841 if (se->flag == 0) {
842 BLI_remlink(&screen->edgebase, se);
843 MEM_freeN(se);
844 }
845 else {
846 se->flag = 0;
847 }
848 se = sen;
849 }
850 }
851
BKE_screen_remove_unused_scrverts(bScreen * screen)852 void BKE_screen_remove_unused_scrverts(bScreen *screen)
853 {
854 ScrVert *sv, *svn;
855 ScrEdge *se;
856
857 /* we assume edges are ok */
858
859 se = screen->edgebase.first;
860 while (se) {
861 se->v1->flag = 1;
862 se->v2->flag = 1;
863 se = se->next;
864 }
865
866 sv = screen->vertbase.first;
867 while (sv) {
868 svn = sv->next;
869 if (sv->flag == 0) {
870 BLI_remlink(&screen->vertbase, sv);
871 MEM_freeN(sv);
872 }
873 else {
874 sv->flag = 0;
875 }
876 sv = svn;
877 }
878 }
879
880 /* ***************** Utilities ********************** */
881
882 /**
883 * Find a region of type \a region_type in the currently active space of \a area.
884 *
885 * \note This does _not_ work if the region to look up is not in the active
886 * space. Use #BKE_spacedata_find_region_type if that may be the case.
887 */
BKE_area_find_region_type(const ScrArea * area,int region_type)888 ARegion *BKE_area_find_region_type(const ScrArea *area, int region_type)
889 {
890 if (area) {
891 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
892 if (region->regiontype == region_type) {
893 return region;
894 }
895 }
896 }
897
898 return NULL;
899 }
900
BKE_area_find_region_active_win(ScrArea * area)901 ARegion *BKE_area_find_region_active_win(ScrArea *area)
902 {
903 if (area) {
904 ARegion *region = BLI_findlink(&area->regionbase, area->region_active_win);
905 if (region && (region->regiontype == RGN_TYPE_WINDOW)) {
906 return region;
907 }
908
909 /* fallback to any */
910 return BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
911 }
912 return NULL;
913 }
914
BKE_area_find_region_xy(ScrArea * area,const int regiontype,int x,int y)915 ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int y)
916 {
917 ARegion *region_found = NULL;
918 if (area) {
919 ARegion *region;
920 for (region = area->regionbase.first; region; region = region->next) {
921 if ((regiontype == RGN_TYPE_ANY) || (region->regiontype == regiontype)) {
922 if (BLI_rcti_isect_pt(®ion->winrct, x, y)) {
923 region_found = region;
924 break;
925 }
926 }
927 }
928 }
929 return region_found;
930 }
931
932 /**
933 * \note This is only for screen level regions (typically menus/popups).
934 */
BKE_screen_find_region_xy(bScreen * screen,const int regiontype,int x,int y)935 ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, int x, int y)
936 {
937 ARegion *region_found = NULL;
938 LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
939 if ((regiontype == RGN_TYPE_ANY) || (region->regiontype == regiontype)) {
940 if (BLI_rcti_isect_pt(®ion->winrct, x, y)) {
941 region_found = region;
942 break;
943 }
944 }
945 }
946 return region_found;
947 }
948
949 /**
950 * \note Ideally we can get the area from the context,
951 * there are a few places however where this isn't practical.
952 */
BKE_screen_find_area_from_space(struct bScreen * screen,SpaceLink * sl)953 ScrArea *BKE_screen_find_area_from_space(struct bScreen *screen, SpaceLink *sl)
954 {
955 ScrArea *area;
956
957 for (area = screen->areabase.first; area; area = area->next) {
958 if (BLI_findindex(&area->spacedata, sl) != -1) {
959 break;
960 }
961 }
962
963 return area;
964 }
965
966 /**
967 * \note Using this function is generally a last resort, you really want to be
968 * using the context when you can - campbell
969 */
BKE_screen_find_big_area(bScreen * screen,const int spacetype,const short min)970 ScrArea *BKE_screen_find_big_area(bScreen *screen, const int spacetype, const short min)
971 {
972 ScrArea *area, *big = NULL;
973 int size, maxsize = 0;
974
975 for (area = screen->areabase.first; area; area = area->next) {
976 if ((spacetype == SPACE_TYPE_ANY) || (area->spacetype == spacetype)) {
977 if (min <= area->winx && min <= area->winy) {
978 size = area->winx * area->winy;
979 if (size > maxsize) {
980 maxsize = size;
981 big = area;
982 }
983 }
984 }
985 }
986
987 return big;
988 }
989
BKE_screen_area_map_find_area_xy(const ScrAreaMap * areamap,const int spacetype,int x,int y)990 ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap,
991 const int spacetype,
992 int x,
993 int y)
994 {
995 LISTBASE_FOREACH (ScrArea *, area, &areamap->areabase) {
996 if (BLI_rcti_isect_pt(&area->totrct, x, y)) {
997 if ((spacetype == SPACE_TYPE_ANY) || (area->spacetype == spacetype)) {
998 return area;
999 }
1000 break;
1001 }
1002 }
1003 return NULL;
1004 }
BKE_screen_find_area_xy(bScreen * screen,const int spacetype,int x,int y)1005 ScrArea *BKE_screen_find_area_xy(bScreen *screen, const int spacetype, int x, int y)
1006 {
1007 return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(screen), spacetype, x, y);
1008 }
1009
BKE_screen_view3d_sync(View3D * v3d,struct Scene * scene)1010 void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
1011 {
1012 if (v3d->scenelock && v3d->localvd == NULL) {
1013 v3d->camera = scene->camera;
1014
1015 if (v3d->camera == NULL) {
1016 ARegion *region;
1017
1018 for (region = v3d->regionbase.first; region; region = region->next) {
1019 if (region->regiontype == RGN_TYPE_WINDOW) {
1020 RegionView3D *rv3d = region->regiondata;
1021 if (rv3d->persp == RV3D_CAMOB) {
1022 rv3d->persp = RV3D_PERSP;
1023 }
1024 }
1025 }
1026 }
1027 }
1028 }
1029
BKE_screen_view3d_scene_sync(bScreen * screen,Scene * scene)1030 void BKE_screen_view3d_scene_sync(bScreen *screen, Scene *scene)
1031 {
1032 /* are there cameras in the views that are not in the scene? */
1033 ScrArea *area;
1034 for (area = screen->areabase.first; area; area = area->next) {
1035 SpaceLink *sl;
1036 for (sl = area->spacedata.first; sl; sl = sl->next) {
1037 if (sl->spacetype == SPACE_VIEW3D) {
1038 View3D *v3d = (View3D *)sl;
1039 BKE_screen_view3d_sync(v3d, scene);
1040 }
1041 }
1042 }
1043 }
1044
BKE_screen_view3d_shading_init(View3DShading * shading)1045 void BKE_screen_view3d_shading_init(View3DShading *shading)
1046 {
1047 const View3DShading *shading_default = DNA_struct_default_get(View3DShading);
1048 memcpy(shading, shading_default, sizeof(*shading));
1049 }
1050
BKE_screen_find_main_region_at_xy(bScreen * screen,const int space_type,const int x,const int y)1051 ARegion *BKE_screen_find_main_region_at_xy(bScreen *screen,
1052 const int space_type,
1053 const int x,
1054 const int y)
1055 {
1056 ScrArea *area = BKE_screen_find_area_xy(screen, space_type, x, y);
1057 if (!area) {
1058 return NULL;
1059 }
1060 return BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, x, y);
1061 }
1062
1063 /* magic zoom calculation, no idea what
1064 * it signifies, if you find out, tell me! -zr
1065 */
1066
1067 /* simple, its magic dude!
1068 * well, to be honest, this gives a natural feeling zooming
1069 * with multiple keypad presses (ton)
1070 */
BKE_screen_view3d_zoom_to_fac(float camzoom)1071 float BKE_screen_view3d_zoom_to_fac(float camzoom)
1072 {
1073 return powf(((float)M_SQRT2 + camzoom / 50.0f), 2.0f) / 4.0f;
1074 }
1075
BKE_screen_view3d_zoom_from_fac(float zoomfac)1076 float BKE_screen_view3d_zoom_from_fac(float zoomfac)
1077 {
1078 return ((sqrtf(4.0f * zoomfac) - (float)M_SQRT2) * 50.0f);
1079 }
1080
BKE_screen_is_fullscreen_area(const bScreen * screen)1081 bool BKE_screen_is_fullscreen_area(const bScreen *screen)
1082 {
1083 return ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL);
1084 }
1085
BKE_screen_is_used(const bScreen * screen)1086 bool BKE_screen_is_used(const bScreen *screen)
1087 {
1088 return (screen->winid != 0);
1089 }
1090
BKE_screen_header_alignment_reset(bScreen * screen)1091 void BKE_screen_header_alignment_reset(bScreen *screen)
1092 {
1093 int alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
1094 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1095 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1096 if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
1097 if (ELEM(area->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
1098 region->alignment = RGN_ALIGN_TOP;
1099 continue;
1100 }
1101 region->alignment = alignment;
1102 }
1103 if (region->regiontype == RGN_TYPE_FOOTER) {
1104 if (ELEM(area->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
1105 region->alignment = RGN_ALIGN_BOTTOM;
1106 continue;
1107 }
1108 region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM;
1109 }
1110 }
1111 }
1112 screen->do_refresh = true;
1113 }
1114