Info Header: Non-blocking Info Messages
authorJoshua Leung <aligorith@gmail.com>
Tue, 2 Mar 2010 11:48:40 +0000 (11:48 +0000)
committerJoshua Leung <aligorith@gmail.com>
Tue, 2 Mar 2010 11:48:40 +0000 (11:48 +0000)
Reports (i.e. 'info' or 'errors') are now shown in the info header in place of the scene statistics if the last executed operator had some, with this info disappearing again once another operator is run (to show scene statistics again).

For example, this means that info such as the the number of verts merged, or whether a Keying Set successfully inserted keyframes, etc. is now shown again somewhere, and that this is done in a non-blocking manner.

The current implementation is still a bit crude (i.e. lacking fancy polish), but is at least barebones functional. The todos...
* When more than 1 report message is generated by the last operator, there is currently a display of the number of reports. In future, it would be nice to be able to add a button beside this or make the label clickable with appropriate text indicating this (commented out atm) to show popup menu of all the reports...

* There could probably be some kind of coloured backdrop behind the text. Currently using standard box, but that has padding problems, and lacks visual interest.
* Timer based fade out/disappear?

release/scripts/ui/space_info.py
source/blender/editors/include/UI_interface.h
source/blender/editors/interface/interface_regions.c
source/blender/editors/interface/interface_templates.c
source/blender/makesrna/intern/rna_ui_api.c
source/blender/makesrna/intern/rna_wm.c

index ff0646ba78848191e60bedd3b9d0086e2fbe5d34..e1bc8f2b226e5fcd5751c70fbf83a65629291b59 100644 (file)
@@ -25,7 +25,12 @@ class INFO_HT_header(bpy.types.Header):
 
     def draw(self, context):
         layout = self.layout
-
+        
+        wm = context.manager
+        if wm and len(wm.operators):
+            last_op = wm.operators[-1]
+        else:
+            last_op = None
         window = context.window
         scene = context.scene
         rd = scene.render
@@ -58,11 +63,14 @@ class INFO_HT_header(bpy.types.Header):
 
         layout.separator()
 
-        layout.template_operator_search()
         layout.template_running_jobs()
+        
+        if last_op and last_op.has_reports:
+            layout.template_reports_banner(last_op)
+        else:
+            layout.label(text=scene.statistics())
 
-        layout.label(text=scene.statistics())
-
+        # XXX: this should be right-aligned to the RHS of the region
         layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER', text="")
 
 
index 54aeea484f0b16e59016ed2d0f3143c151aa9762..5c6ac272c538411779ba47048f47f6c9546027f9 100644 (file)
@@ -687,6 +687,7 @@ void uiTemplateRunningJobs(uiLayout *layout, struct bContext *C);
 void uiTemplateOperatorSearch(uiLayout *layout);
 void uiTemplateHeader3D(uiLayout *layout, struct bContext *C);
 void uiTemplateTextureImage(uiLayout *layout, struct bContext *C, struct Tex *tex);
+void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C, struct wmOperator *op);
 
 void uiTemplateList(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname, struct PointerRNA *activeptr, char *activeprop, int rows, int maxrows, int type);
 
index 8eba7e5505f7edd67642f40ef1216dc52e6b6de4..bc03be84b650b07b05f0983e9b12554108586ef9 100644 (file)
@@ -2271,7 +2271,7 @@ void uiPupMenuReports(bContext *C, ReportList *reports)
                else if(report->type >= RPT_WARNING)
                        BLI_dynstr_appendf(ds, "Warning %%i%d%%t|%s", ICON_ERROR, report->message);
                else if(report->type >= RPT_INFO)
-                       BLI_dynstr_appendf(ds, "Info %%t|%s", report->message);
+                       BLI_dynstr_appendf(ds, "Info %%i%d%%t|%s", ICON_INFO, report->message);
        }
 
        str= BLI_dynstr_get_cstring(ds);
