WIP: Brush assets project #106303

Draft
Julian Eisel wants to merge 358 commits from brush-assets-project into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
7 changed files with 226 additions and 107 deletions
Showing only changes of commit dcc1894b89 - Show all commits

View File

@ -19,6 +19,11 @@ struct ReportList;
struct UserDef;
struct WorkspaceConfigFileData;
/**
* The suffix used for blendfiles managed by the asset system.
*/
#define BLENDER_ASSET_FILE_SUFFIX ".asset.blend"
/**
* Check whether given path ends with a blend file compatible extension
* (`.blend`, `.ble` or `.blend.gz`).

View File

@ -142,6 +142,14 @@ struct Main {
* could try to use more refined detection on load. */
bool has_forward_compatibility_issues;
/**
* The currently opened .blend file was created as an asset library storage.
*
* This is used to warn the user when they try to save it from Blender UI, since this will likely
* break the automatic management from the asset library system.
*/
bool is_asset_repository;
/** Commit timestamp from `buildinfo`. */
uint64_t build_commit_timestamp;
/** Commit Hash from `buildinfo`. */
@ -299,6 +307,17 @@ void BKE_main_merge(Main *bmain_dst, Main **r_bmain_src, MainMergeReport &report
*/
bool BKE_main_is_empty(Main *bmain);
/**
* Check whether the bmain has issues, e.g. for reporting in the status bar.
*/
bool BKE_main_has_issues(const Main *bmain);
/**
* Check whether user confirmation should be required when overwriting this `bmain` into its source
* blendfile.
*/
bool BKE_main_needs_overwrite_confirm(const Main *bmain);
void BKE_main_lock(Main *bmain);
void BKE_main_unlock(Main *bmain);

View File

@ -853,6 +853,9 @@ static void setup_app_data(bContext *C,
* nullptr curscreen)... */
else if (ELEM(nullptr, bfd->curscreen, bfd->curscene)) {
BKE_report(reports->reports, RPT_WARNING, "Library file, loading empty scene");
if (blender::StringRefNull(bfd->main->filepath).endswith(BLENDER_ASSET_FILE_SUFFIX)) {
bfd->main->is_asset_repository = true;
}
mode = LOAD_UI_OFF;
}
else if (G.fileflags & G_FILE_NO_UI) {

View File

@ -444,6 +444,16 @@ bool BKE_main_is_empty(Main *bmain)
return result;
}
bool BKE_main_has_issues(const Main *bmain)
{
return bmain->has_forward_compatibility_issues || bmain->is_asset_repository;
}
bool BKE_main_needs_overwrite_confirm(const Main *bmain)
{
return bmain->has_forward_compatibility_issues || bmain->is_asset_repository;
}
void BKE_main_lock(Main *bmain)
{
BLI_spin_lock((SpinLock *)bmain->lock);

View File

@ -6558,13 +6558,47 @@ void uiTemplateInputStatus(uiLayout *layout, bContext *C)
}
}
static void ui_template_status_info_warnings_messages(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
std::string &warning_message,
std::string &regular_message,
std::string &tooltip_message)
{
tooltip_message = "";
char statusbar_info_flag = U.statusbar_flag;
if (bmain->has_forward_compatibility_issues) {
warning_message = ED_info_statusbar_string_ex(
bmain, scene, view_layer, STATUSBAR_SHOW_VERSION);
statusbar_info_flag &= ~STATUSBAR_SHOW_VERSION;
char writer_ver_str[12];
BKE_blender_version_blendfile_string_from_values(
writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, -1);
tooltip_message += fmt::format(RPT_("File saved by newer Blender\n({}), expect loss of data"),
writer_ver_str);
}
if (bmain->is_asset_repository) {
if (!tooltip_message.empty()) {
tooltip_message += "\n\n";
}
tooltip_message += RPT_(
"This file is managed by the Blender asset system\n"
"By editing it as a regular blend file, it will no longer\n"
"be possible to update its assets through the asset browser");
}
regular_message = ED_info_statusbar_string_ex(bmain, scene, view_layer, statusbar_info_flag);
}
void uiTemplateStatusInfo(uiLayout *layout, bContext *C)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
if (!bmain->has_forward_compatibility_issues) {
if (!BKE_main_has_issues(bmain)) {
const char *status_info_txt = ED_info_statusbar_string(bmain, scene, view_layer);
uiItemL(layout, status_info_txt, ICON_NONE);
return;
@ -6573,13 +6607,13 @@ void uiTemplateStatusInfo(uiLayout *layout, bContext *C)
/* Blender version part is shown as warning area when there are forward compatibility issues with
* currently loaded .blend file. */
const char *status_info_txt = ED_info_statusbar_string_ex(
bmain, scene, view_layer, (U.statusbar_flag & ~STATUSBAR_SHOW_VERSION));
uiItemL(layout, status_info_txt, ICON_NONE);
std::string warning_message;
std::string regular_message;
std::string tooltip_message;
ui_template_status_info_warnings_messages(
bmain, scene, view_layer, warning_message, regular_message, tooltip_message);
status_info_txt = ED_info_statusbar_string_ex(bmain, scene, view_layer, STATUSBAR_SHOW_VERSION);
uiBut *but;
uiItemL(layout, regular_message.c_str(), ICON_NONE);
const uiStyle *style = UI_style_get();
uiLayout *ui_abs = uiLayoutAbsolute(layout, false);
@ -6587,27 +6621,28 @@ void uiTemplateStatusInfo(uiLayout *layout, bContext *C)
eUIEmbossType previous_emboss = UI_block_emboss_get(block);
UI_fontstyle_set(&style->widgetlabel);
int width = int(
BLF_width(style->widgetlabel.uifont_id, status_info_txt, strlen(status_info_txt)));
width = max_ii(width, int(10 * UI_SCALE_FAC));
const int width = max_ii(int(BLF_width(style->widgetlabel.uifont_id,
warning_message.c_str(),
warning_message.length())),
int(10 * UI_SCALE_FAC));
UI_block_align_begin(block);
/* Background for icon. */
but = uiDefBut(block,
UI_BTYPE_ROUNDBOX,
0,
"",
0,
0,
UI_UNIT_X + (6 * UI_SCALE_FAC),
UI_UNIT_Y,
nullptr,
0.0f,
0.0f,
0,
0,
"");
uiBut *but = uiDefBut(block,
UI_BTYPE_ROUNDBOX,
0,
"",
0,
0,
UI_UNIT_X + (6 * UI_SCALE_FAC),
UI_UNIT_Y,
nullptr,
0.0f,
0.0f,
0,
0,
"");
/* UI_BTYPE_ROUNDBOX's bg color is set in but->col. */
UI_GetThemeColorType4ubv(TH_INFO_WARNING, SPACE_INFO, but->col);
@ -6634,14 +6669,13 @@ void uiTemplateStatusInfo(uiLayout *layout, bContext *C)
UI_block_align_end(block);
UI_block_emboss_set(block, UI_EMBOSS_NONE);
/* The report icon itself. */
static char compat_error_msg[256];
char writer_ver_str[12];
BKE_blender_version_blendfile_string_from_values(
writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, -1);
SNPRINTF(compat_error_msg,
RPT_("File saved by newer Blender\n(%s), expect loss of data"),
writer_ver_str);
/* Tool tips have to be static currently.
* FIXME This is a horrible requirement from uiBut, should probably just store an std::string for
* the tooltip as well? */
static char tooltip_static_storage[256];
BLI_strncpy(tooltip_static_storage, tooltip_message.c_str(), sizeof(tooltip_static_storage));
/* The warning icon itself. */
but = uiDefIconBut(block,
UI_BTYPE_BUT,
0,
@ -6655,25 +6689,27 @@ void uiTemplateStatusInfo(uiLayout *layout, bContext *C)
0.0f,
0.0f,
0.0f,
compat_error_msg);
tooltip_static_storage);
UI_GetThemeColorType4ubv(TH_INFO_WARNING_TEXT, SPACE_INFO, but->col);
but->col[3] = 255; /* This theme color is RBG only, so have to set alpha here. */
/* The report message. */
but = uiDefBut(block,
UI_BTYPE_BUT,
0,
status_info_txt,
UI_UNIT_X,
0,
short(width + UI_UNIT_X),
UI_UNIT_Y,
nullptr,
0.0f,
0.0f,
0.0f,
0.0f,
compat_error_msg);
/* The warning message, if any. */
if (!warning_message.empty()) {
but = uiDefBut(block,
UI_BTYPE_BUT,
0,
warning_message.c_str(),
UI_UNIT_X,
0,
short(width + UI_UNIT_X),
UI_UNIT_Y,
nullptr,
0.0f,
0.0f,
0.0f,
0.0f,
tooltip_static_storage);
}
UI_block_emboss_set(block, previous_emboss);
}

