diff --git a/scripts/startup/bl_ui/space_console.py b/scripts/startup/bl_ui/space_console.py index 9644d7d93dc..0899bb99420 100644 --- a/scripts/startup/bl_ui/space_console.py +++ b/scripts/startup/bl_ui/space_console.py @@ -15,6 +15,10 @@ class CONSOLE_HT_header(Header): CONSOLE_MT_editor_menus.draw_collapsible(context, layout) + layout.progress_indicator(progress = 0.5, text="50%") + layout.progress_indicator(progress = 0.8, progress_type = 'RING') + layout.progress_indicator(progress = 0.7, progress_type = 'PIE', text = "Downloading...") + class CONSOLE_MT_editor_menus(Menu): bl_idname = "CONSOLE_MT_editor_menus" diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 5af6d47a677..4bf35bc607b 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1450,6 +1450,12 @@ enum { UI_TEMPLATE_ID_FILTER_AVAILABLE = 1, }; +enum uiButProgressType { + UI_PROGRESS_DETERMINATE_LINEAR = 0, + UI_PROGRESS_DETERMINATE_RING = 1, + UI_PROGRESS_DETERMINATE_PIE = 2, +}; + /***************************** ID Utilities *******************************/ int UI_icon_from_id(const struct ID *id); @@ -2882,6 +2888,11 @@ void uiItemS_ex(uiLayout *layout, float factor); /** Flexible spacing. */ void uiItemSpacer(uiLayout *layout); +void uiItemProgressIndicator(uiLayout *layout, + const char *text, + float progress, + int progress_type); + /* popover */ void uiItemPopoverPanel_ptr( uiLayout *layout, const struct bContext *C, struct PanelType *pt, const char *name, int icon); diff --git a/source/blender/editors/interface/interface_intern.hh b/source/blender/editors/interface/interface_intern.hh index 849f7c434b1..719ace37a58 100644 --- a/source/blender/editors/interface/interface_intern.hh +++ b/source/blender/editors/interface/interface_intern.hh @@ -345,6 +345,7 @@ struct uiButDecorator : public uiBut { struct uiButProgressbar : public uiBut { /* 0..1 range */ float progress = 0; + uiButProgressType progress_type; }; struct uiButViewItem : public uiBut { diff --git a/source/blender/editors/interface/interface_layout.cc b/source/blender/editors/interface/interface_layout.cc index ed5bab78268..e038b8e9f31 100644 --- a/source/blender/editors/interface/interface_layout.cc +++ b/source/blender/editors/interface/interface_layout.cc @@ -3475,6 +3475,44 @@ void uiItemS(uiLayout *layout) uiItemS_ex(layout, 1.0f); } +void uiItemProgressIndicator(uiLayout *layout, const char *text, float progress, int progress_type) +{ + uiBlock *block = layout->root->block; + short width = UI_UNIT_X; + + if (progress_type == UI_PROGRESS_DETERMINATE_LINEAR) { + width = UI_UNIT_X * 5.0f; + } + else if (text && text[0]) { + width = UI_UNIT_X * 8.0f; + } + + UI_block_layout_set_current(block, layout); + uiBut *but = uiDefBut(block, + UI_BTYPE_PROGRESS_BAR, + 0, + (text) ? text : "", + 0, + 0, + width, + short(UI_UNIT_Y), + nullptr, + 0.0, + 0.0, + 0, + 0, + ""); + + if (text && text[0] && (progress_type != UI_PROGRESS_DETERMINATE_LINEAR)) { + /* Default centered is okay for linear, left aligned for others. */ + but->drawflag |= UI_BUT_TEXT_LEFT; + } + + uiButProgressbar *progress_bar = static_cast(but); + progress_bar->progress_type = static_cast(progress_type); + progress_bar->progress = progress; +} + void uiItemSpacer(uiLayout *layout) { uiBlock *block = layout->root->block; diff --git a/source/blender/editors/interface/interface_widgets.cc b/source/blender/editors/interface/interface_widgets.cc index 83ccdd1e4a6..2ed3e155ae7 100644 --- a/source/blender/editors/interface/interface_widgets.cc +++ b/source/blender/editors/interface/interface_widgets.cc @@ -3604,14 +3604,9 @@ static void widget_scroll(uiBut *but, UI_draw_widget_scroll(wcol, rect, &rect1, (state->but_flag & UI_SELECT) ? UI_SCROLL_PRESSED : 0); } -static void widget_progressbar(uiBut *but, - uiWidgetColors *wcol, - rcti *rect, - const uiWidgetStateInfo * /*state*/, - int roundboxalign, - const float zoom) +static void widget_progress_determinate_bar( + uiButProgressbar *but, uiWidgetColors *wcol, rcti *rect, int roundboxalign, const float zoom) { - uiButProgressbar *but_progressbar = (uiButProgressbar *)but; rcti rect_prog = *rect, rect_bar = *rect; uiWidgetBase wtb, wtb_bar; @@ -3619,7 +3614,7 @@ static void widget_progressbar(uiBut *but, widget_init(&wtb_bar); /* round corners */ - const float value = but_progressbar->progress; + const float value = but->progress; const float ofs = widget_radius_from_zoom(zoom, wcol); float w = value * BLI_rcti_size_x(&rect_prog); @@ -3639,6 +3634,59 @@ static void widget_progressbar(uiBut *but, widgetbase_draw(&wtb_bar, wcol); } +static void widget_progress_determinate_ring(uiButProgressbar *but, + uiWidgetColors *wcol, + rcti *rect, + const float ring_width) +{ + float outer_rad = (rect->ymax - rect->ymin) / 2.0f; + float inner_rad = outer_rad * ring_width; + float x = rect->xmin + outer_rad; + float y = rect->ymin + outer_rad; + float start = 0.0f; + float end = but->progress * 360.0f; + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor3ubvAlpha(wcol->item, 255 / UI_PIXEL_AA_JITTER * 2); + GPU_blend(GPU_BLEND_ALPHA); + + for (int i = 0; i < UI_PIXEL_AA_JITTER; i++) { + imm_draw_disk_partial_fill_2d(pos, + x + ui_pixel_jitter[i][0], + y + ui_pixel_jitter[i][1], + inner_rad, + outer_rad, + 48, + start, + end); + } + immUnbindProgram(); + + if (but->drawstr && but->drawstr[0]) { + rect->xmin += UI_UNIT_X; + } +} + +static void widget_progress_indicator(uiBut *but, + uiWidgetColors *wcol, + rcti *rect, + const uiWidgetStateInfo * /*state*/, + int roundboxalign, + const float zoom) +{ + uiButProgressbar *but_progress = static_cast(but); + if (but_progress->progress_type == UI_PROGRESS_DETERMINATE_LINEAR) { + widget_progress_determinate_bar(but_progress, wcol, rect, roundboxalign, zoom); + } + else if (but_progress->progress_type == UI_PROGRESS_DETERMINATE_RING) { + widget_progress_determinate_ring(but_progress, wcol, rect, 0.6f); + } + else if (but_progress->progress_type == UI_PROGRESS_DETERMINATE_PIE) { + widget_progress_determinate_ring(but_progress, wcol, rect, 0.0f); + } +} + static void widget_view_item(uiWidgetColors *wcol, rcti *rect, const uiWidgetStateInfo *state, @@ -4558,7 +4606,7 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type) case UI_WTYPE_PROGRESSBAR: wt.wcol_theme = &btheme->tui.wcol_progress; - wt.custom = widget_progressbar; + wt.custom = widget_progress_indicator; break; case UI_WTYPE_VIEW_ITEM: diff --git a/source/blender/makesrna/intern/rna_ui_api.cc b/source/blender/makesrna/intern/rna_ui_api.cc index 3b728602362..1cee17ac7e0 100644 --- a/source/blender/makesrna/intern/rna_ui_api.cc +++ b/source/blender/makesrna/intern/rna_ui_api.cc @@ -470,6 +470,20 @@ static void rna_uiItemPopoverPanelFromGroup(uiLayout *layout, uiItemPopoverPanelFromGroup(layout, C, space_id, region_id, context, category); } +static void rna_uiItemProgressIndicator(struct uiLayout *layout, + const char *text, + const char *text_ctxt, + bool translate, + float progress, + int progress_type) +{ + if (translate && BLT_translate_iface()) { + text = BLT_pgettext((text_ctxt && text_ctxt[0]) ? text_ctxt : BLT_I18NCONTEXT_DEFAULT, text); + } + + uiItemProgressIndicator(layout, text, progress, progress_type); +} + static void rna_uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, @@ -938,6 +952,13 @@ void RNA_api_ui_layout(StructRNA *srna) {0, nullptr, 0, nullptr, nullptr}, }; + static const EnumPropertyItem progress_types[] = { + {UI_PROGRESS_DETERMINATE_LINEAR, "BAR", 0, "Bar", ""}, + {UI_PROGRESS_DETERMINATE_RING, "RING", 0, "Ring", ""}, + {UI_PROGRESS_DETERMINATE_PIE, "PIE", 0, "Pie", ""}, + {0, nullptr, 0, nullptr, nullptr}, + }; + static const EnumPropertyItem asset_view_template_options[] = { {UI_TEMPLATE_ASSET_DRAW_NO_NAMES, "NO_NAMES", @@ -1331,6 +1352,25 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_ui_description( func, "Item. Inserts horizontal spacing empty space into the layout between items"); + func = RNA_def_function(srna, "progress_indicator", "rna_uiItemProgressIndicator"); + RNA_def_function_ui_description(func, "Progress indicator"); + api_ui_item_common_text(func); + RNA_def_float(func, + "progress", + 0.0f, + 0.0f, + 1.0f, + "Progress", + "Amount of progress from 0.0f to 1.0f", + 0.0f, + 1.0f); + RNA_def_enum(func, + "progress_type", + progress_types, + UI_PROGRESS_DETERMINATE_LINEAR, + "Type", + "The type of progress indicator"); + /* context */ func = RNA_def_function(srna, "context_pointer_set", "uiLayoutSetContextPointer"); parm = RNA_def_string(func, "name", nullptr, 0, "Name", "Name of entry in the context");