Adding a floating panel takes several steps, based on how these are handled in

Blender. A summary of how it works:

 

- each window type in Blender can be assigned a 'Panel handler', for example

with a hotkey or pulldown menu event.

- multiple handlers are possible for 1 window

- when a window is drawn, it checks as last step the handlers and draws the

Panels

- event handling for Panel buttons can be done using the main window event

queue

 

In this tutorial we will add a Paint floating panel and will use the 'Properties' panel

from the Image window as our reference.

1. Adding a #define for our new handler name

In include/BIF_space.h we need to define our new handler. Go down to where the

previous handler was defined

 

<ccode>#define IMAGE_HANDLER_PROPERTIES 30 </ccode>

 

and add the line

<ccode> #define IMAGE_HANDLER_PAINT  31</ccode>

 

after it. Now we can reference this event code by name instead of number. Please

note that the handler number doesn't really matter, apart from that it's saved in

a file when a Panel is visible, so when you load a .blend project again the Panel

will show up still.

2. Add detection of Handler

 

Open drawimage.c and locate void image_blockhandlers(ScrArea *sa).

You can see that the blockhandlers of the current screenarea are gone over to

see if they are set and if they are, the function to draw the panel is called.

 

<ccode> for(a=0; a<SPACE_MAXHANDLER; a+=2) {

  switch(sima->blockhandler[a]) {

  case IMAGE_HANDLER_PROPERTIES:

   image_panel_properties(sima->blockhandler[a+1]);

   break;

  }

  /* clear action value for event */

  sima->blockhandler[a+1]= 0;

 }</ccode>

so we need to add a case for our new handler

<ccode> for(a=0; a<SPACE_MAXHANDLER; a+=2) {

  switch(sima->blockhandler[a]) {

  case IMAGE_HANDLER_PROPERTIES:

   image_panel_properties(sima->blockhandler[a+1]);

   break;

  case IMAGE_HANDLER_PAINT:

   image_panel_paint(sima->blockhandler[a+1]);

   break;

  }

  /* clear action value for event */

  sima->blockhandler[a+1]= 0;

 }</ccode>

 

As you can see, we are calling a function called image_panel_paint that we

have not yet defined yet. We will do that next.

3. Add panel drawing code

n drawimage.c we will look at the

image_panel_properties function. We will disect it...

<ccode>static void image_panel_properties(short cntrl) //

IMAGE_HANDLER_PROPERTIES

{

extern VPaint

Gvp; /* from vpaint -

this was copied from the paint panel*/

uiBlock *block;</ccode>

Here we can see that we create a uiBlock* called

block. this will contain our panel.

<ccode>block= uiNewBlock(&curarea->uiblocks,

"image_panel_properties", UI_EMBOSS, UI_HELV,

curarea->win);

</ccode>

Here we initialize our uiblock by passing it the pointer to the current area

uiblocks, give it the name of the function, and set some drawing flags

and tell it where to draw.

<ccode>uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE |

cntrl);</ccode>

Here we add a control bar to the block passing it a

control number that was passed in.

<ccode>uiSetPanelHandler(IMAGE_HANDLER_PROPERTIES); //

for close and esc</ccode>

Here we tell the block what handler it belongs to so

that we can close it.

<ccode>if(uiNewPanel(curarea, block, "Properties", "Image", 10,

230, 318, 204)==0)
return;</ccode>

Now we create a panel inside the block container, if

it is not visible (tabbed, minimized), it returns, otherwise, we

continue.

The rest of the code in the function defines the

contents of the floating panel using standard blender ui components.

So we will define our simple paint panel this

way

<ccode>static void image_panel_paint(short cntrl) /*

IMAGE_HANDLER_PAINT */

{

uiBlock *block;

block= uiNewBlock(&curarea->uiblocks,

"image_panel_paint", UI_EMBOSS,

UI_HELV, curarea->win);

 

uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);

 

uiSetPanelHandler(IMAGE_HANDLER_PAINT); // for close and esc

 

if(uiNewPanel(curarea, block, "Paint", "Image", 10, 230, 318, 04)==0)

return;
/* Here we will define our stuff

*- this was copied from the paint

* panel*/

 

uiBlockBeginAlign(block);

uiDefButF(block, NUMSLI, 0, "R ", 979,160,194,19, &Gvp.r,

0.0, 1.0, B_VPCOLSLI, 0, "The amount of red used for painting");

 

uiDefButF(block, NUMSLI, 0, "G ", 979,140,194,19, &Gvp.g,

0.0, 1.0, B_VPCOLSLI, 0, "The amount of green used for painting");

 

uiDefButF(block, NUMSLI, 0, "B ", 979,120,194,19, &Gvp.b,

0.0, 1.0, B_VPCOLSLI, 0, "The amount of blue used for painting");

 

uiBlockEndAlign(block);
uiDefButF(block, NUMSLI, 0, "Opacity

", 979,100,194,19, &Gvp.a, 0.0, 1.0, 0, 0, "The amount of

pressure on the brush");

 

uiDefButF(block, NUMSLI, 0, "Size ",

979,80,194,19, &Gvp.size, 2.0, 64.0, 0, 0, "The size of the

brush");
uiDefButF(block, COL, B_VPCOLSLI, "",

1176,100,28,80, &(Gvp.r), 0, 0, 0, 0, "");

}

</ccode>

4. Add Activation Code

A simple way to activate a piece of code is with a hotkey. Currently the

properties panel is activated by the Nkey. So we will look at the code that this

calls in space.c it is in the function

<ccode>void winqreadimagespace(ScrArea *sa, void *spacedata,

BWinEvent *evt)</ccode>

looking down to NKEY we find

<ccode> case NKEY:

  if(G.qual==0) {

  

 add_blockhandler(curarea, IMAGE_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);

scrarea_queue_winredraw(curarea);

  }</ccode>

The first call is made to add_blockhandler which passes the current

area(curarea), the handler to add(IMAGE_HANDLER_PROPERTIES) and an

optional flag (UI_PNL_TO_MOUSE) which causes the panel to open at the

location of the mouse. If this last option is left out, the window will open in the

lowest left area it can. After that, the call to scrarea_queue_winredraw queues a

refresh for the current area(curarea).

For this example we will add our paint panel with the Vkey for no particular

reason.

 

<ccode> case VKEY:
  if(G.qual==0) {

  add_blockhandler(curarea, IMAGE_HANDLER_PAINT, 0);

  scrarea_queue_winredraw(curarea);
  }</ccode>

 

Now you could add whatever activation code you want at this point. Either a

hotkey or a menu option or whatever makes you (and Ton and the gang)

happy. This particular panel will not be activated with the V key, but instead be

placed in a menu. But we will leave it at this for the purposes of this tutorial.

At this point, the code should compile and run. Please keep in mind that each

window type ( image, 3d, oops, etc) can currently support only 4 floating panels.

 

Have fun and Happy Coding!