void register_node_type_sh_group(void)
{
	static bNodeType ntype;
	
	/* NB: cannot use sh_node_type_base for node group, because it would map the node type
	 * to the shared NODE_GROUP integer type id.
	 */
	node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP, NODE_CONST_OUTPUT);
	ntype.type = NODE_GROUP;
	ntype.poll = sh_node_poll_default;
	ntype.poll_instance = node_group_poll_instance;
	ntype.update_internal_links = node_update_internal_links_default;
	ntype.ext.srna = RNA_struct_find("ShaderNodeGroup");
	BLI_assert(ntype.ext.srna != NULL);
	RNA_struct_blender_type_set(ntype.ext.srna, &ntype);
	
	node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
	node_type_socket_templates(&ntype, NULL, NULL);
	node_type_size(&ntype, 140, 60, 400);
	node_type_label(&ntype, node_group_label);
	node_type_update(&ntype, NULL, node_group_verify);
	node_type_exec(&ntype, group_initexec, group_freeexec, group_execute);
	node_type_gpu(&ntype, gpu_group_execute);
	
	nodeRegisterType(&ntype);
}
static bNodeSocketType *make_socket_type_virtual(void)
{
	extern void ED_init_node_socket_type_virtual(bNodeSocketType *);
	
	const char *socket_idname = "NodeSocketVirtual";
	bNodeSocketType *stype;
	StructRNA *srna;
	
	stype = MEM_callocN(sizeof(bNodeSocketType), "node socket C type");
	BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname));
	
	/* set the RNA type
	 * uses the exact same identifier as the socket type idname */
	srna = stype->ext_socket.srna = RNA_struct_find(socket_idname);
	BLI_assert(srna != NULL);
	/* associate the RNA type with the socket type */
	RNA_struct_blender_type_set(srna, stype);
	
	/* extra type info for standard socket types */
	stype->type = SOCK_CUSTOM;
	
	ED_init_node_socket_type_virtual(stype);
	
	return stype;
}
Exemple #3
0
static StructRNA *rna_UIList_register(
        Main *bmain, ReportList *reports, void *data, const char *identifier,
        StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
	uiListType *ult, dummyult = {NULL};
	uiList dummyuilist = {NULL};
	PointerRNA dummyul_ptr;
	int have_function[3];
	size_t over_alloc = 0; /* warning, if this becomes a bess, we better do another alloc */

	/* setup dummy menu & menu type to store static properties in */
	dummyuilist.type = &dummyult;
	RNA_pointer_create(NULL, &RNA_UIList, &dummyuilist, &dummyul_ptr);

	/* validate the python class */
	if (validate(&dummyul_ptr, data, have_function) != 0)
		return NULL;

	if (strlen(identifier) >= sizeof(dummyult.idname)) {
		BKE_reportf(reports, RPT_ERROR, "Registering uilist class: '%s' is too long, maximum length is %d",
		            identifier, (int)sizeof(dummyult.idname));
		return NULL;
	}

	/* check if we have registered this uilist type before, and remove it */
	ult = WM_uilisttype_find(dummyult.idname, true);
	if (ult && ult->ext.srna) {
		rna_UIList_unregister(bmain, ult->ext.srna);
	}
	if (!RNA_struct_available_or_report(reports, dummyult.idname)) {
		return NULL;
	}
	if (!RNA_struct_bl_idname_ok_or_report(reports, dummyult.idname, "_UL_")) {
		return NULL;
	}

	/* create a new menu type */
	ult = MEM_callocN(sizeof(uiListType) + over_alloc, "python uilist");
	memcpy(ult, &dummyult, sizeof(dummyult));

	ult->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, ult->idname, &RNA_UIList);
	ult->ext.data = data;
	ult->ext.call = call;
	ult->ext.free = free;
	RNA_struct_blender_type_set(ult->ext.srna, ult);

	ult->draw_item = (have_function[0]) ? uilist_draw_item : NULL;
	ult->draw_filter = (have_function[1]) ? uilist_draw_filter : NULL;
	ult->filter_items = (have_function[2]) ? uilist_filter_items : NULL;

	WM_uilisttype_add(ult);

	/* update while blender is running */
	WM_main_add_notifier(NC_WINDOW, NULL);

	return ult->ext.srna;
}
Exemple #4
0
static StructRNA *rna_RenderEngine_register(
        Main *bmain, ReportList *reports, void *data, const char *identifier,
        StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
	RenderEngineType *et, dummyet = {NULL};
	RenderEngine dummyengine = {NULL};
	PointerRNA dummyptr;
	int have_function[7];

	/* setup dummy engine & engine type to store static properties in */
	dummyengine.type = &dummyet;
	dummyet.flag |= RE_USE_SHADING_NODES_CUSTOM;
	RNA_pointer_create(NULL, &RNA_RenderEngine, &dummyengine, &dummyptr);

	/* validate the python class */
	if (validate(&dummyptr, data, have_function) != 0)
		return NULL;

	if (strlen(identifier) >= sizeof(dummyet.idname)) {
		BKE_reportf(reports, RPT_ERROR, "Registering render engine class: '%s' is too long, maximum length is %d",
		            identifier, (int)sizeof(dummyet.idname));
		return NULL;
	}

	/* check if we have registered this engine type before, and remove it */
	for (et = R_engines.first; et; et = et->next) {
		if (STREQ(et->idname, dummyet.idname)) {
			if (et->ext.srna)
				rna_RenderEngine_unregister(bmain, et->ext.srna);
			break;
		}
	}
	
	/* create a new engine type */
	et = MEM_callocN(sizeof(RenderEngineType), "python render engine");
	memcpy(et, &dummyet, sizeof(dummyet));

	et->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, et->idname, &RNA_RenderEngine);
	et->ext.data = data;
	et->ext.call = call;
	et->ext.free = free;
	RNA_struct_blender_type_set(et->ext.srna, et);

	et->update = (have_function[0]) ? engine_update : NULL;
	et->render = (have_function[1]) ? engine_render : NULL;
	et->bake = (have_function[2]) ? engine_bake : NULL;
	et->view_update = (have_function[3]) ? engine_view_update : NULL;
	et->view_draw = (have_function[4]) ? engine_view_draw : NULL;
	et->update_script_node = (have_function[5]) ? engine_update_script_node : NULL;
	et->update_render_passes = (have_function[6]) ? engine_update_render_passes : NULL;

	BLI_addtail(&R_engines, et);

	return et->ext.srna;
}
Exemple #5
0
static StructRNA *rna_Header_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
                                      StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
	ARegionType *art;
	HeaderType *ht, dummyht = {NULL};
	Header dummyheader = {NULL};
	PointerRNA dummyhtr;
	int have_function[1];

	/* setup dummy header & header type to store static properties in */
	dummyheader.type = &dummyht;
	RNA_pointer_create(NULL, &RNA_Header, &dummyheader, &dummyhtr);

	/* validate the python class */
	if (validate(&dummyhtr, data, have_function) != 0)
		return NULL;

	if (strlen(identifier) >= sizeof(dummyht.idname)) {
		BKE_reportf(reports, RPT_ERROR, "Registering header class: '%s' is too long, maximum length is %d",
		            identifier, (int)sizeof(dummyht.idname));
		return NULL;
	}

	if (!(art = region_type_find(reports, dummyht.space_type, RGN_TYPE_HEADER)))
		return NULL;

	/* check if we have registered this header type before, and remove it */
	for (ht = art->headertypes.first; ht; ht = ht->next) {
		if (strcmp(ht->idname, dummyht.idname) == 0) {
			if (ht->ext.srna)
				rna_Header_unregister(bmain, ht->ext.srna);
			break;
		}
	}
	
	/* create a new header type */
	ht = MEM_callocN(sizeof(HeaderType), "python buttons header");
	memcpy(ht, &dummyht, sizeof(dummyht));

	ht->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, ht->idname, &RNA_Header);
	ht->ext.data = data;
	ht->ext.call = call;
	ht->ext.free = free;
	RNA_struct_blender_type_set(ht->ext.srna, ht);

	ht->draw = (have_function[0]) ? header_draw : NULL;

	BLI_addtail(&art->headertypes, ht);

	/* update while blender is running */
	WM_main_add_notifier(NC_WINDOW, NULL);
	
	return ht->ext.srna;
}
Exemple #6
0
static StructRNA *rna_KeyingSetInfo_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
                                             StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
	KeyingSetInfo dummyksi = {NULL};
	KeyingSetInfo *ksi;
	PointerRNA dummyptr = {{NULL}};
	int have_function[3];

	/* setup dummy type info to store static properties in */
	/* TODO: perhaps we want to get users to register as if they're using 'KeyingSet' directly instead? */
	RNA_pointer_create(NULL, &RNA_KeyingSetInfo, &dummyksi, &dummyptr);
	
	/* validate the python class */
	if (validate(&dummyptr, data, have_function) != 0)
		return NULL;
	
	if (strlen(identifier) >= sizeof(dummyksi.idname)) {
		BKE_reportf(reports, RPT_ERROR, "Registering keying set info class: '%s' is too long, maximum length is %d",
		            identifier, (int)sizeof(dummyksi.idname));
		return NULL;
	}
	
	/* check if we have registered this info before, and remove it */
	ksi = ANIM_keyingset_info_find_name(dummyksi.idname);
	if (ksi && ksi->ext.srna)
		rna_KeyingSetInfo_unregister(bmain, ksi->ext.srna);
	
	/* create a new KeyingSetInfo type */
	ksi = MEM_callocN(sizeof(KeyingSetInfo), "python keying set info");
	memcpy(ksi, &dummyksi, sizeof(KeyingSetInfo));
	
	/* set RNA-extensions info */
	ksi->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, ksi->idname, &RNA_KeyingSetInfo);
	ksi->ext.data = data;
	ksi->ext.call = call;
	ksi->ext.free = free;
	RNA_struct_blender_type_set(ksi->ext.srna, ksi);
	
	/* set callbacks */
	/* NOTE: we really should have all of these...  */
	ksi->poll = (have_function[0]) ? RKS_POLL_rna_internal : NULL;
	ksi->iter = (have_function[1]) ? RKS_ITER_rna_internal : NULL;
	ksi->generate = (have_function[2]) ? RKS_GEN_rna_internal : NULL;
	
	/* add and register with other info as needed */
	ANIM_keyingset_info_register(ksi);
	
	WM_main_add_notifier(NC_WINDOW, NULL);

	/* return the struct-rna added */
	return ksi->ext.srna;
}
static bNodeSocketType *make_standard_socket_type(int type, int subtype)
{
	extern void ED_init_standard_node_socket_type(bNodeSocketType *);
	
	const char *socket_idname = nodeStaticSocketType(type, subtype);
	const char *interface_idname = nodeStaticSocketInterfaceType(type, subtype);
	bNodeSocketType *stype;
	StructRNA *srna;
	
	stype = MEM_callocN(sizeof(bNodeSocketType), "node socket C type");
	BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname));
	
	/* set the RNA type
	 * uses the exact same identifier as the socket type idname */
	srna = stype->ext_socket.srna = RNA_struct_find(socket_idname);
	BLI_assert(srna != NULL);
	/* associate the RNA type with the socket type */
	RNA_struct_blender_type_set(srna, stype);
	
	/* set the interface RNA type */
	srna = stype->ext_interface.srna = RNA_struct_find(interface_idname);
	BLI_assert(srna != NULL);
	/* associate the RNA type with the socket type */
	RNA_struct_blender_type_set(srna, stype);
	
	/* extra type info for standard socket types */
	stype->type = type;
	stype->subtype = subtype;
	
	/* XXX bad-level call! needed for setting draw callbacks */
	ED_init_standard_node_socket_type(stype);
	
	stype->interface_init_socket = standard_node_socket_interface_init_socket;
	stype->interface_from_socket = standard_node_socket_interface_from_socket;
	stype->interface_verify_socket = standard_node_socket_interface_verify_socket;
	
	return stype;
}
static void operator_properties_init(wmOperatorType *ot)
{
	PyObject *py_class = ot->ext.data;
	RNA_struct_blender_type_set(ot->ext.srna, ot);

	/* only call this so pyrna_deferred_register_class gives a useful error
	 * WM_operatortype_append_ptr will call RNA_def_struct_identifier
	 * later */
	RNA_def_struct_identifier(ot->srna, ot->idname);

	if (pyrna_deferred_register_class(ot->srna, py_class) != 0) {
		PyErr_Print(); /* failed to register operator props */
		PyErr_Clear();
	}
}
Exemple #9
0
static StructRNA *rna_Menu_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
                                    StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
    MenuType *mt, dummymt = {NULL};
    Menu dummymenu= {NULL};
    PointerRNA dummymtr;
    int have_function[2];

    /* setup dummy menu & menu type to store static properties in */
    dummymenu.type= &dummymt;
    RNA_pointer_create(NULL, &RNA_Menu, &dummymenu, &dummymtr);

    /* validate the python class */
    if(validate(&dummymtr, data, have_function) != 0)
        return NULL;

    if(strlen(identifier) >= sizeof(dummymt.idname)) {
        BKE_reportf(reports, RPT_ERROR, "registering menu class: '%s' is too long, maximum length is %d",
                    identifier, (int)sizeof(dummymt.idname));
        return NULL;
    }

    /* check if we have registered this menu type before, and remove it */
    mt= WM_menutype_find(dummymt.idname, TRUE);
    if(mt && mt->ext.srna)
        rna_Menu_unregister(bmain, mt->ext.srna);

    /* create a new menu type */
    mt= MEM_callocN(sizeof(MenuType), "python buttons menu");
    memcpy(mt, &dummymt, sizeof(dummymt));

    mt->ext.srna= RNA_def_struct(&BLENDER_RNA, mt->idname, "Menu");
    mt->ext.data= data;
    mt->ext.call= call;
    mt->ext.free= free;
    RNA_struct_blender_type_set(mt->ext.srna, mt);
    RNA_def_struct_flag(mt->ext.srna, STRUCT_NO_IDPROPERTIES);

    mt->poll= (have_function[0])? menu_poll: NULL;
    mt->draw= (have_function[1])? menu_draw: NULL;

    WM_menutype_add(mt);

    /* update while blender is running */
    WM_main_add_notifier(NC_SCREEN|NA_EDITED, NULL);

    return mt->ext.srna;
}
Exemple #10
0
void register_node_type_cmp_group(void)
{
	static bNodeType ntype;
	
	/* NB: cannot use sh_node_type_base for node group, because it would map the node type
	 * to the shared NODE_GROUP integer type id.
	 */
	node_type_base_custom(&ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP, NODE_OPTIONS | NODE_CONST_OUTPUT);
	ntype.type = NODE_GROUP;
	ntype.poll = cmp_node_poll_default;
	ntype.poll_instance = node_group_poll_instance;
	ntype.update_internal_links = node_update_internal_links_default;
	ntype.ext.srna = RNA_struct_find("CompositorNodeGroup");
	BLI_assert(ntype.ext.srna != NULL);
	RNA_struct_blender_type_set(ntype.ext.srna, &ntype);
	
	node_type_socket_templates(&ntype, NULL, NULL);
	node_type_size(&ntype, 120, 60, 200);
	node_type_label(&ntype, node_group_label);
	node_type_update(&ntype, NULL, node_group_verify);

	nodeRegisterType(&ntype);
}
Exemple #11
0
static StructRNA *rna_Menu_register(
        Main *bmain, ReportList *reports, void *data, const char *identifier,
        StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
	MenuType *mt, dummymt = {NULL};
	Menu dummymenu = {NULL};
	PointerRNA dummymtr;
	int have_function[2];
	size_t over_alloc = 0; /* warning, if this becomes a bess, we better do another alloc */
	size_t description_size = 0;
	char _menu_descr[RNA_DYN_DESCR_MAX];

	/* setup dummy menu & menu type to store static properties in */
	dummymenu.type = &dummymt;
	_menu_descr[0] = '\0';
	dummymenu.type->description = _menu_descr;
	RNA_pointer_create(NULL, &RNA_Menu, &dummymenu, &dummymtr);

	/* We have to set default context! Else we get a void string... */
	strcpy(dummymt.translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);

	/* validate the python class */
	if (validate(&dummymtr, data, have_function) != 0)
		return NULL;

	if (strlen(identifier) >= sizeof(dummymt.idname)) {
		BKE_reportf(reports, RPT_ERROR, "Registering menu class: '%s' is too long, maximum length is %d",
		            identifier, (int)sizeof(dummymt.idname));
		return NULL;
	}

	/* check if we have registered this menu type before, and remove it */
	mt = WM_menutype_find(dummymt.idname, true);
	if (mt && mt->ext.srna) {
		rna_Menu_unregister(bmain, mt->ext.srna);
	}
	if (!RNA_struct_available_or_report(reports, dummymt.idname)) {
		return NULL;
	}
	if (!RNA_struct_bl_idname_ok_or_report(reports, dummymt.idname, "_MT_")) {
		return NULL;
	}

	/* create a new menu type */
	if (_menu_descr[0]) {
		description_size = strlen(_menu_descr) + 1;
		over_alloc += description_size;
	}

	mt = MEM_callocN(sizeof(MenuType) + over_alloc, "python buttons menu");
	memcpy(mt, &dummymt, sizeof(dummymt));

	if (_menu_descr[0]) {
		char *buf = (char *)(mt + 1);
		memcpy(buf, _menu_descr, description_size);
		mt->description = buf;
	}
	else
		mt->description = "";

	mt->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, mt->idname, &RNA_Menu);
	RNA_def_struct_translation_context(mt->ext.srna, mt->translation_context);
	mt->ext.data = data;
	mt->ext.call = call;
	mt->ext.free = free;
	RNA_struct_blender_type_set(mt->ext.srna, mt);
	RNA_def_struct_flag(mt->ext.srna, STRUCT_NO_IDPROPERTIES);

	mt->poll = (have_function[0]) ? menu_poll : NULL;
	mt->draw = (have_function[1]) ? menu_draw : NULL;

	WM_menutype_add(mt);

	/* update while blender is running */
	WM_main_add_notifier(NC_WINDOW, NULL);

	return mt->ext.srna;
}
Exemple #12
0
static StructRNA *rna_Panel_register(
        Main *bmain, ReportList *reports, void *data, const char *identifier,
        StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
	ARegionType *art;
	PanelType *pt, dummypt = {NULL};
	Panel dummypanel = {NULL};
	PointerRNA dummyptr;
	int have_function[3];

	/* setup dummy panel & panel type to store static properties in */
	dummypanel.type = &dummypt;
	RNA_pointer_create(NULL, &RNA_Panel, &dummypanel, &dummyptr);

	/* We have to set default context! Else we get a void string... */
	strcpy(dummypt.translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);

	/* validate the python class */
	if (validate(&dummyptr, data, have_function) != 0)
		return NULL;

	if (strlen(identifier) >= sizeof(dummypt.idname)) {
		BKE_reportf(reports, RPT_ERROR, "Registering panel class: '%s' is too long, maximum length is %d",
		            identifier, (int)sizeof(dummypt.idname));
		return NULL;
	}

	if ((dummypt.category[0] == '\0') && (dummypt.region_type == RGN_TYPE_TOOLS)) {
		/* Use a fallback, otherwise an empty value will draw the panel in every category. */
		strcpy(dummypt.category, PNL_CATEGORY_FALLBACK);
	}

	if (!(art = region_type_find(reports, dummypt.space_type, dummypt.region_type)))
		return NULL;

	/* check if we have registered this panel type before, and remove it */
	for (pt = art->paneltypes.first; pt; pt = pt->next) {
		if (STREQ(pt->idname, dummypt.idname)) {
			if (pt->ext.srna)
				rna_Panel_unregister(bmain, pt->ext.srna);
			else
				BLI_freelinkN(&art->paneltypes, pt);
			break;
		}
	}
	if (!RNA_struct_available_or_report(reports, dummypt.idname)) {
		return NULL;
	}
	if (!RNA_struct_bl_idname_ok_or_report(reports, dummypt.idname, "_PT_")) {
		return NULL;
	}

	/* create a new panel type */
	pt = MEM_callocN(sizeof(PanelType), "python buttons panel");
	memcpy(pt, &dummypt, sizeof(dummypt));

	pt->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, pt->idname, &RNA_Panel);
	RNA_def_struct_translation_context(pt->ext.srna, pt->translation_context);
	pt->ext.data = data;
	pt->ext.call = call;
	pt->ext.free = free;
	RNA_struct_blender_type_set(pt->ext.srna, pt);
	RNA_def_struct_flag(pt->ext.srna, STRUCT_NO_IDPROPERTIES);

	pt->poll = (have_function[0]) ? panel_poll : NULL;
	pt->draw = (have_function[1]) ? panel_draw : NULL;
	pt->draw_header = (have_function[2]) ? panel_draw_header : NULL;

	/* XXX use "no header" flag for some ordering of panels until we have real panel ordering */
	if (pt->flag & PNL_NO_HEADER) {
		PanelType *pth = art->paneltypes.first;
		while (pth && pth->flag & PNL_NO_HEADER)
			pth = pth->next;

		if (pth)
			BLI_insertlinkbefore(&art->paneltypes, pth, pt);
		else
			BLI_addtail(&art->paneltypes, pt);
	}
	else
		BLI_addtail(&art->paneltypes, pt);

	/* update while blender is running */
	WM_main_add_notifier(NC_WINDOW, NULL);

	return pt->ext.srna;
}
Exemple #13
0
static StructRNA *rna_Panel_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
                                     StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
    ARegionType *art;
    PanelType *pt, dummypt = {NULL};
    Panel dummypanel= {NULL};
    PointerRNA dummyptr;
    int have_function[3];

    /* setup dummy panel & panel type to store static properties in */
    dummypanel.type= &dummypt;
    RNA_pointer_create(NULL, &RNA_Panel, &dummypanel, &dummyptr);

    /* validate the python class */
    if(validate(&dummyptr, data, have_function) != 0)
        return NULL;

    if(strlen(identifier) >= sizeof(dummypt.idname)) {
        BKE_reportf(reports, RPT_ERROR, "registering panel class: '%s' is too long, maximum length is %d",
                    identifier, (int)sizeof(dummypt.idname));
        return NULL;
    }

    if(!(art=region_type_find(reports, dummypt.space_type, dummypt.region_type)))
        return NULL;

    /* check if we have registered this panel type before, and remove it */
    for(pt=art->paneltypes.first; pt; pt=pt->next) {
        if(strcmp(pt->idname, dummypt.idname) == 0) {
            if(pt->ext.srna)
                rna_Panel_unregister(bmain, pt->ext.srna);
            else
                BLI_freelinkN(&art->paneltypes, pt);
            break;
        }
    }

    /* create a new panel type */
    pt= MEM_callocN(sizeof(PanelType), "python buttons panel");
    memcpy(pt, &dummypt, sizeof(dummypt));

    pt->ext.srna= RNA_def_struct(&BLENDER_RNA, pt->idname, "Panel");
    pt->ext.data= data;
    pt->ext.call= call;
    pt->ext.free= free;
    RNA_struct_blender_type_set(pt->ext.srna, pt);
    RNA_def_struct_flag(pt->ext.srna, STRUCT_NO_IDPROPERTIES);

    pt->poll= (have_function[0])? panel_poll: NULL;
    pt->draw= (have_function[1])? panel_draw: NULL;
    pt->draw_header= (have_function[2])? panel_draw_header: NULL;

    /* XXX use "no header" flag for some ordering of panels until we have real panel ordering */
    if(pt->flag & PNL_NO_HEADER) {
        PanelType *pth = art->paneltypes.first;
        while(pth && pth->flag & PNL_NO_HEADER)
            pth=pth->next;

        if(pth)
            BLI_insertlinkbefore(&art->paneltypes, pth, pt);
        else
            BLI_addtail(&art->paneltypes, pt);
    }
    else
        BLI_addtail(&art->paneltypes, pt);

    /* update while blender is running */
    WM_main_add_notifier(NC_SCREEN|NA_EDITED, NULL);

    return pt->ext.srna;
}