Adding a floating panel takes several steps, we will add a Paint floating panel and will use the 'Properties' panel from the image window as our reference.

 

So we have several things to do before we can make a panel work. So here we go.

 

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

 

#define IMAGE_HANDLER_PROPERTIES 30 

 

and add the line

 
#define IMAGE_HANDLER_PAINT  31

 

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

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.

 

 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;
 }

so we need to add a case for our new handler

 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;
 }

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

In drawimage.c we will look at the image_panel_properties function. We will disect it...

static void image_panel_properties(short cntrl) // IMAGE_HANDLER_PROPERTIES
{
 extern VPaint Gvp;         /* from vpaint - this was copied from the paint panel*/
 uiBlock *block;

Here we can see that we create a uiBlock* called block. this will contain our panel.

 block= uiNewBlock(&curarea->uiblocks, "image_panel_properties", UI_EMBOSS, UI_HELV, curarea->win);

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.

 uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);

Here we add a control bar to the block passing it a control number that was passed in.

 uiSetPanelHandler(IMAGE_HANDLER_PROPERTIES);  // for close and esc

Here we tell the block what handler it belongs to so that we can close it.

 if(uiNewPanel(curarea, block, "Properties", "Image", 10, 230, 318, 204)==0)
 return;

Now we create a panel inside the block container, if it is not successful, 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

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, 204)==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, "");
}
 

 

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

void winqreadimagespace(ScrArea *sa, void *spacedata, BWinEvent *evt)

looking down to NKEY we find

 case NKEY:
  if(G.qual==0) {
   add_blockhandler(curarea, IMAGE_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
   scrarea_queue_winredraw(curarea);
  }

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.

 

 case VKEY:
  if(G.qual==0) {
  add_blockhandler(curarea, IMAGE_HANDLER_PAINT, 0);
  scrarea_queue_winredraw(curarea);
  }

 

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!