View File

@ -3552,8 +3552,8 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *
}
if (blendfile_path[0] != '\0') {
if (CTX_data_main(C)->has_forward_compatibility_issues) {
wm_save_file_forwardcompat_dialog(C, op);
if (BKE_main_needs_overwrite_confirm(CTX_data_main(C))) {
wm_save_file_overwrite_dialog(C, op);
ret = OPERATOR_INTERFACE;
}
else {
@ -3907,49 +3907,62 @@ static void wm_free_operator_properties_callback(void *user_data)
IDP_FreeProperty(properties);
}
static const char *save_file_forwardcompat_dialog_name = "save_file_forwardcompat_popup";
static const char *save_file_overwrite_dialog_name = "save_file_overwrite_popup";
static void file_forwardcompat_detailed_info_show(uiLayout *parent_layout, Main *bmain)
static void file_overwrite_detailed_info_show(uiLayout *parent_layout, Main *bmain)
{
uiLayout *layout = uiLayoutColumn(parent_layout, true);
/* Trick to make both lines of text below close enough to look like they are part of a same
* block. */
uiLayoutSetScaleY(layout, 0.70f);
char writer_ver_str[16];
char current_ver_str[16];
if (bmain->versionfile == BLENDER_VERSION) {
BKE_blender_version_blendfile_string_from_values(
writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, bmain->subversionfile);
BKE_blender_version_blendfile_string_from_values(
current_ver_str, sizeof(current_ver_str), BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION);
}
else {
BKE_blender_version_blendfile_string_from_values(
writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, -1);
BKE_blender_version_blendfile_string_from_values(
current_ver_str, sizeof(current_ver_str), BLENDER_VERSION, -1);
if (bmain->has_forward_compatibility_issues) {
char writer_ver_str[16];
char current_ver_str[16];
if (bmain->versionfile == BLENDER_VERSION) {
BKE_blender_version_blendfile_string_from_values(
writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, bmain->subversionfile);
BKE_blender_version_blendfile_string_from_values(
current_ver_str, sizeof(current_ver_str), BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION);
}
else {
BKE_blender_version_blendfile_string_from_values(
writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, -1);
BKE_blender_version_blendfile_string_from_values(
current_ver_str, sizeof(current_ver_str), BLENDER_VERSION, -1);
}
char message_line1[256];
char message_line2[256];
SNPRINTF(message_line1,
RPT_("This file was saved by a newer version of Blender (%s)"),
writer_ver_str);
SNPRINTF(message_line2,
RPT_("Saving it with this Blender (%s) may cause loss of data"),
current_ver_str);
uiItemL(layout, message_line1, ICON_NONE);
uiItemL(layout, message_line2, ICON_NONE);
}
char message_line1[256];
char message_line2[256];
SNPRINTF(message_line1,
RPT_("This file was saved by a newer version of Blender (%s)"),
writer_ver_str);
SNPRINTF(message_line2,
RPT_("Saving it with this Blender (%s) may cause loss of data"),
current_ver_str);
uiItemL(layout, message_line1, ICON_NONE);
uiItemL(layout, message_line2, ICON_NONE);
if (bmain->is_asset_repository) {
if (bmain->has_forward_compatibility_issues) {
uiItemS_ex(layout, 1.4f);
}
uiItemL(layout, RPT_("This file is managed by the Blender asset system"), ICON_NONE);
uiItemL(
layout, RPT_("By overwriting it as a regular blend file, it will no longer "), ICON_NONE);
uiItemL(layout, RPT_("be possible to update its assets through the asset browser"), ICON_NONE);
}
}
static void save_file_forwardcompat_cancel(bContext *C, void *arg_block, void * /*arg_data*/)
static void save_file_overwrite_cancel(bContext *C, void *arg_block, void * /*arg_data*/)
{
wmWindow *win = CTX_wm_window(C);
UI_popup_block_close(C, win, static_cast<uiBlock *>(arg_block));
}
static void save_file_forwardcompat_cancel_button(uiBlock *block, wmGenericCallback *post_action)
static void save_file_overwrite_cancel_button(uiBlock *block, wmGenericCallback *post_action)
{
uiBut *but = uiDefIconTextBut(block,
UI_BTYPE_BUT,
@ -3966,11 +3979,11 @@ static void save_file_forwardcompat_cancel_button(uiBlock *block, wmGenericCallb
0,
0,
"");
UI_but_func_set(but, save_file_forwardcompat_cancel, block, post_action);
UI_but_func_set(but, save_file_overwrite_cancel, block, post_action);
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
}
static void save_file_forwardcompat_overwrite(bContext *C, void *arg_block, void *arg_data)
static void save_file_overwrite_confirm(bContext *C, void *arg_block, void *arg_data)
{
wmWindow *win = CTX_wm_window(C);
@ -3993,8 +4006,7 @@ static void save_file_forwardcompat_overwrite(bContext *C, void *arg_block, void
WM_generic_callback_free(callback);
}
static void save_file_forwardcompat_overwrite_button(uiBlock *block,
wmGenericCallback *post_action)
static void save_file_overwrite_confirm_button(uiBlock *block, wmGenericCallback *post_action)
{
uiBut *but = uiDefIconTextBut(block,
UI_BTYPE_BUT,
@ -4011,20 +4023,37 @@ static void save_file_forwardcompat_overwrite_button(uiBlock *block,
0,
0,
"");
UI_but_func_set(but, save_file_forwardcompat_overwrite, block, post_action);
UI_but_func_set(but, save_file_overwrite_confirm, block, post_action);
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
UI_but_flag_enable(but, UI_BUT_REDALERT);
}
static void save_file_forwardcompat_saveas(bContext *C, void *arg_block, void * /*arg_data*/)
static void save_file_overwrite_saveas(bContext *C, void *arg_block, void * /*arg_data*/)
{
Main *bmain = CTX_data_main(C);
wmWindow *win = CTX_wm_window(C);
UI_popup_block_close(C, win, static_cast<uiBlock *>(arg_block));
WM_operator_name_call(C, "WM_OT_save_as_mainfile", WM_OP_INVOKE_DEFAULT, nullptr, nullptr);
PointerRNA props_ptr;
wmOperatorType *ot = WM_operatortype_find("WM_OT_save_as_mainfile", false);
WM_operator_properties_create_ptr(&props_ptr, ot);
if (bmain->is_asset_repository) {
/* If needed, substitute the 'proposed' Save As filepath by replacing the `.asset.blend` part
* of it by just `.blend`. */
std::string filepath = BKE_main_blendfile_path(bmain);
if (blender::StringRef(filepath).endswith(BLENDER_ASSET_FILE_SUFFIX)) {
filepath.replace(
filepath.rfind(BLENDER_ASSET_FILE_SUFFIX), strlen(BLENDER_ASSET_FILE_SUFFIX), ".blend");
RNA_string_set(&props_ptr, "filepath", filepath.c_str());
}
}
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, nullptr);
WM_operator_properties_free(&props_ptr);
}
static void save_file_forwardcompat_saveas_button(uiBlock *block, wmGenericCallback *post_action)
static void save_file_overwrite_saveas_button(uiBlock *block, wmGenericCallback *post_action)
{
uiBut *but = uiDefIconTextBut(block,
UI_BTYPE_BUT,
@ -4041,19 +4070,17 @@ static void save_file_forwardcompat_saveas_button(uiBlock *block, wmGenericCallb
0,
0,
"");
UI_but_func_set(but, save_file_forwardcompat_saveas, block, post_action);
UI_but_func_set(but, save_file_overwrite_saveas, block, post_action);
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT);
}
static uiBlock *block_create_save_file_forwardcompat_dialog(bContext *C,
ARegion *region,
void *arg1)
static uiBlock *block_create_save_file_overwrite_dialog(bContext *C, ARegion *region, void *arg1)
{
wmGenericCallback *post_action = static_cast<wmGenericCallback *>(arg1);
Main *bmain = CTX_data_main(C);
uiBlock *block = UI_block_begin(C, region, save_file_forwardcompat_dialog_name, UI_EMBOSS);
uiBlock *block = UI_block_begin(C, region, save_file_overwrite_dialog_name, UI_EMBOSS);
UI_block_flag_enable(
block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT);
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
@ -4061,8 +4088,27 @@ static uiBlock *block_create_save_file_forwardcompat_dialog(bContext *C,
uiLayout *layout = uiItemsAlertBox(block, 34, ALERT_ICON_WARNING);
/* Title. */
uiItemL_ex(
layout, RPT_("Overwrite file with an older Blender version?"), ICON_NONE, true, false);
if (bmain->has_forward_compatibility_issues) {
if (bmain->is_asset_repository) {
uiItemL_ex(
layout,
RPT_("Convert asset blend file to regular blend file with an older Blender version?"),
ICON_NONE,
true,
false);
}
else {
uiItemL_ex(
layout, RPT_("Overwrite file with an older Blender version?"), ICON_NONE, true, false);
}
}
else if (bmain->is_asset_repository) {
uiItemL_ex(
layout, RPT_("Convert asset blend file to regular blend file?"), ICON_NONE, true, false);
}
else {
BLI_assert_unreachable();
}
/* Filename. */
const char *blendfile_path = BKE_main_blendfile_path(CTX_data_main(C));
@ -4079,7 +4125,7 @@ static uiBlock *block_create_save_file_forwardcompat_dialog(bContext *C,
uiItemL(layout, filename, ICON_NONE);
/* Detailed message info. */
file_forwardcompat_detailed_info_show(layout, bmain);
file_overwrite_detailed_info_show(layout, bmain);
uiItemS_ex(layout, 4.0f);
@ -4089,7 +4135,7 @@ static uiBlock *block_create_save_file_forwardcompat_dialog(bContext *C,
uiLayoutSetScaleY(split, 1.2f);
uiLayoutColumn(split, false);
save_file_forwardcompat_overwrite_button(block, post_action);
save_file_overwrite_confirm_button(block, post_action);
uiLayout *split_right = uiLayoutSplit(split, 0.1f, true);
@ -4097,25 +4143,25 @@ static uiBlock *block_create_save_file_forwardcompat_dialog(bContext *C,
/* Empty space. */
uiLayoutColumn(split_right, false);
save_file_forwardcompat_cancel_button(block, post_action);
save_file_overwrite_cancel_button(block, post_action);
uiLayoutColumn(split_right, false);
save_file_forwardcompat_saveas_button(block, post_action);
save_file_overwrite_saveas_button(block, post_action);
UI_block_bounds_set_centered(block, 14 * UI_SCALE_FAC);
return block;
}
void wm_save_file_forwardcompat_dialog(bContext *C, wmOperator *op)
void wm_save_file_overwrite_dialog(bContext *C, wmOperator *op)
{
if (!UI_popup_block_name_exists(CTX_wm_screen(C), save_file_forwardcompat_dialog_name)) {
if (!UI_popup_block_name_exists(CTX_wm_screen(C), save_file_overwrite_dialog_name)) {
wmGenericCallback *callback = MEM_cnew<wmGenericCallback>(__func__);
callback->exec = nullptr;
callback->user_data = IDP_CopyProperty(op->properties);
callback->free_user_data = wm_free_operator_properties_callback;
UI_popup_block_invoke(
C, block_create_save_file_forwardcompat_dialog, callback, free_post_file_close_action);
C, block_create_save_file_overwrite_dialog, callback, free_post_file_close_action);
}
}
@ -4245,7 +4291,7 @@ static void wm_block_file_close_discard_button(uiBlock *block, wmGenericCallback
static void wm_block_file_close_save_button(uiBlock *block,
wmGenericCallback *post_action,
const bool has_forwardcompat_issues)
const bool needs_overwrite_confirm)
{
uiBut *but = uiDefIconTextBut(
block,
@ -4253,7 +4299,7 @@ static void wm_block_file_close_save_button(uiBlock *block,
0,
ICON_NONE,
/* Forward compatibility issues force using 'save as' operator instead of 'save' one. */
has_forwardcompat_issues ? IFACE_("Save As...") : IFACE_("Save"),
needs_overwrite_confirm ? IFACE_("Save As...") : IFACE_("Save"),
0,
0,
0,
@ -4289,7 +4335,7 @@ static uiBlock *block_create__close_file_dialog(bContext *C, ARegion *region, vo
uiLayout *layout = uiItemsAlertBox(block, 34, ALERT_ICON_QUESTION);
const bool has_forwardcompat_issues = bmain->has_forward_compatibility_issues;
const bool needs_overwrite_confirm = BKE_main_needs_overwrite_confirm(bmain);
/* Title. */
uiItemL_ex(layout, RPT_("Save changes before closing?"), ICON_NONE, true, false);
@ -4306,8 +4352,8 @@ static uiBlock *block_create__close_file_dialog(bContext *C, ARegion *region, vo
uiItemL(layout, filename, ICON_NONE);
/* Potential forward compatibility issues message. */
if (has_forwardcompat_issues) {
file_forwardcompat_detailed_info_show(layout, bmain);
if (needs_overwrite_confirm) {
file_overwrite_detailed_info_show(layout, bmain);
}
/* Image Saving Warnings. */
@ -4416,7 +4462,7 @@ static uiBlock *block_create__close_file_dialog(bContext *C, ARegion *region, vo
uiLayoutSetScaleY(split, 1.2f);
uiLayoutColumn(split, false);
wm_block_file_close_save_button(block, post_action, has_forwardcompat_issues);
wm_block_file_close_save_button(block, post_action, needs_overwrite_confirm);
uiLayoutColumn(split, false);
wm_block_file_close_discard_button(block, post_action);
@ -4442,7 +4488,7 @@ static uiBlock *block_create__close_file_dialog(bContext *C, ARegion *region, vo
wm_block_file_close_cancel_button(block, post_action);
uiLayoutColumn(split_right, false);
wm_block_file_close_save_button(block, post_action, has_forwardcompat_issues);
wm_block_file_close_save_button(block, post_action, needs_overwrite_confirm);
}
UI_block_bounds_set_centered(block, 14 * UI_SCALE_FAC);

View File

@ -97,7 +97,7 @@ bool wm_file_or_session_data_has_unsaved_changes(const Main *bmain, const wmWind
*
* Important to ask confirmation, as this is a very common scenario of data loss.
*/
void wm_save_file_forwardcompat_dialog(bContext *C, wmOperator *op);
void wm_save_file_overwrite_dialog(bContext *C, wmOperator *op);
void WM_OT_save_homefile(wmOperatorType *ot);
void WM_OT_save_userpref(wmOperatorType *ot);