svn merge -r 21041:21301 https://svn.blender.org/svnroot/bf-blender/branches/blender2...
[blender.git] / source / blender / editors / interface / interface_templates.c
index 15c0619e4e16879b1d0fa4a186fbe88b8c2be61c..8f1d57b28ed3cbcf0ca4ab2c880890970ebfa173 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * $Id: interface_templates.c 21247 2009-06-29 21:50:53Z jaguarandi $
+ * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
 
 #include "MEM_guardedalloc.h"
 
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
 #include "BLI_string.h"
 
 #include "BKE_context.h"
+#include "BKE_icons.h"
+#include "BKE_global.h"
 #include "BKE_library.h"
 #include "BKE_utildefines.h"
 
@@ -43,6 +48,7 @@
 
 #include "UI_interface.h"
 #include "UI_resources.h"
+#include "interface_intern.h"
 
 void ui_template_fix_linking()
 {
@@ -58,107 +64,55 @@ void uiTemplateHeader(uiLayout *layout, bContext *C)
        ED_area_header_standardbuttons(C, block, 0);
 }
 
-/******************* Header ID Template ************************/
+/********************** Search Callbacks *************************/
 
 typedef struct TemplateID {
        PointerRNA ptr;
        PropertyRNA *prop;
 
-       int flag;
-       short browse;
-
-       char newop[256];
-       char openop[256];
-       char unlinkop[256];
-       
-       short idtype;
+       ListBase *idlb;
 } TemplateID;
 
-static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
+/* Search browse menu, assign  */
+static void id_search_call_cb(struct bContext *C, void *arg_template, void *item)
 {
-       TemplateID *template= (TemplateID*)arg_litem;
-       PointerRNA idptr= RNA_property_pointer_get(&template->ptr, template->prop);
-       ID *id= idptr.data;
-       int event= GET_INT_FROM_POINTER(arg_event);
-       
-       if(event == UI_ID_BROWSE && template->browse == 32767)
-               event= UI_ID_ADD_NEW;
-       else if(event == UI_ID_BROWSE && template->browse == 32766)
-               event= UI_ID_OPEN;
+       TemplateID *template= (TemplateID*)arg_template;
 
-       switch(event) {
-               case UI_ID_BROWSE:
-                       printf("warning, id browse shouldnt come here\n");
-                       break;
-               case UI_ID_DELETE:
-                       memset(&idptr, 0, sizeof(idptr));
-                       RNA_property_pointer_set(&template->ptr, template->prop, idptr);
-                       RNA_property_update(C, &template->ptr, template->prop);
-                       break;
-               case UI_ID_FAKE_USER:
-                       if(id) {
-                               if(id->flag & LIB_FAKEUSER) id->us++;
-                               else id->us--;
-                       }
-                       else return;
-                       break;
-               case UI_ID_PIN:
-                       break;
-               case UI_ID_ADD_NEW:
-                       WM_operator_name_call(C, template->newop, WM_OP_INVOKE_REGION_WIN, NULL);
-                       break;
-               case UI_ID_OPEN:
-                       WM_operator_name_call(C, template->openop, WM_OP_INVOKE_REGION_WIN, NULL);
-                       break;
-#if 0
-               case UI_ID_ALONE:
-                       if(!id || id->us < 1)
-                               return;
-                       break;
-               case UI_ID_LOCAL:
-                       if(!id || id->us < 1)
-                               return;
-                       break;
-               case UI_ID_AUTO_NAME:
-                       break;
-#endif
-       }
-}
-
-/* ID Search browse menu, assign  */
-static void id_search_call_cb(struct bContext *C, void *arg_litem, void *item)
-{
+       /* ID */
        if(item) {
-               TemplateID *template= (TemplateID*)arg_litem;
-               PointerRNA idptr= RNA_property_pointer_get(&template->ptr, template->prop);
+               PointerRNA idptr;
 
                RNA_id_pointer_create(item, &idptr);
                RNA_property_pointer_set(&template->ptr, template->prop, idptr);
                RNA_property_update(C, &template->ptr, template->prop);
-       }       
+       }
 }
 
 /* ID Search browse menu, do the search */