index e2804efe0405d6007273498344b316eb499dffb8..e3dac41979d7fecb21149d6851a8fee4f34d37f5 100644 (file)
@@ -2484,4 +2484,45 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
                uiDefIconTextBut(block, BUT, B_STOPANIM, ICON_CANCEL, "Anim Player", 0,0,100,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop animation playback");
 }
 
+/************************* Reports for Last Operator Template **************************/
+
+void uiTemplateReportsBanner(uiLayout *layout, bContext *C, wmOperator *op)
+{
+       ReportList *reports = op->reports;
+       uiLayout *box;
+       
+       /* sanity checks */
+       if (ELEM(NULL, op, reports)) {
+               printf("uiTemplateReportsBanner: no operator with reports!\n");
+               return;
+       }
+       
+       /* make a box around the report to make it stand out */
+       box = uiLayoutBox(layout);
+       uiLayoutSetScaleY(box, 0.48); /* experimentally determined value to reduce execessive padding... */
+       
+       /* if more than one report, we need to show the popup when user clicks on the temp label... */
+       if (reports->list.first != reports->list.last) {
+               int numReports = BLI_countlist(&reports->list);
+               char buf[64];
+               
+               // XXX: we need uiItem* to return uiBut pointer so that we can use it to set callbacks
+               // used to call uiPupMenuReports... as alternative, we could fall back to the "old ways"
+               //sprintf(buf, "Last Operator had %d errors. Click to see more...", numReports);
+               sprintf(buf, "Last Operator had %d errors", numReports);
+               uiItemL(box, buf, ICON_INFO);
+       }
+       else {
+               /* single report, so show report directly */
+               // XXX: what if the report is too long? should we truncate the text?
+               Report *report= (Report *)reports->list.first;
+               
+               if(report->type >= RPT_ERROR)
+                       uiItemL(box, report->message, ICON_ERROR);
+               else if(report->type >= RPT_WARNING)
+                       uiItemL(box, report->message, ICON_ERROR);
+               else if(report->type >= RPT_INFO)
+                       uiItemL(box, report->message, ICON_INFO);
+       }
+}
 
index ccd6274060af8e6052b7f7cbbbc8d1fa2d103154..07c4d9c826e1ff2112f8f55b9c74b3961845fa7f 100644 (file)
@@ -384,6 +384,11 @@ void RNA_api_ui_layout(StructRNA *srna)
 
        func= RNA_def_function(srna, "template_header_3D", "uiTemplateHeader3D");
        RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+       
+       func= RNA_def_function(srna, "template_reports_banner", "uiTemplateReportsBanner");
+       RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+       parm= RNA_def_pointer(func, "operator", "Operator", "", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
 
 
 
index 7164e894b3cfdc97da0218a04104326aa08ac085..cda7fca107322e26ed2be6552613fe0ef3479476 100644 (file)
@@ -339,6 +339,12 @@ static int rna_Operator_name_length(PointerRNA *ptr)
        return strlen(op->type->name);
 }
 
+static int rna_Operator_has_reports_get(PointerRNA *ptr)
+{
+       wmOperator *op= (wmOperator*)ptr->data;
+       return (op->reports && op->reports->list.first);
+}
+
 static PointerRNA rna_Operator_properties_get(PointerRNA *ptr)
 {
        wmOperator *op= (wmOperator*)ptr->data;
@@ -912,7 +918,12 @@ static void rna_def_operator(BlenderRNA *brna)
        RNA_def_property_struct_type(prop, "OperatorProperties");
        RNA_def_property_ui_text(prop, "Properties", "");
        RNA_def_property_pointer_funcs(prop, "rna_Operator_properties_get", NULL, NULL);
-
+       
+       prop= RNA_def_property(srna, "has_reports", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* this is 'virtual' property */
+       RNA_def_property_boolean_funcs(prop, "rna_Operator_has_reports_get", NULL);
+       RNA_def_property_ui_text(prop, "Has Reports", "Operator has a set of reports (warnings and errors) from last execution");
+       
        prop= RNA_def_property(srna, "layout", PROP_POINTER, PROP_NONE);
        RNA_def_property_struct_type(prop, "UILayout");