* For new buttons spaces, automatically set horizontal/vertical align depending on size, instead of free. * Cleaned up the UI panel API. There's now a new uiBeginPanel function which takes a panel type, and a uiEndPanel which takes the final size. uiNewPanel* functions will be phased out. * Animate the re-alignment when a panel size changes, e.g. when enabling dupliframes. * Load ui scripts from the release/ folder first if it is available. This makes it easier to edit ui scripts, since it will directly use the original files which avoids having to run the build system. * Improve editing of panel types while blender is open. That means fixing some issues with lacking updates, overlaps, strange ordering. It even does an animation now when the panel resizes.
253 lines
6.9 KiB
C
253 lines
6.9 KiB
C
/**
|
|
* $Id$
|
|
*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* Contributor(s): Campbell Barton
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#include "bpy_panel_wrap.h"
|
|
#include "bpy_rna.h"
|
|
#include "bpy_util.h"
|
|
#include "bpy_compat.h"
|
|
|
|
#include "RNA_define.h"
|
|
#include "RNA_enum_types.h"
|
|
|
|
#include "BLI_listbase.h"
|
|
#include "BKE_context.h"
|
|
#include "BKE_screen.h"
|
|
#include "DNA_screen_types.h"
|
|
#include "MEM_guardedalloc.h"
|
|
#include "ED_screen.h"
|
|
#include "WM_api.h"
|
|
#include "WM_types.h"
|
|
|
|
#define PYPANEL_ATTR_UINAME "__label__"
|
|
#define PYPANEL_ATTR_IDNAME "__name__" /* use pythons class name */
|
|
#define PYPANEL_ATTR_CONTEXT "__context__"
|
|
|
|
#define PYPANEL_DRAW 1
|
|
#define PYPANEL_POLL 2
|
|
|
|
extern void BPY_update_modules( void ); //XXX temp solution
|
|
|
|
static int PyPanel_generic(int mode, const bContext *C, Panel *pnl)
|
|
{
|
|
PyObject *py_class= (PyObject *)(pnl->type->py_data);
|
|
|
|
PyObject *args;
|
|
PyObject *ret= NULL, *py_class_instance, *item;
|
|
PointerRNA panelptr;
|
|
int ret_flag= 0;
|
|
|
|
PyGILState_STATE gilstate = PyGILState_Ensure();
|
|
|
|
BPY_update_modules(); // XXX - the RNA pointers can change so update before running, would like a nicer solutuon for this.
|
|
|
|
args = PyTuple_New(1);
|
|
RNA_pointer_create(&CTX_wm_screen(C)->id, pnl->type->srna, pnl, &panelptr);
|
|
PyTuple_SET_ITEM(args, 0, pyrna_struct_CreatePyObject(&panelptr));
|
|
py_class_instance = PyObject_Call(py_class, args, NULL);
|
|
Py_DECREF(args);
|
|
|
|
if (py_class_instance) { /* Initializing the class worked, now run its invoke function */
|
|
PointerRNA context_ptr;
|
|
|
|
if (mode==PYPANEL_DRAW) {
|
|
item= PyObject_GetAttrString(py_class, "draw");
|
|
}
|
|
else if (mode==PYPANEL_POLL) {
|
|
item= PyObject_GetAttrString(py_class, "poll");
|
|
}
|
|
args = PyTuple_New(2);
|
|
PyTuple_SET_ITEM(args, 0, py_class_instance);
|
|
|
|
RNA_pointer_create(NULL, &RNA_Context, (void *)C, &context_ptr);
|
|
|
|
PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&context_ptr));
|
|
|
|
ret = PyObject_Call(item, args, NULL);
|
|
|
|
/* args is decref'd from item */
|
|
Py_DECREF(item);
|
|
}
|
|
|
|
if (ret == NULL) { /* covers py_class_instance failing too */
|
|
PyErr_Print(); /* XXX use reporting api? */
|
|
}
|
|
else {
|
|
if (mode==PYPANEL_POLL) {
|
|
if (PyBool_Check(ret) == 0) {
|
|
PyErr_SetString(PyExc_ValueError, "Python poll function return value ");
|
|
PyErr_Print(); /* XXX use reporting api? */
|
|
}
|
|
else {
|
|
ret_flag= ret==Py_True ? 1:0;
|
|
}
|
|
}
|
|
else {
|
|
//XXX - draw stuff
|
|
}
|
|
|
|
Py_DECREF(ret);
|
|
}
|
|
PyGILState_Release(gilstate);
|
|
|
|
return ret_flag;
|
|
}
|
|
|
|
static void PyPanel_draw(const bContext *C, Panel *pnl)
|
|
{
|
|
PyPanel_generic(PYPANEL_DRAW, C, pnl);
|
|
}
|
|
|
|
static int PyPanel_poll(const bContext *C)
|
|
{
|
|
//return PyPanel_generic(PYPANEL_POLL, C, NULL);
|
|
return 1; // XXX we need the panel type to access the PyObject grr!
|
|
}
|
|
|
|
/* pyOperators - Operators defined IN Python */
|
|
PyObject *PyPanel_wrap_add(PyObject *self, PyObject *args)
|
|
{
|
|
bContext *C;
|
|
PyObject *item;
|
|
PyObject *py_class;
|
|
PyObject *base_class;
|
|
char *space_identifier;
|
|
char *region_identifier;
|
|
char *idname;
|
|
int space_value;
|
|
int region_value;
|
|
|
|
PanelType *pt;
|
|
SpaceType *st;
|
|
ARegionType *art;
|
|
|
|
static struct BPY_class_attr_check pypnl_class_attr_values[]= {
|
|
{PYPANEL_ATTR_IDNAME, 's', 0, 0},
|
|
{PYPANEL_ATTR_UINAME, 's', 0, 0},
|
|
{PYPANEL_ATTR_CONTEXT, 's', 0, 0},
|
|
{"draw", 'f', 2, 0}, /* Do we need the Panel struct?, could be an extra arg */
|
|
{"poll", 'f', 2, BPY_CLASS_ATTR_OPTIONAL},
|
|
{NULL, 0, 0, 0}};
|
|
|
|
enum {
|
|
PYPANEL_ATTR_IDNAME_IDX=0,
|
|
PYPANEL_ATTR_UINAME_IDX,
|
|
PYPANEL_ATTR_CONTEXT_IDX,
|
|
PYPANEL_ATTR_DRAW_IDX,
|
|
PYPANEL_ATTR_POLL_IDX
|
|
};
|
|
|
|
PyObject *pypnl_class_attrs[6]= {NULL, NULL, NULL, NULL, NULL, NULL};
|
|
|
|
if( !PyArg_ParseTuple( args, "Oss:addPanel", &py_class, &space_identifier, ®ion_identifier))
|
|
return NULL;
|
|
|
|
base_class = PyObject_GetAttrStringArgs(PyDict_GetItemString(PyEval_GetGlobals(), "bpy"), 2, "types", "Panel");
|
|
Py_DECREF(base_class);
|
|
|
|
/* Should this use a base class? */
|
|
if (BPY_class_validate("Panel", py_class, base_class, pypnl_class_attr_values, pypnl_class_attrs) < 0) {
|
|
return NULL; /* BPY_class_validate sets the error */
|
|
}
|
|
|
|
if (RNA_enum_value_from_id(space_type_items, space_identifier, &space_value)==0) {
|
|
char *cstring= BPy_enum_as_string(space_type_items);
|
|
PyErr_Format( PyExc_AttributeError, "SpaceType \"%s\" is not one of [%s]", space_identifier, cstring);
|
|
MEM_freeN(cstring);
|
|
return NULL;
|
|
}
|
|
|
|
if (RNA_enum_value_from_id(region_type_items, region_identifier, ®ion_value)==0) {
|
|
char *cstring= BPy_enum_as_string(region_type_items);
|
|
PyErr_Format( PyExc_AttributeError, "RegionType \"%s\" is not one of [%s]", region_identifier, cstring);
|
|
MEM_freeN(cstring);
|
|
return NULL;
|
|
}
|
|
|
|
st= BKE_spacetype_from_id(space_value);
|
|
|
|
#if 0
|
|
// for printing what panels we have
|
|
for(art= st->regiontypes.first; art; art= art->next) {
|
|
|
|
printf("REG %d\n", art->regionid);
|
|
|
|
for(pt= art->paneltypes.first; pt; pt= pt->next) {
|
|
printf("\tREG %s %s - %s\n", pt->idname, pt->name, pt->context);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for(art= st->regiontypes.first; art; art= art->next) {
|
|
if (art->regionid==region_value)
|
|
break;
|
|
}
|
|
|
|
if (art==NULL) {
|
|
PyErr_Format( PyExc_AttributeError, "SpaceType \"%s\" does not have a UI region '%s'", space_identifier, region_identifier);
|
|
return NULL;
|
|
}
|
|
|
|
idname= _PyUnicode_AsString(pypnl_class_attrs[PYPANEL_ATTR_IDNAME_IDX]);
|
|
|
|
for(pt=art->paneltypes.first; pt; pt=pt->next)
|
|
if(strcmp(pt->idname, idname) == 0)
|
|
break;
|
|
|
|
if(!pt) {
|
|
pt= MEM_callocN(sizeof(PanelType), "python buttons panel");
|
|
pt->srna= RNA_def_struct(&BLENDER_RNA, pt->idname, "Panel");
|
|
BLI_addtail(&art->paneltypes, pt);
|
|
}
|
|
|
|
pt->idname= idname;
|
|
|
|
item= pypnl_class_attrs[PYPANEL_ATTR_UINAME_IDX];
|
|
pt->name= item? _PyUnicode_AsString(item): pt->idname;
|
|
pt->context= _PyUnicode_AsString(pypnl_class_attrs[PYPANEL_ATTR_CONTEXT_IDX]);
|
|
|
|
if (pypnl_class_attrs[PYPANEL_ATTR_POLL_IDX])
|
|
pt->poll= PyPanel_poll;
|
|
else
|
|
pt->poll= NULL;
|
|
|
|
pt->draw= PyPanel_draw;
|
|
|
|
Py_INCREF(py_class);
|
|
pt->py_data= (void *)py_class;
|
|
RNA_struct_py_type_set(pt->srna, py_class);
|
|
|
|
C= (bContext *)PyCObject_AsVoidPtr(PyDict_GetItemString(PyEval_GetGlobals(), "__bpy_context__"));
|
|
if(C)
|
|
WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
PyObject *PyPanel_wrap_remove(PyObject *self, PyObject *args)
|
|
{
|
|
// XXX - todo
|
|
Py_RETURN_NONE;
|
|
}
|
|
|