-static void id_search_cb(const struct bContext *C, void *arg_litem, char *str, uiSearchItems *items)
+static void id_search_cb(const struct bContext *C, void *arg_template, char *str, uiSearchItems *items)
 {
-       TemplateID *template= (TemplateID*)arg_litem;
-       ListBase *lb= wich_libbase(CTX_data_main(C), template->idtype);
+       TemplateID *template= (TemplateID*)arg_template;
+       Scene *scene= CTX_data_scene(C);
+       ListBase *lb= template->idlb;
        ID *id;
-       
+       int iconid;
+
+       /* ID listbase */
        for(id= lb->first; id; id= id->next) {
-               
-               if(BLI_strcasestr(id->name+2, str)) {
-                       if(0==uiSearchItemAdd(items, id->name+2, id))
+               iconid= ui_id_icon_get(scene, id);
+
+               if(BLI_strcasestr(id->name+2, str))
+                       if(!uiSearchItemAdd(items, id->name+2, id, iconid))
                                break;
-               }
        }
 }
 
 /* ID Search browse menu, open */
-static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
+static uiBlock *search_menu(bContext *C, ARegion *ar, void *arg_litem)
 {
        static char search[256];
        static TemplateID template;
+       PointerRNA idptr;
        wmEvent event;
        wmWindow *win= CTX_wm_window(C);
        uiBlock *block;
@@ -169,6 +123,9 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
        /* arg_litem is malloced, can be freed by parent button */
        template= *((TemplateID*)arg_litem);
        
+       /* get active id for showing first item */
+       idptr= RNA_property_pointer_get(&template.ptr, template.prop);
+
        block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
        uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1);
        
@@ -176,7 +133,7 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
        uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
        
        but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, "");
-       uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb);
+       uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
        
        uiBoundsBlock(block, 6);
        uiBlockSetDirection(block, UI_DOWN);    
@@ -192,47 +149,73 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
        return block;
 }
 
-/* ****************** */
+/************************ ID Template ***************************/
 
+static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
+{
+       TemplateID *template= (TemplateID*)arg_litem;
+       PointerRNA idptr= RNA_property_pointer_get(&template->ptr, template->prop);
+       ID *id= idptr.data;
+       int event= GET_INT_FROM_POINTER(arg_event);
+       
+       switch(event) {
+               case UI_ID_BROWSE:
+               case UI_ID_PIN:
+                       printf("warning, id event %d shouldnt come here\n", event);
+                       break;
+               case UI_ID_OPEN:
+               case UI_ID_ADD_NEW:
+                       if(template->idlb->last) {
+                               RNA_id_pointer_create(template->idlb->last, &idptr);
+                               RNA_property_pointer_set(&template->ptr, template->prop, idptr);
+                               RNA_property_update(C, &template->ptr, template->prop);
+                       }
+                       break;
+               case UI_ID_DELETE:
+                       memset(&idptr, 0, sizeof(idptr));
+                       RNA_property_pointer_set(&template->ptr, template->prop, idptr);
+                       RNA_property_update(C, &template->ptr, template->prop);
+                       break;
+               case UI_ID_FAKE_USER:
+                       if(id) {
+                               if(id->flag & LIB_FAKEUSER) id->us++;
+                               else id->us--;
+                       }
+                       else return;
+                       break;
+#if 0
+               case UI_ID_ALONE:
+                       if(!id || id->us < 1)
+                               return;
+                       break;
+               case UI_ID_LOCAL:
+                       if(!id || id->us < 1)
+                               return;
+                       break;
+               case UI_ID_AUTO_NAME:
+                       break;
+#endif
+       }
+}
 
