2.5/Posemode:
[blender-staging.git] / source / blender / blenkernel / intern / context.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) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation (2008).
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include "MEM_guardedalloc.h"
29
30 #include "DNA_ID.h"
31 #include "DNA_listBase.h"
32 #include "DNA_scene_types.h"
33 #include "DNA_screen_types.h"
34 #include "DNA_space_types.h"
35 #include "DNA_view3d_types.h"
36 #include "DNA_windowmanager_types.h"
37 #include "DNA_object_types.h"
38
39 #include "RNA_access.h"
40
41 #include "BLI_listbase.h"
42 #include "BLI_string.h"
43
44 #include "BKE_context.h"
45 #include "BKE_main.h"
46 #include "BKE_screen.h"
47 #include "BKE_global.h"
48
49 #include <string.h>
50
51 /* struct */
52
53 struct bContext {
54         int thread;
55
56         /* windowmanager context */
57         struct {
58                 struct wmWindowManager *manager;
59                 struct wmWindow *window;
60                 struct bScreen *screen;
61                 struct ScrArea *area;
62                 struct ARegion *region;
63                 struct ARegion *menu;
64                 struct bContextStore *store;
65         } wm;
66         
67         /* data context */
68         struct {
69                 struct Main *main;
70                 struct Scene *scene;
71
72                 int recursion;
73                 int py_init; /* true if python is initialized */
74         } data;
75         
76         /* data evaluation */
77         struct {
78                 int render;
79         } eval;
80 };
81
82 /* context */
83
84 bContext *CTX_create()
85 {
86         bContext *C;
87         
88         C= MEM_callocN(sizeof(bContext), "bContext");
89
90         return C;
91 }
92
93 bContext *CTX_copy(const bContext *C)
94 {
95         bContext *newC= MEM_dupallocN((void*)C);
96
97         return newC;
98 }
99
100 void CTX_free(bContext *C)
101 {
102         MEM_freeN(C);
103 }
104
105 /* store */
106
107 bContextStore *CTX_store_add(ListBase *contexts, char *name, PointerRNA *ptr)
108 {
109         bContextStoreEntry *entry;
110         bContextStore *ctx, *lastctx;
111
112         /* ensure we have a context to put the entry in, if it was already used
113          * we have to copy the context to ensure */
114         ctx= contexts->last;
115
116         if(!ctx || ctx->used) {
117                 if(ctx) {
118                         lastctx= ctx;
119                         ctx= MEM_dupallocN(lastctx);
120                         BLI_duplicatelist(&ctx->entries, &lastctx->entries);
121                 }
122                 else
123                         ctx= MEM_callocN(sizeof(bContextStore), "bContextStore");
124
125                 BLI_addtail(contexts, ctx);
126         }
127
128         entry= MEM_callocN(sizeof(bContextStoreEntry), "bContextStoreEntry");
129         BLI_strncpy(entry->name, name, sizeof(entry->name));
130         entry->ptr= *ptr;
131
132         BLI_addtail(&ctx->entries, entry);
133
134         return ctx;
135 }
136
137 void CTX_store_set(bContext *C, bContextStore *store)
138 {
139         C->wm.store= store;
140 }
141
142 bContextStore *CTX_store_copy(bContextStore *store)
143 {
144         bContextStore *ctx;
145
146         ctx= MEM_dupallocN(store);
147         BLI_duplicatelist(&ctx->entries, &store->entries);
148
149         return ctx;
150 }
151
152 void CTX_store_free(bContextStore *store)
153 {
154         BLI_freelistN(&store->entries);
155         MEM_freeN(store);
156 }
157
158 void CTX_store_free_list(ListBase *contexts)
159 {
160         bContextStore *ctx;
161
162         while((ctx= contexts->first)) {
163                 BLI_remlink(contexts, ctx);
164                 CTX_store_free(ctx);
165         }
166 }
167
168 /* is python initialied? */
169 int CTX_py_init_get(bContext *C)
170 {
171         return C->data.py_init;
172 }
173 void CTX_py_init_set(bContext *C, int value)
174 {
175         C->data.py_init= value;
176 }
177
178 /* window manager context */
179
180 wmWindowManager *CTX_wm_manager(const bContext *C)
181 {
182         return C->wm.manager;
183 }
184
185 wmWindow *CTX_wm_window(const bContext *C)
186 {
187         return C->wm.window;
188 }
189
190 bScreen *CTX_wm_screen(const bContext *C)
191 {
192         return C->wm.screen;
193 }
194
195 ScrArea *CTX_wm_area(const bContext *C)
196 {
197         return C->wm.area;
198 }
199
200 SpaceLink *CTX_wm_space_data(const bContext *C)
201 {
202         return (C->wm.area)? C->wm.area->spacedata.first: NULL;
203 }
204
205 ARegion *CTX_wm_region(const bContext *C)
206 {
207         return C->wm.region;
208 }
209
210 void *CTX_wm_region_data(const bContext *C)
211 {
212         return (C->wm.region)? C->wm.region->regiondata: NULL;
213 }
214
215 struct ARegion *CTX_wm_menu(const bContext *C)
216 {
217         return C->wm.menu;
218 }
219
220 struct ReportList *CTX_wm_reports(const bContext *C)
221 {
222         if (C->wm.manager)
223                 return &(C->wm.manager->reports);
224
225         return NULL;
226 }
227
228 View3D *CTX_wm_view3d(const bContext *C)
229 {
230         if(C->wm.area && C->wm.area->spacetype==SPACE_VIEW3D)
231                 return C->wm.area->spacedata.first;
232         return NULL;
233 }
234
235 RegionView3D *CTX_wm_region_view3d(const bContext *C)
236 {
237         if(C->wm.area && C->wm.area->spacetype==SPACE_VIEW3D)
238                 if(C->wm.region)
239                         return C->wm.region->regiondata;
240         return NULL;
241 }
242
243 struct SpaceText *CTX_wm_space_text(const bContext *C)
244 {
245         if(C->wm.area && C->wm.area->spacetype==SPACE_TEXT)
246                 return C->wm.area->spacedata.first;
247         return NULL;
248 }
249
250 struct SpaceConsole *CTX_wm_space_console(const bContext *C)
251 {
252         if(C->wm.area && C->wm.area->spacetype==SPACE_CONSOLE)
253                 return C->wm.area->spacedata.first;
254         return NULL;
255 }
256
257 struct SpaceImage *CTX_wm_space_image(const bContext *C)
258 {
259         if(C->wm.area && C->wm.area->spacetype==SPACE_IMAGE)
260                 return C->wm.area->spacedata.first;
261         return NULL;
262 }
263
264 struct SpaceButs *CTX_wm_space_buts(const bContext *C)
265 {
266         if(C->wm.area && C->wm.area->spacetype==SPACE_BUTS)
267                 return C->wm.area->spacedata.first;
268         return NULL;
269 }
270
271 struct SpaceFile *CTX_wm_space_file(const bContext *C)
272 {
273         if(C->wm.area && C->wm.area->spacetype==SPACE_FILE)
274                 return C->wm.area->spacedata.first;
275         return NULL;
276 }
277
278 struct SpaceSeq *CTX_wm_space_seq(const bContext *C)
279 {
280         if(C->wm.area && C->wm.area->spacetype==SPACE_SEQ)
281                 return C->wm.area->spacedata.first;
282         return NULL;
283 }
284
285 struct SpaceOops *CTX_wm_space_outliner(const bContext *C)
286 {
287         if(C->wm.area && C->wm.area->spacetype==SPACE_OUTLINER)
288                 return C->wm.area->spacedata.first;
289         return NULL;
290 }
291
292 struct SpaceNla *CTX_wm_space_nla(const bContext *C)
293 {
294         if(C->wm.area && C->wm.area->spacetype==SPACE_NLA)
295                 return C->wm.area->spacedata.first;
296         return NULL;
297 }
298
299 struct SpaceTime *CTX_wm_space_time(const bContext *C)
300 {
301         if(C->wm.area && C->wm.area->spacetype==SPACE_TIME)
302                 return C->wm.area->spacedata.first;
303         return NULL;
304 }
305
306 struct SpaceNode *CTX_wm_space_node(const bContext *C)
307 {
308         if(C->wm.area && C->wm.area->spacetype==SPACE_NODE)
309                 return C->wm.area->spacedata.first;
310         return NULL;
311 }
312
313 struct SpaceLogic *CTX_wm_space_logic(const bContext *C)
314 {
315         if(C->wm.area && C->wm.area->spacetype==SPACE_LOGIC)
316                 return C->wm.area->spacedata.first;
317         return NULL;
318 }
319
320 struct SpaceIpo *CTX_wm_space_graph(const bContext *C)
321 {
322         if(C->wm.area && C->wm.area->spacetype==SPACE_IPO)
323                 return C->wm.area->spacedata.first;
324         return NULL;
325 }
326
327 struct SpaceAction *CTX_wm_space_action(const bContext *C)
328 {
329         if(C->wm.area && C->wm.area->spacetype==SPACE_ACTION)
330                 return C->wm.area->spacedata.first;
331         return NULL;
332 }
333
334 struct SpaceInfo *CTX_wm_space_info(const bContext *C)
335 {
336         if(C->wm.area && C->wm.area->spacetype==SPACE_INFO)
337                 return C->wm.area->spacedata.first;
338         return NULL;
339 }
340
341 void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
342 {
343         C->wm.manager= wm;
344         C->wm.window= NULL;
345         C->wm.screen= NULL;
346         C->wm.area= NULL;
347         C->wm.region= NULL;
348 }
349
350 void CTX_wm_window_set(bContext *C, wmWindow *win)
351 {
352         C->wm.window= win;
353         C->wm.screen= (win)? win->screen: NULL;
354         C->data.scene= (C->wm.screen)? C->wm.screen->scene: NULL;
355         C->wm.area= NULL;
356         C->wm.region= NULL;
357 }
358
359 void CTX_wm_screen_set(bContext *C, bScreen *screen)
360 {
361         C->wm.screen= screen;
362         C->data.scene= (C->wm.screen)? C->wm.screen->scene: NULL;
363         C->wm.area= NULL;
364         C->wm.region= NULL;
365 }
366
367 void CTX_wm_area_set(bContext *C, ScrArea *area)
368 {
369         C->wm.area= area;
370         C->wm.region= NULL;
371 }
372
373 void CTX_wm_region_set(bContext *C, ARegion *region)
374 {
375         C->wm.region= region;
376 }
377
378 void CTX_wm_menu_set(bContext *C, ARegion *menu)
379 {
380         C->wm.menu= menu;
381 }
382
383 /* data context utility functions */
384
385 struct bContextDataResult {
386         PointerRNA ptr;
387         ListBase list;
388         const char **dir;
389 };
390
391 static int ctx_data_get(bContext *C, const char *member, bContextDataResult *result)
392 {
393         int done= 0, recursion= C->data.recursion;
394
395         memset(result, 0, sizeof(bContextDataResult));
396
397         /* we check recursion to ensure that we do not get infinite
398          * loops requesting data from ourselfs in a context callback */
399         if(!done && recursion < 1 && C->wm.store) {
400                 bContextStoreEntry *entry;
401
402                 C->data.recursion= 1;
403
404                 for(entry=C->wm.store->entries.first; entry; entry=entry->next) {
405                         if(strcmp(entry->name, member) == 0) {
406                                 result->ptr= entry->ptr;
407                                 done= 1;
408                         }
409                 }
410         }
411         if(!done && recursion < 2 && C->wm.region) {
412                 C->data.recursion= 2;
413                 if(C->wm.region->type && C->wm.region->type->context)
414                         done= C->wm.region->type->context(C, member, result);
415         }
416         if(!done && recursion < 3 && C->wm.area) {
417                 C->data.recursion= 3;
418                 if(C->wm.area->type && C->wm.area->type->context)
419                         done= C->wm.area->type->context(C, member, result);
420         }
421         if(!done && recursion < 4 && C->wm.screen) {
422                 bContextDataCallback cb= C->wm.screen->context;
423                 C->data.recursion= 4;
424                 if(cb)
425                         done= cb(C, member, result);
426         }
427
428         C->data.recursion= recursion;
429
430         return done;
431 }
432
433 static void *ctx_data_pointer_get(const bContext *C, const char *member)
434 {
435         bContextDataResult result;
436
437         if(ctx_data_get((bContext*)C, member, &result))
438                 return result.ptr.data;
439
440         return NULL;
441 }
442
443 static int ctx_data_pointer_verify(const bContext *C, const char *member, void **pointer)
444 {
445         bContextDataResult result;
446
447         if(ctx_data_get((bContext*)C, member, &result)) {
448                 *pointer= result.ptr.data;
449                 return 1;
450         }
451         else {
452                 *pointer= NULL;
453                 return 0;
454         }
455 }
456
457 static int ctx_data_collection_get(const bContext *C, const char *member, ListBase *list)
458 {
459         bContextDataResult result;
460
461         if(ctx_data_get((bContext*)C, member, &result)) {
462                 *list= result.list;
463                 return 1;
464         }
465
466         list->first= NULL;
467         list->last= NULL;
468
469         return 0;
470 }
471
472 PointerRNA CTX_data_pointer_get(const bContext *C, const char *member)
473 {
474         bContextDataResult result;
475
476         if(ctx_data_get((bContext*)C, member, &result))
477                 return result.ptr;
478         else
479                 return PointerRNA_NULL;
480 }
481
482 PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
483 {
484         PointerRNA ptr = CTX_data_pointer_get(C, member);
485
486         if(ptr.data && RNA_struct_is_a(ptr.type, type))
487                 return ptr;
488         
489         return PointerRNA_NULL;
490 }
491
492 ListBase CTX_data_collection_get(const bContext *C, const char *member)
493 {
494         bContextDataResult result;
495
496         if(ctx_data_get((bContext*)C, member, &result)) {
497                 return result.list;
498         }
499         else {
500                 ListBase list;
501                 memset(&list, 0, sizeof(list));
502                 return list;
503         }
504 }
505
506 void CTX_data_get(const bContext *C, const char *member, PointerRNA *r_ptr, ListBase *r_lb)
507 {
508         bContextDataResult result;
509
510         if(ctx_data_get((bContext*)C, member, &result)) {
511                 *r_ptr= result.ptr;
512                 *r_lb= result.list;
513         }
514         else {
515                 memset(r_ptr, 0, sizeof(*r_ptr));
516                 memset(r_lb, 0, sizeof(*r_lb));
517         }
518 }
519
520 static void data_dir_add(ListBase *lb, const char *member)
521 {
522         LinkData *link;
523
524         if(strcmp(member, "scene") == 0) /* exception */
525                 return;
526
527         for(link=lb->first; link; link=link->next)
528                 if(strcmp(link->data, member) == 0)
529                         return;
530         
531         link= MEM_callocN(sizeof(LinkData), "LinkData");
532         link->data= (void*)member;
533         BLI_addtail(lb, link);
534 }
535
536 ListBase CTX_data_dir_get(const bContext *C)
537 {
538         bContextDataResult result;
539         ListBase lb;
540         int a;
541
542         memset(&lb, 0, sizeof(lb));
543
544         if(C->wm.store) {
545                 bContextStoreEntry *entry;
546
547                 for(entry=C->wm.store->entries.first; entry; entry=entry->next)
548                         data_dir_add(&lb, entry->name);
549         }
550         if(C->wm.region && C->wm.region->type && C->wm.region->type->context) {
551                 memset(&result, 0, sizeof(result));
552                 C->wm.region->type->context(C, "", &result);
553
554                 if(result.dir)
555                         for(a=0; result.dir[a]; a++)
556                                 data_dir_add(&lb, result.dir[a]);
557         }
558         if(C->wm.area && C->wm.area->type && C->wm.area->type->context) {
559                 memset(&result, 0, sizeof(result));
560                 C->wm.area->type->context(C, "", &result);
561
562                 if(result.dir)
563                         for(a=0; result.dir[a]; a++)
564                                 data_dir_add(&lb, result.dir[a]);
565         }
566         if(C->wm.screen && C->wm.screen->context) {
567                 bContextDataCallback cb= C->wm.screen->context;
568                 memset(&result, 0, sizeof(result));
569                 cb(C, "", &result);
570
571                 if(result.dir)
572                         for(a=0; result.dir[a]; a++)
573                                 data_dir_add(&lb, result.dir[a]);
574         }
575
576         return lb;
577 }
578
579 int CTX_data_equals(const char *member, const char *str)
580 {
581         return (strcmp(member, str) == 0);
582 }
583
584 int CTX_data_dir(const char *member)
585 {
586         return (strcmp(member, "") == 0);
587 }
588
589 void CTX_data_id_pointer_set(bContextDataResult *result, ID *id)
590 {
591         RNA_id_pointer_create(id, &result->ptr);
592 }
593
594 void CTX_data_pointer_set(bContextDataResult *result, ID *id, StructRNA *type, void *data)
595 {
596         RNA_pointer_create(id, type, data, &result->ptr);
597 }
598
599 void CTX_data_id_list_add(bContextDataResult *result, ID *id)
600 {
601         CollectionPointerLink *link;
602
603         link= MEM_callocN(sizeof(CollectionPointerLink), "CTX_data_id_list_add");
604         RNA_id_pointer_create(id, &link->ptr);
605
606         BLI_addtail(&result->list, link);
607 }
608
609 void CTX_data_list_add(bContextDataResult *result, ID *id, StructRNA *type, void *data)
610 {
611         CollectionPointerLink *link;
612
613         link= MEM_callocN(sizeof(CollectionPointerLink), "CTX_data_list_add");
614         RNA_pointer_create(id, type, data, &link->ptr);
615
616         BLI_addtail(&result->list, link);
617 }
618
619 int ctx_data_list_count(const bContext *C, int (*func)(const bContext*, ListBase*))
620 {
621         ListBase list;
622
623         if(func(C, &list)) {
624                 int tot= BLI_countlist(&list);
625                 BLI_freelistN(&list);
626                 return tot;
627         }
628         else
629                 return 0;
630 }
631
632 void CTX_data_dir_set(bContextDataResult *result, const char **dir)
633 {
634         result->dir= dir;
635 }
636
637 /* data context */
638
639 Main *CTX_data_main(const bContext *C)
640 {
641         Main *bmain;
642
643         if(ctx_data_pointer_verify(C, "main", (void*)&bmain))
644                 return bmain;
645         else
646                 return C->data.main;
647 }
648
649 void CTX_data_main_set(bContext *C, Main *bmain)
650 {
651         C->data.main= bmain;
652 }
653
654 Scene *CTX_data_scene(const bContext *C)
655 {
656         Scene *scene;
657
658         if(ctx_data_pointer_verify(C, "scene", (void*)&scene))
659                 return scene;
660         else
661                 return C->data.scene;
662 }
663
664 char *CTX_data_mode_string(const bContext *C)
665 {
666         Object *obedit= CTX_data_edit_object(C);
667
668         if(obedit) {
669                 switch(obedit->type) {
670                         case OB_MESH:
671                                 return "mesh_edit";
672                         case OB_CURVE:
673                                 return "curve_edit";
674                         case OB_SURF:
675                                 return "surface_edit";
676                         case OB_FONT:
677                                 return "text_edit";
678                         case OB_ARMATURE:
679                                 return "armature_edit";
680                         case OB_MBALL:
681                                 return "mball_edit";
682                         case OB_LATTICE:
683                                 return "lattice_edit";
684                 }
685         }
686         else {
687                 Object *ob = CTX_data_active_object(C);
688                 
689                 if(ob) {
690                         if(ob->mode & OB_MODE_POSE) return "posemode";
691                         else if(ob->mode & OB_MODE_SCULPT)  return "sculpt_mode";
692                         else if(ob->mode & OB_MODE_WEIGHT_PAINT) return "weightpaint";
693                         else if(ob->mode & OB_MODE_VERTEX_PAINT) return "vertexpaint";
694                         else if(ob->mode & OB_MODE_TEXTURE_PAINT) return "texturepaint";
695                         else if(ob->mode & OB_MODE_PARTICLE_EDIT) return "particlemode";
696                 }
697         }
698         
699         return "objectmode";
700 }
701
702 void CTX_data_scene_set(bContext *C, Scene *scene)
703 {
704         C->data.scene= scene;
705 }
706
707 ToolSettings *CTX_data_tool_settings(const bContext *C)
708 {
709         Scene *scene = CTX_data_scene(C);
710
711         if(scene)
712                 return scene->toolsettings;
713         else
714                 return NULL;
715 }
716
717 int CTX_data_selected_nodes(const bContext *C, ListBase *list)
718 {
719         return ctx_data_collection_get(C, "selected_nodes", list);
720 }
721
722 int CTX_data_selected_editable_objects(const bContext *C, ListBase *list)
723 {
724         return ctx_data_collection_get(C, "selected_editable_objects", list);
725 }
726
727 int CTX_data_selected_editable_bases(const bContext *C, ListBase *list)
728 {
729         return ctx_data_collection_get(C, "selected_editable_bases", list);
730 }
731
732 int CTX_data_selected_objects(const bContext *C, ListBase *list)
733 {
734         return ctx_data_collection_get(C, "selected_objects", list);
735 }
736
737 int CTX_data_selected_bases(const bContext *C, ListBase *list)
738 {
739         return ctx_data_collection_get(C, "selected_bases", list);
740 }
741
742 int CTX_data_visible_objects(const bContext *C, ListBase *list)
743 {
744         return ctx_data_collection_get(C, "visible_objects", list);
745 }
746
747 int CTX_data_visible_bases(const bContext *C, ListBase *list)
748 {
749         return ctx_data_collection_get(C, "visible_bases", list);
750 }
751
752 int CTX_data_selectable_objects(const bContext *C, ListBase *list)
753 {
754         return ctx_data_collection_get(C, "selectable_objects", list);
755 }
756
757 int CTX_data_selectable_bases(const bContext *C, ListBase *list)
758 {
759         return ctx_data_collection_get(C, "selectable_bases", list);
760 }
761
762 struct Object *CTX_data_active_object(const bContext *C)
763 {
764         return ctx_data_pointer_get(C, "active_object");
765 }
766
767 struct Base *CTX_data_active_base(const bContext *C)
768 {
769         return ctx_data_pointer_get(C, "active_base");
770 }
771
772 struct Object *CTX_data_edit_object(const bContext *C)
773 {
774         return ctx_data_pointer_get(C, "edit_object");
775 }
776
777 struct Image *CTX_data_edit_image(const bContext *C)
778 {
779         return ctx_data_pointer_get(C, "edit_image");
780 }
781
782 struct Text *CTX_data_edit_text(const bContext *C)
783 {
784         return ctx_data_pointer_get(C, "edit_text");
785 }
786
787 struct EditBone *CTX_data_active_bone(const bContext *C)
788 {
789         return ctx_data_pointer_get(C, "active_bone");
790 }
791
792 int CTX_data_selected_bones(const bContext *C, ListBase *list)
793 {
794         return ctx_data_collection_get(C, "selected_bones", list);
795 }
796
797 int CTX_data_selected_editable_bones(const bContext *C, ListBase *list)
798 {
799         return ctx_data_collection_get(C, "selected_editable_bones", list);
800 }
801
802 int CTX_data_visible_bones(const bContext *C, ListBase *list)
803 {
804         return ctx_data_collection_get(C, "visible_bones", list);
805 }
806
807 int CTX_data_editable_bones(const bContext *C, ListBase *list)
808 {
809         return ctx_data_collection_get(C, "editable_bones", list);
810 }
811
812 struct bPoseChannel *CTX_data_active_pchan(const bContext *C)
813 {
814         return ctx_data_pointer_get(C, "active_pchan");
815 }
816
817 int CTX_data_selected_pchans(const bContext *C, ListBase *list)
818 {
819         return ctx_data_collection_get(C, "selected_pchans", list);
820 }
821
822 int CTX_data_visible_pchans(const bContext *C, ListBase *list)
823 {
824         return ctx_data_collection_get(C, "visible_pchans", list);
825 }
826