PupBlock method. This wraps the "clevernumbut" code to allow scripters to use popup blocks for user input instead of a sequence of multiple different popups.
See the blend file for a comprehensive test and example file.
This commit is contained in:
2006-01-08 18:59:55 +00:00
parent 072c32bcea
commit 2ead92cc2b
3 changed files with 207 additions and 20 deletions

View File

@@ -107,6 +107,8 @@ static PyObject *Method_PupFloatInput( PyObject * self, PyObject * args );
static PyObject *Method_PupStrInput( PyObject * self, PyObject * args ); static PyObject *Method_PupStrInput( PyObject * self, PyObject * args );
/* next by Jonathan Merritt (lancelet): */ /* next by Jonathan Merritt (lancelet): */
static PyObject *Method_Image( PyObject * self, PyObject * args); static PyObject *Method_Image( PyObject * self, PyObject * args);
/* CLEVER NUMBUT */
static PyObject *Method_PupBlock( PyObject * self, PyObject * args );
static uiBlock *Get_uiBlock( void ); static uiBlock *Get_uiBlock( void );
static void py_slider_update( void *butv, void *data2_unused ); static void py_slider_update( void *butv, void *data2_unused );
@@ -277,6 +279,22 @@ static char Method_PupStrInput_doc[] =
(max = 20) - The maximum number of chars the user can input;\n\ (max = 20) - The maximum number of chars the user can input;\n\
Return the user input value or None on user exit"; Return the user input value or None on user exit";
static char Method_PupBlock_doc[] =
"(title, sequence) - Display a pop-up block.\n\
(title) - The title of the block.\n\
(sequence) - A sequence defining what the block contains. \
The order of the list is the order of appearance, from top down.\n\
Possible format for sequence items:\n\
[value is an object created with Create]\n\
\ttext: Defines a label in the block\n\
\t(text, value, tooltip = ''): Defines a toggle button \n\
\t(text, value, min, max, tooltip = ''): Defines a num or string button \n\
\t\t\tdepending on the value.\n\
\t\tFor string, max is the maximum length of the text and min is unused.\n\
Return 1 if the pop-up is confirmed, 0 otherwise. \n\
Warning: On cancel, the value objects are brought back to there previous values, \
\texcept for string values which will still contain the modified values.\n";
static char Method_Exit_doc[] = "() - Exit the windowing interface"; static char Method_Exit_doc[] = "() - Exit the windowing interface";
/* /*
@@ -307,6 +325,7 @@ static struct PyMethodDef Draw_methods[] = {
MethodDef( PupIntInput ), MethodDef( PupIntInput ),
MethodDef( PupFloatInput ), MethodDef( PupFloatInput ),
MethodDef( PupStrInput ), MethodDef( PupStrInput ),
MethodDef( PupBlock ),
MethodDef( Image ), MethodDef( Image ),
MethodDef( Exit ), MethodDef( Exit ),
MethodDef( Redraw ), MethodDef( Redraw ),
@@ -335,7 +354,7 @@ static void Button_dealloc( PyObject * self )
{ {
Button *but = ( Button * ) self; Button *but = ( Button * ) self;
if( but->type == 3 ) { if( but->type == BSTRING_TYPE ) {
if( but->val.asstr ) if( but->val.asstr )
MEM_freeN( but->val.asstr ); MEM_freeN( but->val.asstr );
} }
@@ -348,11 +367,11 @@ static PyObject *Button_getattr( PyObject * self, char *name )
Button *but = ( Button * ) self; Button *but = ( Button * ) self;
if( strcmp( name, "val" ) == 0 ) { if( strcmp( name, "val" ) == 0 ) {
if( but->type == 1 ) if( but->type == BINT_TYPE )
return Py_BuildValue( "i", but->val.asint ); return Py_BuildValue( "i", but->val.asint );
else if( but->type == 2 ) else if( but->type == BFLOAT_TYPE )
return Py_BuildValue( "f", but->val.asfloat ); return Py_BuildValue( "f", but->val.asfloat );
else if( but->type == 3 ) else if( but->type == BSTRING_TYPE )
return Py_BuildValue( "s", but->val.asstr ); return Py_BuildValue( "s", but->val.asstr );
} }
@@ -365,11 +384,11 @@ static int Button_setattr( PyObject * self, char *name, PyObject * v )
Button *but = ( Button * ) self; Button *but = ( Button * ) self;
if( strcmp( name, "val" ) == 0 ) { if( strcmp( name, "val" ) == 0 ) {
if( but->type == 1 ) if( but->type == BINT_TYPE )
PyArg_Parse( v, "i", &but->val.asint ); PyArg_Parse( v, "i", &but->val.asint );
else if( but->type == 2 ) else if( but->type == BFLOAT_TYPE )
PyArg_Parse( v, "f", &but->val.asfloat ); PyArg_Parse( v, "f", &but->val.asfloat );
else if( but->type == 3 ) { else if( but->type == BSTRING_TYPE ) {
char *newstr; char *newstr;
PyArg_Parse( v, "s", &newstr ); PyArg_Parse( v, "s", &newstr );
@@ -705,15 +724,15 @@ static PyObject *Method_Create( PyObject * self, PyObject * args )
but = newbutton( ); but = newbutton( );
if( PyFloat_Check( in ) ) { if( PyFloat_Check( in ) ) {
but->type = 2; but->type = BFLOAT_TYPE;
but->val.asfloat = (float)PyFloat_AsDouble( in ); but->val.asfloat = (float)PyFloat_AsDouble( in );
} else if( PyInt_Check( in ) ) { } else if( PyInt_Check( in ) ) {
but->type = 1; but->type = BINT_TYPE;
but->val.asint = PyInt_AsLong( in ); but->val.asint = PyInt_AsLong( in );
} else if( PyString_Check( in ) ) { } else if( PyString_Check( in ) ) {
char *newstr = PyString_AsString( in ); char *newstr = PyString_AsString( in );
but->type = 3; but->type = BSTRING_TYPE;
but->slen = strlen( newstr ); but->slen = strlen( newstr );
but->val.asstr = MEM_mallocN( but->slen + 1, "button string" ); but->val.asstr = MEM_mallocN( but->slen + 1, "button string" );
@@ -790,7 +809,7 @@ static PyObject *Method_Menu( PyObject * self, PyObject * args )
"button event argument must be in the range [0, 16382]"); "button event argument must be in the range [0, 16382]");
but = newbutton( ); but = newbutton( );
but->type = 1; but->type = BINT_TYPE;
but->val.asint = def; but->val.asint = def;
block = Get_uiBlock( ); block = Get_uiBlock( );
@@ -819,7 +838,7 @@ static PyObject *Method_Toggle( PyObject * self, PyObject * args )
"button event argument must be in the range [0, 16382]"); "button event argument must be in the range [0, 16382]");
but = newbutton( ); but = newbutton( );
but->type = 1; but->type = BINT_TYPE;
but->val.asint = def; but->val.asint = def;
block = Get_uiBlock( ); block = Get_uiBlock( );
@@ -895,7 +914,7 @@ static PyObject *Method_Slider( PyObject * self, PyObject * args )
min = (float)PyFloat_AsDouble( mino ); min = (float)PyFloat_AsDouble( mino );
max = (float)PyFloat_AsDouble( maxo ); max = (float)PyFloat_AsDouble( maxo );
but->type = 2; but->type = BFLOAT_TYPE;
but->val.asfloat = ini; but->val.asfloat = ini;
block = Get_uiBlock( ); block = Get_uiBlock( );
@@ -915,7 +934,7 @@ static PyObject *Method_Slider( PyObject * self, PyObject * args )
min = PyInt_AsLong( mino ); min = PyInt_AsLong( mino );
max = PyInt_AsLong( maxo ); max = PyInt_AsLong( maxo );
but->type = 1; but->type = BINT_TYPE;
but->val.asint = ini; but->val.asint = ini;
block = Get_uiBlock( ); block = Get_uiBlock( );
@@ -960,15 +979,15 @@ another int and string as arguments" );
but = newbutton( ); but = newbutton( );
if( PyFloat_Check( inio ) ) if( PyFloat_Check( inio ) )
but->type = 2; but->type = BFLOAT_TYPE;
else else
but->type = 1; but->type = BINT_TYPE;
ini = (float)PyFloat_AsDouble( inio ); ini = (float)PyFloat_AsDouble( inio );
min = (float)PyFloat_AsDouble( mino ); min = (float)PyFloat_AsDouble( mino );
max = (float)PyFloat_AsDouble( maxo ); max = (float)PyFloat_AsDouble( maxo );
if( but->type == 2 ) { if( but->type == BFLOAT_TYPE ) {
but->val.asfloat = ini; but->val.asfloat = ini;
block = Get_uiBlock( ); block = Get_uiBlock( );
if( block ) { if( block ) {
@@ -1025,7 +1044,7 @@ static PyObject *Method_Number( PyObject * self, PyObject * args )
min = (float)PyFloat_AsDouble( mino ); min = (float)PyFloat_AsDouble( mino );
max = (float)PyFloat_AsDouble( maxo ); max = (float)PyFloat_AsDouble( maxo );
but->type = 2; but->type = BFLOAT_TYPE;
but->val.asfloat = ini; but->val.asfloat = ini;
block = Get_uiBlock( ); block = Get_uiBlock( );
@@ -1039,7 +1058,7 @@ static PyObject *Method_Number( PyObject * self, PyObject * args )
min = PyInt_AsLong( mino ); min = PyInt_AsLong( mino );
max = PyInt_AsLong( maxo ); max = PyInt_AsLong( maxo );
but->type = 1; but->type = BINT_TYPE;
but->val.asint = ini; but->val.asint = ini;
block = Get_uiBlock( ); block = Get_uiBlock( );
@@ -1079,7 +1098,7 @@ static PyObject *Method_String( PyObject * self, PyObject * args )
if (real_len > len) real_len = len; if (real_len > len) real_len = len;
but = newbutton( ); but = newbutton( );
but->type = 3; but->type = BSTRING_TYPE;
but->slen = len; but->slen = len;
but->val.asstr = MEM_mallocN( len + 1, "pybutton str" ); but->val.asstr = MEM_mallocN( len + 1, "pybutton str" );
@@ -1260,6 +1279,125 @@ static PyObject *Method_PupStrInput( PyObject * self, PyObject * args )
"couldn't create a PyString" ); "couldn't create a PyString" );
} }
static PyObject *Method_PupBlock( PyObject * self, PyObject * args )
{
PyObject *pyList, *pyItem;
float min, max;
int len, i;
char *title;
if (!PyArg_ParseTuple( args, "sO", &title, &pyList ) || !PySequence_Check( pyList ))
return EXPP_ReturnPyObjError( PyExc_TypeError, "expected a string and a sequence" );
len = PySequence_Length(pyList);
if (len == 0)
return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string and a non-empty sequence." );
if (len > 24) /* LIMIT DEFINED IN toolbox.c */
return EXPP_ReturnPyObjError( PyExc_ValueError, "sequence cannot have more than 24 elements" );
for ( i=0 ; i<len ; i++ ) {
PyObject *pyMin = NULL, *pyMax = NULL;
PyObject *f1, *f2;
Button *but = NULL;
int tlen;
char *text, *tip = NULL;
pyItem = PySequence_GetItem( pyList, i );
if (!pyItem)
return NULL;
if (PyString_Check( pyItem )) {
tlen = -2; /* single string for label, giving it a special len for later */
}
else if (PyTuple_Check( pyItem )) {
/* tuple for other button, get the length for later */
tlen = PyTuple_Size( pyItem );
}
else {
/* Neither a string or a tuple, error */
Py_DECREF( pyItem );
return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string or a tuple containing 2 to 5 values." );
}
switch (tlen) {
case -2: /* LABEL */
text = PyString_AsString( pyItem );
add_numbut(i, LABEL, text, 0, 0, NULL, NULL);
break;
case 2: /* TOGGLE (no tooltip) */
case 3: /* TOGGLE */
if (!PyArg_ParseTuple( pyItem, "sO!|s", &text, &Button_Type, &but, &tip )) {
Py_DECREF( pyItem );
return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a tuple containing a string, a Button object and optionally a string for toggles" );
}
if (but->type != BINT_TYPE) {
Py_DECREF( pyItem );
return EXPP_ReturnPyObjError( PyExc_ValueError, "Button object for toggles should hold an integer" );
}
add_numbut(i, TOG|INT, text, 0, 0, &but->val.asint, tip);
break;
case 4: /* TEX and NUM (no tooltip) */
case 5: /* TEX and NUM */
if (!PyArg_ParseTuple( pyItem, "sO!OO|s", &text, &Button_Type, &but, &pyMin, &pyMax, &tip )) {
Py_DECREF( pyItem );
return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a tuple containing a string, a Button object, two numerical values and optionally a string for Text and Num buttons" );
}
f1 = PyNumber_Float(pyMin);
f2 = PyNumber_Float(pyMax);
if (!f1 || !f2) {
Py_DECREF( pyItem );
return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a tuple containing a string, a Button object, two numerical values and optionally a string for Text and Num buttons" );
}
min = (float)PyFloat_AS_DOUBLE(f1);
max = (float)PyFloat_AS_DOUBLE(f2);
Py_DECREF( f1 );
Py_DECREF( f2 );
switch ( but->type ) {
case BINT_TYPE:
add_numbut(i, NUM|INT, text, min, max, &but->val.asint, tip);
break;
case BFLOAT_TYPE:
add_numbut(i, NUM|FLO, text, min, max, &but->val.asfloat, tip);
break;
case BSTRING_TYPE:
max = (float)floor(max);
if (max > but->slen) {
int old_len = but->slen;
char *old_str = but->val.asstr;
but->slen = (int)max;
but->val.asstr = MEM_callocN( but->slen + 1, "button pupblock");
BLI_strncpy( but->val.asstr, old_str, old_len + 1 );
MEM_freeN(old_str);
}
add_numbut(i, TEX, text, 0.0f, max, but->val.asstr, tip);
}
break;
default:
Py_DECREF( pyItem );
return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string or a tuple containing 2 to 5 values." );
}
Py_DECREF( pyItem );
}
if (do_clever_numbuts(title, len, REDRAW))
return EXPP_incr_ret_True();
else
return EXPP_incr_ret_False();
}
/***************************************************************************** /*****************************************************************************
* Function: Method_Image * * Function: Method_Image *
* Python equivalent: Blender.Draw.Image * * Python equivalent: Blender.Draw.Image *

View File

@@ -59,6 +59,10 @@ typedef struct _Button {
char *tooltip; char *tooltip;
} Button; } Button;
#define BINT_TYPE 1
#define BFLOAT_TYPE 2
#define BSTRING_TYPE 3
/* /*
* these are declared in ../BPY_extern.h * these are declared in ../BPY_extern.h

View File

@@ -9,6 +9,7 @@ Draw
B{New}: B{New}:
- access to ASCII values in L{events<Register>} callbacks; - access to ASCII values in L{events<Register>} callbacks;
- 'large' fonts for L{Text} and L{GetStringWidth}. - 'large' fonts for L{Text} and L{GetStringWidth}.
- Pop-up blocks with L{PupBlock}
This module provides access to a B{windowing interface} in Blender. Its widgets This module provides access to a B{windowing interface} in Blender. Its widgets
include many kinds of buttons: push, toggle, menu, number, string, slider, include many kinds of buttons: push, toggle, menu, number, string, slider,
@@ -406,6 +407,50 @@ def PupStrInput(text, default, max = 20):
@return: The text entered by the user or None if none was chosen. @return: The text entered by the user or None if none was chosen.
""" """
def PupBlock(title, sequence):
"""
Display a pop-up block.
Possible formats for the items in the sequence parameter.
(Value are objects created with L{Create})
- string: Defines a label
- (string, Value, string): Defines a toggle button. The first string is the text on the button, the optional second string is the tooltip.
- (string, Value, min, max, string): Defines a numeric or string button, depending on the content of Value. The first string is the text on the button, the optional second string is the tooltip. I{For string, max is the maximum length of the string and min is unused.}
Example::
import Blender
text = Blender.Draw.Create("short text")
f = Blender.Draw.Create(1.0)
i = Blender.Draw.Create(2)
tog = Blender.Draw.Create(0)
block = []
block.append(("Name: ", text, 0, 30, "this is some tool tip"))
block.append("Some Label")
block.append(("Value: ", f, 0.0, 100.0))
block.append(("Value: ", i, 0, 100))
block.append(("Option", tog, "another tooltip"))
retval = Blender.Draw.PupBlock("PupBlock test", block)
print "PupBlock returned", retval
print "text\\t", text
print "float\\t", f
print "int\\t", i
print "toggle\\t", tog
@warning: On cancel, the Value objects are brought back to there initial values except for string values which will still contain the modified values.
@type title: string
@param title: The title of the block.
@param sequence: A sequence defining what the block contains.
The order of the list is the order of appearance, from top down.
@rtype: int
@return: 1 if the pop-up is confirmed, 0 otherwise
"""
def Menu(name, event, x, y, width, height, default, tooltip = None): def Menu(name, event, x, y, width, height, default, tooltip = None):
""" """
Create a new Menu Button object. Create a new Menu Button object.