-static void template_header_ID(bContext *C, uiBlock *block, TemplateID *template, StructRNA *type)
+static void template_ID(bContext *C, uiBlock *block, TemplateID *template, StructRNA *type, int flag, char *newop, char *unlinkop)
 {
        uiBut *but;
        PointerRNA idptr;
        ListBase *lb;
 
        idptr= RNA_property_pointer_get(&template->ptr, template->prop);
-       lb= wich_libbase(CTX_data_main(C), template->idtype);
+       lb= template->idlb;
+
+       uiBlockBeginAlign(block);
 
        if(idptr.type)
                type= idptr.type;
        if(type)
                uiDefIconBut(block, LABEL, 0, RNA_struct_ui_icon(type), 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
 
-       uiBlockBeginAlign(block);
-       if(template->flag & UI_ID_BROWSE) {
-               /*
-               char *extrastr, *str;
-               
-               if((template->flag & UI_ID_ADD_NEW) && (template->flag & UI_ID_OPEN))
-                       extrastr= "OPEN NEW %x 32766 |ADD NEW %x 32767";
-               else if(template->flag & UI_ID_ADD_NEW)
-                       extrastr= "ADD NEW %x 32767";
-               else if(template->flag & UI_ID_OPEN)
-                       extrastr= "OPEN NEW %x 32766";
-               else
-                       extrastr= NULL;
-
-               duptemplate= MEM_dupallocN(template);
-               IDnames_to_pupstring(&str, NULL, extrastr, lb, idptr.data, &duptemplate->browse);
-
-               but= uiDefButS(block, MENU, 0, str, 0, 0, UI_UNIT_X, UI_UNIT_Y, &duptemplate->browse, 0, 0, 0, 0, "Browse existing choices, or add new");
-               uiButSetNFunc(but, template_id_cb, duptemplate, SET_INT_IN_POINTER(UI_ID_BROWSE));
-       
-               MEM_freeN(str);
-               */
-               uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X, UI_UNIT_Y, "Browse ID data");
-       }
+       if(flag & UI_ID_BROWSE)
+               uiDefBlockButN(block, search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X, UI_UNIT_Y, "Browse ID data");
 
        /* text button with name */
        if(idptr.data) {
@@ -244,11 +227,12 @@ static void template_header_ID(bContext *C, uiBlock *block, TemplateID *template
                uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
        }
        
-       if(template->flag & UI_ID_ADD_NEW) {
+       if(flag & UI_ID_ADD_NEW) {
                int w= idptr.data?UI_UNIT_X:UI_UNIT_X*6;
                
-               if(template->newop[0]) {
-                       but= uiDefIconTextButO(block, BUT, template->newop, WM_OP_EXEC_REGION_WIN, ICON_ZOOMIN, "Add New", 0, 0, w, UI_UNIT_Y, NULL);
+               if(newop) {
+                       but= uiDefIconTextButO(block, BUT, newop, WM_OP_EXEC_REGION_WIN, ICON_ZOOMIN, "Add New", 0, 0, w, UI_UNIT_Y, NULL);
+                       uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
                }
                else {
                        but= uiDefIconTextBut(block, BUT, 0, ICON_ZOOMIN, "Add New", 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
@@ -257,9 +241,9 @@ static void template_header_ID(bContext *C, uiBlock *block, TemplateID *template
        }
        
        /* delete button */
-       if(idptr.data && (template->flag & UI_ID_DELETE)) {
-               if(template->unlinkop[0]) {
-                       but= uiDefIconButO(block, BUT, template->unlinkop, WM_OP_EXEC_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+       if(idptr.data && (flag & UI_ID_DELETE)) {
+               if(unlinkop) {
+                       but= uiDefIconButO(block, BUT, unlinkop, WM_OP_EXEC_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
                }
                else {
                        but= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
@@ -270,12 +254,13 @@ static void template_header_ID(bContext *C, uiBlock *block, TemplateID *template
        uiBlockEndAlign(block);
 }
 
-void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop)
+void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *unlinkop)
 {
        TemplateID *template;
        uiBlock *block;
        PropertyRNA *prop;
        StructRNA *type;
+       int flag;
 
        if(!ptr->data)
                return;
@@ -290,26 +275,19 @@ void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname
        template= MEM_callocN(sizeof(TemplateID), "TemplateID");
        template->ptr= *ptr;
        template->prop= prop;
-       template->flag= UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE;
 
-       if(newop) {
-               template->flag |= UI_ID_ADD_NEW;
-               BLI_strncpy(template->newop, newop, sizeof(template->newop));
-       }
-       if(openop) {
-               template->flag |= UI_ID_OPEN;
-               BLI_strncpy(template->openop, openop, sizeof(template->openop));
-       }
-       if(unlinkop)
-               BLI_strncpy(template->unlinkop, unlinkop, sizeof(template->unlinkop));
+       flag= UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE;
+
+       if(newop)
+               flag |= UI_ID_ADD_NEW;
 
        type= RNA_property_pointer_type(ptr, prop);
-       template->idtype = RNA_type_to_ID_code(type);
+       template->idlb= wich_libbase(CTX_data_main(C), RNA_type_to_ID_code(type));
 
-       if(template->idtype) {
+       if(template->idlb) {
                uiLayoutRow(layout, 1);
                block= uiLayoutGetBlock(layout);
-               template_header_ID(C, block, template, type);
+               template_ID(C, block, template, type, flag, newop, unlinkop);
        }
 
        MEM_freeN(template);
@@ -362,6 +340,15 @@ static void modifiers_del(bContext *C, void *ob_v, void *md_v)
        BKE_reports_clear(&reports);
 }
 
+static void modifiers_activate(bContext *C, void *ob_v, void *md_v)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= ob_v;
+
+       WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
+       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+}
+
 static void modifiers_moveUp(bContext *C, void *ob_v, void *md_v)
 {
        Scene *scene= CTX_data_scene(C);
@@ -555,7 +542,10 @@ static uiLayout *draw_modifier(uiLayout *layout, Object *ob, ModifierData *md, i
                uiBlockSetEmboss(block, UI_EMBOSSN);
                uiDefIconButBitI(block, ICONTOG, eModifierMode_Expanded, 0, ICON_TRIA_RIGHT, 0, 0, UI_UNIT_X, UI_UNIT_Y, &md->mode, 0.0, 0.0, 0.0, 0.0, "Collapse/Expand Modifier");
        }
-
+       
+       /* modifier-type icon */
+       uiDefIconBut(block, BUT, 0, RNA_struct_ui_icon(ptr.type), 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Current Modifier Type");
+       
        uiBlockSetEmboss(block, UI_EMBOSS);
        
        if (isVirtual) {
@@ -566,14 +556,16 @@ static uiLayout *draw_modifier(uiLayout *layout, Object *ob, ModifierData *md, i
                uiButSetFunc(but, modifiers_convertToReal, ob, md);
        } else {
                uiBlockBeginAlign(block);
-               uiDefBut(block, TEX, 0, "", 0, 0, buttonWidth-60, UI_UNIT_Y, md->name, 0.0, sizeof(md->name)-1, 0.0, 0.0, "Modifier name"); 
+               uiDefBut(block, TEX, 0, "", 0, 0, buttonWidth-40, UI_UNIT_Y, md->name, 0.0, sizeof(md->name)-1, 0.0, 0.0, "Modifier name"); 
 
                /* Softbody not allowed in this situation, enforce! */
                if (((md->type!=eModifierType_Softbody && md->type!=eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) && (md->type!=eModifierType_Surface)) {
                        uiDefIconButBitI(block, TOG, eModifierMode_Render, 0, ICON_SCENE, 0, 0, 19, UI_UNIT_Y,&md->mode, 0, 0, 1, 0, "Enable modifier during rendering");
                        but= uiDefIconButBitI(block, TOG, eModifierMode_Realtime, 0, ICON_VIEW3D, 0, 0, 19, UI_UNIT_Y,&md->mode, 0, 0, 1, 0, "Enable modifier during interactive display");
+                       uiButSetFunc(but, modifiers_activate, ob, md);
                        if (mti->flags&eModifierTypeFlag_SupportsEditmode) {
-                               uiDefIconButBitI(block, TOG, eModifierMode_Editmode, 0, ICON_EDITMODE_HLT, 0, 0, 19, UI_UNIT_Y,&md->mode, 0, 0, 1, 0, "Enable modifier during Editmode (only if enabled for display)");
+                               but= uiDefIconButBitI(block, TOG, eModifierMode_Editmode, 0, ICON_EDITMODE_HLT, 0, 0, 19, UI_UNIT_Y,&md->mode, 0, 0, 1, 0, "Enable modifier during Editmode (only if enabled for display)");
+                               uiButSetFunc(but, modifiers_activate, ob, md);
                        }
                }
                uiBlockEndAlign(block);
@@ -1490,3 +1482,264 @@ void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, char *propname)
                }
        }
 }
+
+
+/************************* List Template **************************/
+
+ListBase uiTemplateList(uiLayout *layout, PointerRNA *ptr, char *propname, PointerRNA *activeptr, char *activepropname, int rows, int columns, int compact)
+{
+       CollectionPointerLink *link;
+       PropertyRNA *prop= NULL, *activeprop;
+       PropertyType type, activetype;
+       uiLayout *box, *row, *col;
+       uiBlock *block;
+       uiBut *but;
+       Panel *pa;
+       ListBase lb;
+       char *name, str[32];
+       int i= 0, activei= 0, len, items, found, min, max;
+
+       lb.first= lb.last= NULL;
+       
+       /* validate arguments */
+       block= uiLayoutGetBlock(layout);
+       pa= block->panel;
+
+       if(!pa) {
+               printf("uiTemplateList: only works inside a panel.\n");
+               return lb;
+       }
+
+       if(!activeptr->data)
+               return lb;
+       
+       if(ptr->data) {
+               prop= RNA_struct_find_property(ptr, propname);
+               if(!prop) {
+                       printf("uiTemplateList: property not found: %s\n", propname);
+                       return lb;
+               }
+       }
+
+       activeprop= RNA_struct_find_property(activeptr, activepropname);
+       if(!activeprop) {
+               printf("uiTemplateList: property not found: %s\n", activepropname);
+               return lb;
+       }
+
+       if(prop) {
+               type= RNA_property_type(prop);
+               if(type != PROP_COLLECTION) {
+                       printf("uiTemplateList: expected collection property.\n");
+                       return lb;
+               }
+       }
+
+       activetype= RNA_property_type(activeprop);
+       if(activetype != PROP_INT) {
+               printf("uiTemplateList: expected integer property.\n");
+               return lb;
+       }
+
+       /* get active data */
+       activei= RNA_property_int_get(activeptr, activeprop);
+
+       if(compact) {
+               /* compact layout */
+               found= 0;
+
+               row= uiLayoutRow(layout, 1);
+
+               if(ptr->data && prop) {
+                       /* create list items */
+                       RNA_PROP_BEGIN(ptr, itemptr, prop) {
+                               found= (activei == i);
+
+                               if(found) {
+                                       /* create button */
+                                       name= RNA_struct_name_get_alloc(&itemptr, NULL, 0);
+                                       if(name) {
+                                               uiItemL(row, name, RNA_struct_ui_icon(itemptr.type));
+                                               MEM_freeN(name);
+                                       }
+
+                                       /* add to list to return */
+                                       link= MEM_callocN(sizeof(CollectionPointerLink), "uiTemplateList return");
+                                       link->ptr= itemptr;
+                                       BLI_addtail(&lb, link);
+                               }
+
+                               i++;
+                       }
+                       RNA_PROP_END;
+               }
+
+               /* if not found, add in dummy button */
+               if(i == 0)
+                       uiItemL(row, "", 0);
+
+               /* next/prev button */
+               sprintf(str, "%d :", i);
+               but= uiDefIconTextButR(block, NUM, 0, 0, str, 0,0,UI_UNIT_X*5,UI_UNIT_Y, activeptr, activepropname, 0, 0, 0, 0, 0, "");
+               if(i == 0)
+                       uiButSetFlag(but, UI_BUT_DISABLED);
+       }
+       else {
+               /* default rows/columns */
+               if(rows == 0)
+                       rows= 5;
+               if(columns == 0)
+                       columns= 1;
+
+               /* layout */
+               box= uiLayoutBox(layout);
+               row= uiLayoutRow(box, 0);
+               col = uiLayoutColumn(row, 1);
+
+               uiBlockSetEmboss(block, UI_EMBOSSN);
+
+               /* init numbers */
+               RNA_property_int_range(activeptr, activeprop, &min, &max);
+
+               len= max - min + 1;
+               items= rows*columns;
+
+               pa->list_scroll= MIN2(pa->list_scroll, len-items);
+               pa->list_scroll= MAX2(pa->list_scroll, 0);
+
+               if(ptr->data && prop) {
+                       /* create list items */
+                       RNA_PROP_BEGIN(ptr, itemptr, prop) {
+                               if(i >= pa->list_scroll && i<pa->list_scroll+items) {
+                                       name= RNA_struct_name_get_alloc(&itemptr, NULL, 0);
+
+                                       if(name) {
+                                               /* create button */
+                                               but= uiDefIconTextButR(block, ROW, 0, RNA_struct_ui_icon(itemptr.type), name, 0,0,UI_UNIT_X*10,UI_UNIT_Y, activeptr, activepropname, 0, 0, i, 0, 0, "");
+                                               uiButSetFlag(but, UI_ICON_LEFT|UI_TEXT_LEFT);
+
+                                               MEM_freeN(name);
+                                       }
+
+                                       /* add to list to return */
+                                       link= MEM_callocN(sizeof(CollectionPointerLink), "uiTemplateList return");
+                                       link->ptr= itemptr;
+                                       BLI_addtail(&lb, link);
+                               }
+
+                               i++;
+                       }
+                       RNA_PROP_END;
+               }
+
+               /* add dummy buttons to fill space */
+               while(i < pa->list_scroll+items) {
+                       if(i >= pa->list_scroll)
+                               uiItemL(col, "", 0);
+                       i++;
+               }
+
+               uiBlockSetEmboss(block, UI_EMBOSS);
+
+               /* add scrollbar */
+               if(len > items) {
+                       col= uiLayoutColumn(row, 0);
+                       uiDefButI(block, SCROLL, 0, "", 0,0,UI_UNIT_X*0.75,UI_UNIT_Y*items, &pa->list_scroll, 0, len-items, items, 0, "");
+               }
+       }
+
+       /* return items in list */
+       return lb;
+}
+
+/************************* Operator Search Template **************************/
+
+static void operator_call_cb(struct bContext *C, void *arg1, void *arg2)
+{
+       wmOperatorType *ot= arg2;
+       
+       if(ot)
+               WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL);
+}
+
+static void operator_search_cb(const struct bContext *C, void *arg, char *str, uiSearchItems *items)
+{
+       wmOperatorType *ot = WM_operatortype_first();
+       
+       for(; ot; ot= ot->next) {
+               
+               if(BLI_strcasestr(ot->name, str)) {
+                       if(ot->poll==NULL || ot->poll((bContext *)C)) {
+                               char name[256];
+                               int len= strlen(ot->name);
+                               
+                               /* display name for menu, can hold hotkey */
+                               BLI_strncpy(name, ot->name, 256);
+                               
+                               /* check for hotkey */
+                               if(len < 256-6) {
+                                       if(WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, &name[len+1], 256-len-1))
+                                               name[len]= '|';
+                               }
+                               
+                               if(0==uiSearchItemAdd(items, name, ot, 0))
+                                       break;
+                       }
+               }
+       }
+}
+
+void uiTemplateOperatorSearch(uiLayout *layout)
+{
+       uiBlock *block;
+       uiBut *but;
+       static char search[256]= "";
+               
+       block= uiLayoutGetBlock(layout);
+       uiBlockSetCurLayout(block, layout);
+
+       but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X*6, UI_UNIT_Y, "");
+       uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
+}
+
+/************************* Running Jobs Template **************************/
+
+#define B_STOPRENDER   1
+#define B_STOPCAST             2
+#define B_STOPANIM             3
+
+static void do_running_jobs(bContext *C, void *arg, int event)
+{
+       switch(event) {
+               case B_STOPRENDER:
+                       G.afbreek= 1;
+                       break;
+               case B_STOPCAST:
+                       WM_jobs_stop(CTX_wm_manager(C), CTX_wm_screen(C));
+                       break;
+               case B_STOPANIM:
+                       ED_screen_animation_timer(C, 0, 0);
+                       break;
+       }
+}
+
+void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
+{
+       bScreen *screen= CTX_wm_screen(C);
+       Scene *scene= CTX_data_scene(C);
+       wmWindowManager *wm= CTX_wm_manager(C);
+       uiBlock *block;
+
+       block= uiLayoutGetBlock(layout);
+       uiBlockSetCurLayout(block, layout);
+
+       uiBlockSetHandleFunc(block, do_running_jobs, NULL);
+
+       if(WM_jobs_test(wm, scene))
+               uiDefIconTextBut(block, BUT, B_STOPRENDER, ICON_REC, "Render", 0,0,75,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop rendering");
+       if(WM_jobs_test(wm, screen))
+               uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_REC, "Capture", 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop screencast");
+       if(screen->animtimer)
+               uiDefIconTextBut(block, BUT, B_STOPANIM, ICON_REC, "Anim Player", 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop animation playback");
+}
+