UI: Generalized Alert and Popup Block Error Indication
This PR adds an optional block alert level, defaulting to none. Then for error-level alerts only it adds a red line and a color icon. Dialogs with other alert types do not change at all. This also adds a UI_alert function to create such dialogs. Pull Request: https://projects.blender.org/blender/blender/pulls/134084
This commit is contained in:
committed by
Harley Acheson
parent
d3712a16db
commit
9a3f80b8f2
@@ -1 +1 @@
|
||||
<svg id="svg5" height="1600" viewBox="0 0 1600 1599.9999" width="1600" xmlns="http://www.w3.org/2000/svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"><sodipodi:namedview pagecolor="#303030" showgrid="true"><inkscape:grid id="grid5" units="px" spacingx="100" spacingy="100" color="#4772b3" opacity="0.2" visible="true" /></sodipodi:namedview><g transform="matrix(26.923423 0 0 26.923423 -3507.7961 -61.577)"><g id="blender_error" fill="none"><path id="path1" d="m183.05322 22.7471c0-.270966-.10532-.530681-.2939-.722911l-12.92693-13.1769239c-.18857-.1922299-.44337-.2995889-.70919-.2995889h-18.28246c-.26582 0-.52061.107359-.70919.2995889l-12.92692 13.1769239c-.18859.19223-.29391.451945-.29391.722911v18.636029c0 .270964.10532.53068.29391.722909l12.92692 13.176912c.18858.192231.44337.299601.70919.299601h18.28246c.26582 0 .52062-.10737.70919-.299601l12.92693-13.176912c.18858-.192229.2939-.451945.2939-.722909z" stroke-width=".037616"/></g><g id="blender_text" fill="#ffffff" fill-rule="evenodd"><path id="path3" d="m150.10053 19.686508c-.256 0-.51202.097496-.70752.292496l-1.41403 1.414022c-.39.390999-.39 1.023965 0 1.414965l9.19202 9.192013-9.19202 9.192014c-.39.391-.39 1.023965 0 1.414965l1.41403 1.414022c.391.39 1.02396.39 1.41496 0l9.19201-9.192013 9.19202 9.192013c.391.39 1.02404.39 1.41504 0l1.41395-1.414022c.39-.391.39-1.023965 0-1.414965l-9.19202-9.192014 9.19202-9.192013c.39-.391.39-1.023966 0-1.414965l-1.41395-1.414022c-.391-.39-1.02404-.39-1.41504 0l-9.19202 9.192013-9.19201-9.192013c-.1955-.195-.45145-.292496-.70744-.292496z"/><path id="path2" d="m186 22.059c0-.531-.211-1.039-.586-1.414l-14.059-14.059c-.375-.375-.883-.586-1.414-.586h-19.882c-.531 0-1.039.211-1.414.586l-14.059 14.059c-.375.375-.586.883-.586 1.414v19.882c0 .531.211 1.039.586 1.414l14.059 14.059c.375.375.883.586 1.414.586h19.882c.531 0 1.039-.211 1.414-.586l14.059-14.059c.375-.375.586-.883.586-1.414zm-3 .828c0-.265-.105-.519-.293-.707l-12.887-12.887c-.188-.188-.442-.293-.707-.293h-18.226c-.265 0-.519.105-.707.293l-12.887 12.887c-.188.188-.293.442-.293.707v18.226c0 .265.105.519.293.707l12.887 12.887c.188.188.442.293.707.293h18.226c.265 0 .519-.105.707-.293l12.887-12.887c.188-.188.293-.442.293-.707z"/></g></g></svg>
|
||||
<svg id="svg5" height="1600" viewBox="0 0 1600 1599.9999" width="1600" xmlns="http://www.w3.org/2000/svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"><sodipodi:namedview pagecolor="#303030" showgrid="true"><inkscape:grid id="grid5" units="px" spacingx="100" spacingy="100" color="#4772b3" opacity="0.2" visible="true" /></sodipodi:namedview><g transform="matrix(26.923423 0 0 26.923423 -3507.7961 -61.577)"><g id="blender_error" fill="none"><path id="path1" d="m183.05322 22.7471c0-.270966-.10532-.530681-.2939-.722911l-12.92693-13.1769239c-.18857-.1922299-.44337-.2995889-.70919-.2995889h-18.28246c-.26582 0-.52061.107359-.70919.2995889l-12.92692 13.1769239c-.18859.19223-.29391.451945-.29391.722911v18.636029c0 .270964.10532.53068.29391.722909l12.92692 13.176912c.18858.192231.44337.299601.70919.299601h18.28246c.26582 0 .52062-.10737.70919-.299601l12.92693-13.176912c.18858-.192229.2939-.451945.2939-.722909z" stroke-width=".037616"/></g><g fill="#ffffff" fill-rule="evenodd"><path id="path3" d="m150.10053 19.686508c-.256 0-.51202.097496-.70752.292496l-1.41403 1.414022c-.39.390999-.39 1.023965 0 1.414965l9.19202 9.192013-9.19202 9.192014c-.39.391-.39 1.023965 0 1.414965l1.41403 1.414022c.391.39 1.02396.39 1.41496 0l9.19201-9.192013 9.19202 9.192013c.391.39 1.02404.39 1.41504 0l1.41395-1.414022c.39-.391.39-1.023965 0-1.414965l-9.19202-9.192014 9.19202-9.192013c.39-.391.39-1.023966 0-1.414965l-1.41395-1.414022c-.391-.39-1.02404-.39-1.41504 0l-9.19202 9.192013-9.19201-9.192013c-.1955-.195-.45145-.292496-.70744-.292496z"/><path id="path2" d="m186 22.059c0-.531-.211-1.039-.586-1.414l-14.059-14.059c-.375-.375-.883-.586-1.414-.586h-19.882c-.531 0-1.039.211-1.414.586l-14.059 14.059c-.375.375-.586.883-.586 1.414v19.882c0 .531.211 1.039.586 1.414l14.059 14.059c.375.375.883.586 1.414.586h19.882c.531 0 1.039-.211 1.414-.586l14.059-14.059c.375-.375.586-.883.586-1.414zm-3 .828c0-.265-.105-.519-.293-.707l-12.887-12.887c-.188-.188-.442-.293-.707-.293h-18.226c-.265 0-.519.105-.707.293l-12.887 12.887c-.188.188-.293.442-.293.707v18.226c0 .265.105.519.293.707l12.887 12.887c.188.188.442.293.707.293h18.226c.265 0 .519-.105.707-.293l12.887-12.887c.188-.188.293-.442.293-.707z"/></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
@@ -292,3 +292,5 @@ blender::ui::AbstractTreeView *UI_block_add_view(
|
||||
uiBlock &block,
|
||||
blender::StringRef idname,
|
||||
std::unique_ptr<blender::ui::AbstractTreeView> tree_view);
|
||||
|
||||
void UI_alert(bContext *C, std::string title, std::string message, eAlertIcon icon, bool compact);
|
||||
|
||||
@@ -5105,6 +5105,11 @@ uiBut *uiDefButAlert(uiBlock *block, int icon, int x, int y, short width, short
|
||||
{
|
||||
ImBuf *ibuf = UI_icon_alert_imbuf_get((eAlertIcon)icon, float(width));
|
||||
if (ibuf) {
|
||||
if (icon == ALERT_ICON_ERROR) {
|
||||
uchar color[4];
|
||||
UI_GetThemeColor4ubv(TH_ERROR, color);
|
||||
return uiDefButImage(block, ibuf, x, y, ibuf->x, ibuf->y, color);
|
||||
}
|
||||
bTheme *btheme = UI_GetTheme();
|
||||
return uiDefButImage(block, ibuf, x, y, ibuf->x, ibuf->y, btheme->tui.wcol_menu_back.text);
|
||||
}
|
||||
|
||||
@@ -578,6 +578,8 @@ struct uiBlockDynamicListener {
|
||||
void (*listener_func)(const wmRegionListenerParams *params);
|
||||
};
|
||||
|
||||
enum class uiBlockAlertLevel : int8_t { None, Info, Success, Warning, Error };
|
||||
|
||||
struct uiBlock {
|
||||
uiBlock *next, *prev;
|
||||
|
||||
@@ -609,6 +611,8 @@ struct uiBlock {
|
||||
rctf rect;
|
||||
float aspect;
|
||||
|
||||
uiBlockAlertLevel alert_level = uiBlockAlertLevel::None;
|
||||
|
||||
/** Unique hash used to implement popup menu memory. */
|
||||
uint puphash;
|
||||
|
||||
|
||||
@@ -6115,6 +6115,22 @@ uiLayout *uiItemsAlertBox(uiBlock *block,
|
||||
0,
|
||||
style);
|
||||
|
||||
if (icon == ALERT_ICON_INFO) {
|
||||
block->alert_level = uiBlockAlertLevel::Info;
|
||||
}
|
||||
else if (icon == ALERT_ICON_WARNING) {
|
||||
block->alert_level = uiBlockAlertLevel::Warning;
|
||||
}
|
||||
else if (icon == ALERT_ICON_QUESTION) {
|
||||
block->alert_level = uiBlockAlertLevel::Warning;
|
||||
}
|
||||
else if (icon == ALERT_ICON_ERROR) {
|
||||
block->alert_level = uiBlockAlertLevel::Error;
|
||||
}
|
||||
else {
|
||||
block->alert_level = uiBlockAlertLevel::None;
|
||||
}
|
||||
|
||||
/* Split layout to put alert icon on left side. */
|
||||
uiLayout *split_block = &block_layout.split(split_factor, false);
|
||||
|
||||
|
||||
@@ -5359,6 +5359,40 @@ static void ui_draw_clip_tri(uiBlock *block, const rcti *rect, uiWidgetType *wt)
|
||||
}
|
||||
}
|
||||
|
||||
static void ui_draw_dialog_alert(uiBlock *block, const rcti *rect)
|
||||
{
|
||||
if (block->alert_level != uiBlockAlertLevel::Error) {
|
||||
return;
|
||||
}
|
||||
|
||||
float color[4];
|
||||
switch (block->alert_level) {
|
||||
case uiBlockAlertLevel::Error:
|
||||
UI_GetThemeColor4fv(TH_ERROR, color);
|
||||
break;
|
||||
case uiBlockAlertLevel::Warning:
|
||||
UI_GetThemeColor4fv(TH_WARNING, color);
|
||||
break;
|
||||
case uiBlockAlertLevel::Success:
|
||||
UI_GetThemeColor4fv(TH_SUCCESS, color);
|
||||
break;
|
||||
default:
|
||||
UI_GetThemeColor4fv(TH_INFO, color);
|
||||
}
|
||||
|
||||
bTheme *btheme = UI_GetTheme();
|
||||
const float bg_radius = btheme->tui.wcol_menu_back.roundness * U.widget_unit;
|
||||
const float line_width = 3.0f * UI_SCALE_FAC;
|
||||
const float radius = (bg_radius > (line_width * 2.0f)) ? 0.0f : bg_radius;
|
||||
const float padding = (bg_radius > (line_width * 2.0f)) ? bg_radius : 0.0f;
|
||||
rctf line_rect;
|
||||
BLI_rctf_rcti_copy(&line_rect, rect);
|
||||
line_rect.ymin = line_rect.ymax - line_width;
|
||||
BLI_rctf_pad(&line_rect, -padding, 0.0f);
|
||||
UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
|
||||
UI_draw_roundbox_4fv(&line_rect, true, radius, color);
|
||||
}
|
||||
|
||||
void ui_draw_menu_back(uiStyle * /*style*/, uiBlock *block, const rcti *rect)
|
||||
{
|
||||
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_BACK);
|
||||
@@ -5366,7 +5400,14 @@ void ui_draw_menu_back(uiStyle * /*style*/, uiBlock *block, const rcti *rect)
|
||||
wt->state(wt, &STATE_INFO_NULL, blender::ui::EmbossType::Undefined);
|
||||
if (block) {
|
||||
const float zoom = 1.0f / block->aspect;
|
||||
wt->draw_block(&wt->wcol, rect, block->flag, block->direction, zoom);
|
||||
wt->draw_block(&wt->wcol,
|
||||
rect,
|
||||
block->flag,
|
||||
block->alert_level == uiBlockAlertLevel::None ? block->direction : UI_DIR_DOWN,
|
||||
zoom);
|
||||
if (block->alert_level != uiBlockAlertLevel::None) {
|
||||
ui_draw_dialog_alert(block, rect);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wt->draw_block(&wt->wcol, rect, 0, 0, 1.0f);
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
#include "BLF_api.hh"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_rect.h"
|
||||
@@ -1000,4 +1002,138 @@ void ui_popup_block_free(bContext *C, uiPopupBlockHandle *handle)
|
||||
MEM_delete(handle);
|
||||
}
|
||||
|
||||
struct ui_alert_data {
|
||||
eAlertIcon icon;
|
||||
std::string title;
|
||||
std::string message;
|
||||
bool compact;
|
||||
bool okay_button;
|
||||
bool mouse_move_quit;
|
||||
};
|
||||
|
||||
static void ui_alert_ok_cb(bContext *C, void *arg1, void *arg2)
|
||||
{
|
||||
ui_alert_data *data = static_cast<ui_alert_data *>(arg1);
|
||||
MEM_delete(data);
|
||||
uiBlock *block = static_cast<uiBlock *>(arg2);
|
||||
UI_popup_menu_retval_set(block, UI_RETURN_OK, true);
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
UI_popup_block_close(C, win, block);
|
||||
}
|
||||
|
||||
static void ui_alert_ok(bContext * /*C*/, void *arg, int /*retval*/)
|
||||
{
|
||||
ui_alert_data *data = static_cast<ui_alert_data *>(arg);
|
||||
MEM_delete(data);
|
||||
}
|
||||
|
||||
static void ui_alert_cancel(bContext * /*C*/, void *user_data)
|
||||
{
|
||||
ui_alert_data *data = static_cast<ui_alert_data *>(user_data);
|
||||
MEM_delete(data);
|
||||
}
|
||||
|
||||
static uiBlock *ui_alert_create(bContext *C, ARegion *region, void *user_data)
|
||||
{
|
||||
ui_alert_data *data = static_cast<ui_alert_data *>(user_data);
|
||||
|
||||
const uiStyle *style = UI_style_get_dpi();
|
||||
const short icon_size = (data->compact ? 32 : 40) * UI_SCALE_FAC;
|
||||
const int max_width = int((data->compact ? 250.0f : 350.0f) * UI_SCALE_FAC);
|
||||
const int min_width = int(120.0f * UI_SCALE_FAC);
|
||||
|
||||
uiBlock *block = UI_block_begin(C, region, __func__, blender::ui::EmbossType::Emboss);
|
||||
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
|
||||
UI_block_flag_disable(block, UI_BLOCK_LOOP);
|
||||
UI_block_emboss_set(block, blender::ui::EmbossType::Emboss);
|
||||
UI_popup_dummy_panel_set(region, block);
|
||||
|
||||
UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_NUMSELECT);
|
||||
if (data->mouse_move_quit) {
|
||||
UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT);
|
||||
}
|
||||
|
||||
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
|
||||
|
||||
UI_fontstyle_set(&style->widget);
|
||||
/* Width based on the text lengths. */
|
||||
int text_width = BLF_width(style->widget.uifont_id, data->title.c_str(), data->title.size());
|
||||
|
||||
blender::Vector<blender::StringRef> messages = BLF_string_wrap(
|
||||
fstyle->uifont_id, data->message, max_width, BLFWrapMode::Typographical);
|
||||
|
||||
for (auto &st_ref : messages) {
|
||||
const std::string &st = st_ref;
|
||||
text_width = std::max(text_width,
|
||||
int(BLF_width(style->widget.uifont_id, st.c_str(), st.size())));
|
||||
}
|
||||
|
||||
int dialog_width = std::max(text_width + int(style->columnspace * 2.5), min_width);
|
||||
|
||||
uiLayout *layout;
|
||||
layout = uiItemsAlertBox(block, style, dialog_width + icon_size, data->icon, icon_size);
|
||||
|
||||
uiLayout *content = &layout->column(false);
|
||||
content->scale_y_set(0.75f);
|
||||
|
||||
/* Title. */
|
||||
uiItemL_ex(content, data->title, ICON_NONE, true, false);
|
||||
|
||||
content->separator(1.0f);
|
||||
|
||||
/* Message lines. */
|
||||
for (auto &st : messages) {
|
||||
content->label(st, ICON_NONE);
|
||||
}
|
||||
|
||||
if (data->okay_button) {
|
||||
|
||||
layout->separator(2.0f);
|
||||
|
||||
/* Clear so the OK button is left alone. */
|
||||
UI_block_func_set(block, nullptr, nullptr, nullptr);
|
||||
|
||||
const float pad = std::max((1.0f - ((200.0f * UI_SCALE_FAC) / float(text_width))) / 2.0f,
|
||||
0.01f);
|
||||
uiLayout *split = &layout->split(pad, true);
|
||||
split->column(true);
|
||||
uiLayout *buttons = &split->split(1.0f - (pad * 2.0f), true);
|
||||
buttons->scale_y_set(1.2f);
|
||||
|
||||
uiBlock *buttons_block = layout->block();
|
||||
uiBut *okay_but = uiDefBut(
|
||||
buttons_block, ButType::But, 0, "OK", 0, 0, 0, UI_UNIT_Y, nullptr, 0, 0, "");
|
||||
UI_but_func_set(okay_but, ui_alert_ok_cb, user_data, block);
|
||||
UI_but_flag_enable(okay_but, UI_BUT_ACTIVE_DEFAULT);
|
||||
}
|
||||
|
||||
const int padding = (data->compact ? 10 : 14) * UI_SCALE_FAC;
|
||||
|
||||
if (data->mouse_move_quit) {
|
||||
const float button_center_x = -0.5f;
|
||||
const float button_center_y = data->okay_button ? 4.0f : 2.0f;
|
||||
const int bounds_offset[2] = {int(button_center_x * layout->width()),
|
||||
int(button_center_y * UI_UNIT_X)};
|
||||
UI_block_bounds_set_popup(block, padding, bounds_offset);
|
||||
}
|
||||
else {
|
||||
UI_block_bounds_set_centered(block, padding);
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
void UI_alert(bContext *C, std::string title, std::string message, eAlertIcon icon, bool compact)
|
||||
{
|
||||
ui_alert_data *data = MEM_new<ui_alert_data>(__func__);
|
||||
data->title = title;
|
||||
data->message = message;
|
||||
data->icon = icon;
|
||||
data->compact = compact;
|
||||
data->okay_button = true;
|
||||
data->mouse_move_quit = compact;
|
||||
|
||||
UI_popup_block_ex(C, ui_alert_create, ui_alert_ok, ui_alert_cancel, data, nullptr);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
Reference in New Issue
Block a user