---------------------------------------------------
Blender interface.c API toolkit notes
(july 2003, Ton Roosendaal)
---------------------------------------------------
Contents
1 General notes
1.1 C and H files
2. Windows & Blocks
2.1 Memory allocation
2.2 And how it works internally
3. API for uiBlock
3.1 uiBlock Controlling functions
3.2 Internal function to know
4. API for uiButton
4.1 UiDefBut
1. BUT
2. TOG or TOGN or TOGR
TOG|BIT|
3. TOG3|BIT|
4. ROW
5. SLI or NUMSLI or HSVSLI
6. NUM
7. TEX
8. LABEL
9 SEPR
10. MENU
11. COL
4.2 Icon buttons
12. ICONROW
13. ICONTEXTROW
4.3 pulldown menus / block buttons
14. BLOCK
4.4 specials
15. KEYEVT
16. LINK and INLINK
17. IDPOIN
4.5 uiButton control fuctions
----------------1. General notes
- The API is built with Blender in mind, with some buttons
acting on lists of Blender data.
It was not meant to be available as a separate SDK, nor to
be used for other applications.
- It works with only OpenGL calls, for the full 100%. This means
that it has some quirks
built-in to work with all OS's and OpenGL versions.
Especially frontbuffer drawing is
a continuous point of attention. Buttons can be drawn with
any window matrix. However,
errors can still occor when buttons are created in windows
with non-standard glViewports.
- The code was written to replace the old 1.8 button system, but
under high pressure. Quite
some button methods from the old system were copied for that
reason.
- I tried to design a unified GUI system, which equally works for
pulldown menus, pop up menus,
and normal button layouts. Although it gives nice features
and freedom in design, the code
looks quite hard to understand for that reason. Not all
'normal' pulldown menu features
could be hacked in easily, they just differ too much from
other UI elements. Could be
looked at once...
- During the past period of NaN (beginning of 2002) someone tried
to make a more 'high' level
API for it, with less low level defines and structure info
needed in calling code. I am not
really sure if this was done well... or even finished. In
the bottom of interface.c you can
see the 'new' API which is now used in Blender code. It used
to be so much more simple!
Nevertheless, I will use that convention in this doc.
- Unfinished stuff: the code was scheduled to
be expanded with 'floating blocks' which can
serve as permanent little button-fields in Blender windows.
Think for example of having
an (optional) extra field in the 3d window displaying object
loc/rot/size.
After that, the existing button windows can be reorganized
in such blocks as well, allowing
a user to configure the genereal buttons layout (make
vertical for example).
--------------1.1 C and H files
blender/source/blender/src/interface.c blender/source/blender/include/interface.h blender/source/blender/include/BIF_interface.h
(the previous 2 include files have not been separated fully
yet)
Color and icons stuff has been put in:
(unfinished code, under development)
blender/source/blender/src/resources.c
blender/source/blender/include/BIF_resources.h
Related code:
blender/source/blender/src/toolbox.c (extra GUI elements built on
top of this API)
--------------2. Windows & Blocks
All GUI elements are collected in uiBlocks, which in turn are
linked together in a list that's
part of a Blender Area-window.
uiBlock *block=
uiNewBlock(&curarea->uiblocks,
"stuff", UI_EMBOSSX, UI_HELV, curarea->win);
The next code example makes a new block, and puts it in the
list of blocks of the current active
Area:
uiDoBlocks(&curarea->uiblocks,
event);
This code is usually available in each area-window event queue
handler. You give uiDoBlocks
an event code, and the uiDoBlocks handles whatever is to be
handled. Blocks can be
standard buttons or pull down menus. Can return immediately, or
jump to an internal handling
loop.
2.1 Memory allocation
Important to know is that for this toolkit there's no
difference in "creating blocks" or
"drawing blocks". In fact, for each window redraw all blocks are
created again. Constructing
button interfaces in Blender always happens in the main drawing
function itself.
Memory allocation is handled as follows:
- if in this window a uiBlock with the same name existed, it is
freed
- when you close a window (or blender) the uiBlocks get
freed.
- when you duplicate (split) a window, the uiBlocks get
copied
2.2 And how it works internally
With a call to uiDoblocks, all blocks in the current active
window are evaluated.
It walks through the lists in a rather complex
manner:
- while(looping)
- for each block
- call uiDoBlock (handles buttons for single
block)
- (end for)
- while first block is a menu
- if block is a menu and not
initialized:
- initalize 'saveunder'
- draw it
- get event from queue
- call uiDoBlock (handles buttons for single
block)
- if return "end" from uiDoBlock
restore 'saveunder's
free all menu blocks
exit from loop
- do tooltip if nothing has happened
- (end while)
- if there was menu, it does this loop once more
(when you click outside a menu, at another
button)
- (end while)
- do tooltip if nothing has happened
-------------3. API for uiBlock
Create a new buttons block, and link it to the
window:
uiBlock *uiNewBlock(ListBase *lb, char *name, short dt, short
font, short win)
ListBase *lb pointer to list basis, where the block will
be appended to (blenlib)
char *name unique name to identify the block. When
the name exists in the list,
the old uiBlock gets freed.
short dt drawtype. See below
short font font id number
short win blender area-window id
drawtype:
UI_EMBOSSX 0 UI_EMBOSSW 1 UI_EMBOSSN 2 UI_EMBOSSF 3 UI_EMBOSSM 4 UI_EMBOSSP 5
font:
UI_HELV 0 UI_HELVB 1 With the new truetype option in Blender, this is used for all font
families
When a uiBlock is created, each uiButton that is defined gets
the uiBlock properties.
Changing Block properties inbetween will affact uiButtons defined
thereafter.
----------3.1 uiBlock Controlling
functions:
void uiDrawBlock(block) draws the block
void uiBlockSetCol(uiBlock *block, int col)
col:
BUTGREY,
BUTGREEN,
BUTBLUE,
BUTSALMON,
MIDGREY,
BUTPURPLE,
void uiBlockSetEmboss(uiBlock *block, int emboss)
changes drawtype
void uiBlockSetDirection(uiBlock *block, int
direction) for pop-up and pulldown menus:
direction:
UI_TOP UI_DOWN UI_LEFT UI_RIGHT
void uiBlockSetXOfs(uiBlock *block, int xofs)
for menus, offset from parent
void uiBlockSetButmFunc(uiBlock *block, void (*menufunc)(void
*arg, int event), void *arg)
sets function to be handled when a menu-block is marked
"OK"
void uiAutoBlock(uiBlock *block, float minx, float miny, float
sizex, float sizey, UI_BLOCK_ROWS)
Sets the buttons in this block to automatically align,
and fit within boundaries.
Internally it allows multiple collums or rows as well. Only
'row order' has been implemented.
The uiDefBut definitions don't need coordinates as input
here, but instead:
- first value (x1) to indicate row number
- width and height values (if filled in) will be used to
define a relative width/height.
A call to uiDrawBlock will invoke the calculus to fit in all
buttons.
---------- 3.2 Internal function to
know:
These flags used to be accessible from outside of interface.c.
Currently it is only
used elsewhere by toolbox.c, so it can be considered 'internal'
somewhat.
void uiBlockSetFlag(uiBlock *block, int flag) UI_BLOCK_LOOP 1 a sublooping block,
drawn in frontbuffer, i.e. menus
UI_BLOCK_REDRAW 2 block needs a
redraw
UI_BLOCK_RET_1 4 block is closed when
an event happens with value '1' (press key, not for mouse)
UI_BLOCK_BUSY 8 internal
UI_BLOCK_NUMSELECT 16 keys 1-2-...-9-0 can be
used to select items
UI_BLOCK_ENTER_OK 32 enter key closes block
with "OK"
(these values are being set within the interface.c and toolbox.c
code.)
-------------4. API for uiButton
In Blender a button can do four things:
- directly visualize data, and write to it.
- put event codes (shorts) back in the queue, to be handled
- call a user-defined function pointer (while being pressed,
etc)
- create and call another block (i.e. menu)
Internally, each button or menu item is a 'uiButton', with a
generic API and handling:
ui_def_but(block, type, retval, str, x1, y1, x2, y2, poin, min,
max, a1, a2, tip);
Beacause a lot of obscure generic (re-use) happens here,
translation calls have been made
for each most button types individually.
-----------4.1 UiDefBut
uiBut *UiDefBut[CSIF]( uiBlock *block, int type, int
retval, char *str,
short x1, short y1, short x2, short y2,
xxxx *poin,
float min, float max, float a1, float
a2, char *tip)
UiDefButC operatates on char
UiDefButS operatates on short
UiDefButI operatates on int
UiDefButF operatates on float
*block: current uiBlock
pointer
type: see below
retval: return value, which is put back
in queue
*str: button name
x1, y1: coordinates of left-lower
corner
x1, y2: width, height
*poin: pointer to char, short, int,
float
min, max used for slider buttons
a1, a2 extra info for some buttons
*tip: tooltip string
type:
1. BUT
Activation button. (like "Render")
Passing on a pointer is not needed
2. TOG or TOGN or TOGR
Toggle button (like "Lock")
The pointer value is set either at 0 or 1
If pressed, it calls the optional function with arguments
provided.
Type TOGN: works negative, when pressed it
sets at 0
Type TOGR: is part of a row, redraws
automatically all buttons with same *poin
"|BIT|"
When added to type, it works on a single bit
(lowest order
bit: nr = '0')
3. TOG3|BIT|
A toggle with 3 values!
Can be only used for short *poin.
In the third toggle setting, the bit
of *( poin+1) is set.
4. ROW
Button that's part of a row.
in "min" you set a row-id number, in "max" the value you want
*poin to be
assigned when you press the button. Always pass on these
values as floats.
When this button is pressed, it sets the "max" value to
*poin, and redraws
all buttons with the same row-id number.
5. SLI or NUMSLI or HSVSLI
Slider, number-slider or hsv-slider button.
"min" and "max" are to clamp the value to.
If you want a button type "Col" to be updated, make 'a1'
equal to 'retval'
from the COL button.
6. NUM
Number button
Set the clamping values 'min' and 'max' always as
float.
For UiDefButF, set a 'step' in 'a1', in 1/100's. The step
value is the increment or
decrement when you click once on the right or left side of a
button.
The optional button function is additionally called for each
change of the *poin value.
7. TEX
Text string button.
Pointertype is standard a char. Value 'max' is length of
string (pass as float).
When button is left with ESC, it doesn't put the 'retval' at
the queue.
8. LABEL
Label button.
Only displays text.
If 'min' is set at 1.0, the text is printed in white.
9 SEPR
A separator line, typically used within pulldown menus.
10. MENU
Menu button.
The syntax of the string in *name defines the menu
items:
- %t means the previous text becomes the title
- item separator is '|'
- return values are indicated with %x[nr]
(i.e: %x12).
without returnvalues, the first item gets value 0
(incl. title!)
Example: "Do something %t| turn left %2| turn
right %1| nothing %0"
11. COL
A special button that only visualizes a RGB value
In 'retval' you can put a code, which is used to identify for
sliders if it needs
redraws while using the sliders. Check button '5'.
As *poin you input the pointer to the 'r' value, 'g' and 'b'
are supposed to be
next to that.
------------4.2 Icon buttons
Instead of a 'name', all buttons as described for uiDefBut
also can have an icon:
uiBut *uiDefIconBut(uiBlock *block, int type, int retval, int
icon,
short x1, short y1, short x2, short y2, void
*poin,
float min, float max, float a1, float a2, char *tip)
Same syntax and types available as previous uiDefBut,
but now with an icon code
instead of a name. THe icons are numbered in
resources.c
uiBut *uiDefIconTextButF(uiBlock *block, int type, int retval,
int icon, char *str,
short x1, short y1, short x2, short y2, float
*poin,
float min, float max, float a1, float a2, char *tip)
Same again, but now with an icon and string as button
name.
Two special icon buttons are available in
Blender:
12. ICONROW
(uiDefIconBut)
This button pops up a vertical menu with a row of icons to
choose from.
'max' = amount of icons. The icons are supposed to be ordered
in a sequence
It writes in *poin which item in the menu was choosen
(starting with 0).
13. ICONTEXTROW
(uiDefIconTextBut)
Same as previous, but with the texts next to it.
-----------4.3 pulldown menus / block buttons
14. BLOCK
void uiDefBlockBut(uiBlock *block, uiBlockFuncFP func, void *arg,
char *str,
short x1, short y1, short x2, short y2, char *tip)
This button creates a new block when pressed. The
function argument 'func' is called
to take care of this. An example func:
static uiBlock *info_file_importmenu(void *arg_unused)
{
uiBlock *block;
short yco= 0, xco = 20;
block=
uiNewBlock(&curarea->uiblocks,
"importmenu", UI_EMBOSSW, UI_HELV,
G.curscreen->mainwin);
uiBlockSetXOfs(block, -40); // offset to parent
button
uiDefBut(block, LABEL, 0, "VRML 2.0 options", xco, yco,
125, 19, NULL, 0.0, 0.0, 0, 0, "");
uiDefButS(block, TOG|BIT|0, 0, "SepLayers", xco,
yco-=20, 75, 19, &U.vrmlflag, 0.0, 0.0, 0, 0,
"");
uiDefButS(block, TOG|BIT|1, 0, "Scale 1/100", xco,
yco-=20, 75, 19, &U.vrmlflag, 0.0, 0.0, 0, 0,
"");
uiDefButS(block, TOG|BIT|2, 0, "Two Sided", xco,
yco-=20, 75, 19, &U.vrmlflag, 0.0, 0.0, 0, 0,
"");
uiBlockSetDirection(block, UI_RIGHT);
uiTextBoundsBlock(block, 50); // checks for
fontsize
return block;
}
The uiDef coordinates here are only relative. When this
function is called, the interface
code automatically makes sure the buttons fit in the menu
nicely.
Inside a menu uiBlock, other uiBlocks can be invoked to make
a hierarchical menu.
-----------4.4 specials
15. KEYEVT
void uiDefKeyevtButS(uiBlock *block, int retval, char
*str,
short x1, short y1, short x2, short y2, short *spoin,
char *tip)
A special button, which stores a keyvalue in *spoin.
When the button is pressed,
it displays the text 'Press any Key'. A keypress then stores
the value.
16. LINK and INLINK
These button present a method of linking data in
Blender, by drawing a line from one
icon to another. It consists of two button
types:
LINK, the 'linking from' part, can be:
- a single pointer to data (only one line allowed)
- an array of pointers to data. The LINK buttons system keeps track of allocating
space for the array, and set the correct pointers in
it.
INLINK, the 'linking to' part activates creating a link, when
a user releases the mouse
cursor over it, while dragging a line from the LINK
button.
These buttons are defined as follows:
uiBut but= uiDefIconBut(block, LINK, 0, ICON_LINK, x1, y1, w,
h, NULL, 0, 0, 0, 0, "");
uiSetButLink(but, void **pt, void ***ppt, short *totlink,
short fromcode, short tocode);
**pt: pointer to pointer (only one link
allowed)
***ppt: pointer to pointerpointer (an array
of pointers)
(Either one of these values should be NULL)
fromcode: (currently unused)
tocode: a short indicating which blocks it
can link to.
uiDefIconBut(block, INLINK, 0, ICON_INLINK, x1, y1, w, h, void
*poin, short fromcode, 0, 0, 0, "");
poin: the pointer of the datablock you want
to create links to
fromcode: a short identifying which LINK
buttons can connect to it
17. IDPOIN
void uiDefIDPoinBut(uiBlock *block, uiIDPoinFuncFP func, int
retval, char *str,
short x1, short y1, short x2, short y2, void
*idpp, char *tip)
The ID struct is a generic part in structs like Object,
Material, Mesh, etc.
Most linking options in Blender happens using ID's. (Mesh
-> Material).
This special button in Blender visualizes an ID pointer with
its name. Typing in
a new name, changes the pointer. For most ID types in Blender
functions have been
written already, needed by this button, to check validity of
names, and assign the pointer.
(BTW: the 'void *idpp' has to be a pointer to
the ID pointer!)
Example function that can be put in
'func':
void test_scriptpoin_but(char *name, ID **idpp)
{
ID *id;
id= G.main->text.first;
while(id) {
if( strcmp(name, id->name+2)==0 )
{
*idpp= id;
return;
}
id= id->next;
}
*idpp= 0;
}
------------- 4.5 uiButton control fuctions
void uiButSetFunc(uiBut *but, void (*func)(void *arg1, void *arg2),
void *arg1, void *arg2)
When the button is pressed and released, it calls this
function, with the 2 arguments.
void uiButSetFlag(uiBut *but, int flag)
set a flag for further control of button
behaviour:
flag:
UI_TEXT_LEFT
int uiButGetRetVal(uiBut *but)
gives return value