WIP: Brush assets project #106303

Draft
Julian Eisel wants to merge 351 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.
18 changed files with 370 additions and 262 deletions
Showing only changes of commit b83ac545ec - Show all commits

View File

@ -134,9 +134,18 @@ BUILD_MANDATORY_SUBPACKAGES = (
},
),
Package(name="Git",
sub_packages=(
Package(name="Git LFS",
distro_package_names={DISTRO_ID_DEBIAN: "git-lfs",
DISTRO_ID_FEDORA: "git-lfs",
DISTRO_ID_SUSE: "git-lfs",
DISTRO_ID_ARCH: "git-lfs",
},
),
),
distro_package_names={DISTRO_ID_DEBIAN: "git",
DISTRO_ID_FEDORA: "git",
DISTRO_ID_SUSE: None,
DISTRO_ID_SUSE: "git",
DISTRO_ID_ARCH: "git",
},
),

View File

@ -108,7 +108,9 @@ LightTreeEmitter::LightTreeEmitter(Scene *scene,
/* TODO: need a better way to handle this when textures are used. */
float area = triangle_area(vertices[0], vertices[1], vertices[2]);
measure.energy = area * average(shader->emission_estimate);
/* Use absolute value of emission_estimate so lights with negative strength are properly
* supported in the light tree. */
measure.energy = area * average(fabs(shader->emission_estimate));
/* NOTE: the original implementation used the bounding box centroid, but triangle centroid
* seems to work fine */
@ -220,7 +222,7 @@ LightTreeEmitter::LightTreeEmitter(Scene *scene,
/* Use absolute value of energy so lights with negative strength are properly supported in the
* light tree. */
measure.energy = fabsf(average(strength));
measure.energy = average(fabs(strength));
light_set_membership = lamp->get_light_set_membership();
}

View File

@ -264,7 +264,7 @@ void Shader::estimate_emission()
}
ShaderInput *surf = graph->output()->input("Surface");
emission_estimate = fabs(output_estimate_emission(surf->link, emission_is_constant));
emission_estimate = output_estimate_emission(surf->link, emission_is_constant);
if (is_zero(emission_estimate)) {
emission_sampling = EMISSION_SAMPLING_NONE;
@ -274,8 +274,9 @@ void Shader::estimate_emission()
* using a lot of memory in the light tree and potentially wasting samples
* where indirect light samples are sufficient.
* Possible optimization: estimate front and back emission separately. */
emission_sampling = (reduce_max(emission_estimate) > 0.5f) ? EMISSION_SAMPLING_FRONT_BACK :
EMISSION_SAMPLING_NONE;
emission_sampling = (reduce_max(fabs(emission_estimate)) > 0.5f) ?
EMISSION_SAMPLING_FRONT_BACK :
EMISSION_SAMPLING_NONE;
}
else {
emission_sampling = emission_sampling_method;

@ -1 +1 @@
Subproject commit d2eea8a8a6b22d6ec6849deea72e141fc5b384d4
Subproject commit 014844518a90dd96685f6f3f114b9ce6b2522e43

@ -1 +1 @@
Subproject commit 6c8139034cfb05f8dee9f6648d31443792c160b5
Subproject commit 9e78c2e377a75ab8fa33430d8e6567f34b2b05b2

@ -1 +1 @@
Subproject commit bf950af1a7d197675bd28ce7d4920ba2b4a0a4f6
Subproject commit 0a6d9ad4c6effa4227a9c0a324c7b588c1f9f71b

@ -1 +1 @@
Subproject commit 2935423fe0636157750feef1fc02d8d0c3efd9dd
Subproject commit 19b2b87f5ef0d8caa39e0882fbf832052974b785

@ -1 +1 @@
Subproject commit 38a8f38d98987efc9aebe878ca941d99756e914e
Subproject commit 3a36a5abc7b8866fe1e4d23ddea9aed1ff01c80d

View File

@ -450,7 +450,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
** AutoPackage; version 1.0 -- http://autopackage.org
BinReloc - a library for creating relocatable executables
Written by: Hongli Lai <h.lai@chello.nl>
** LZMA SDK; version 5.2.5 -- https://www.7-zip.org/sdk.html
** LZMA SDK; version 23.01 -- https://www.7-zip.org/sdk.html
LZMA SDK: Public Domain
Creative Commons Legal Code
@ -3462,7 +3462,7 @@ SOFTWARE.
------
** {fmt}; version 10.0.0 -- https://github.com/fmtlib/fmt
** {fmt}; version 10.1.1 -- https://github.com/fmtlib/fmt
Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
** Brotli; version 1.0.9 -- https://github.com/google/brotli
Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.

View File

@ -31,9 +31,9 @@
*/
#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h"
#include "BLI_set.hh"
#include "BLI_utildefines.h"
#include "BLI_vector.hh"
#include "DNA_userdef_enums.h"
@ -662,9 +662,8 @@ bool BKE_id_is_editable(const Main *bmain, const ID *id);
/**
* Returns ordered list of data-blocks for display in the UI.
* Result is list of #LinkData of IDs that must be freed.
*/
void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb);
blender::Vector<ID *> BKE_id_ordered_list(const ListBase *lb);
/**
* Reorder ID in the list, before or after the "relative" ID.
*/

View File

@ -15,3 +15,9 @@ struct Library;
struct Main;
void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath);
/**
* Rebuild the hierarchy of libraries, after e.g. deleting or relocating one, often some indirectly
* linked libraries lose their 'parent' pointer, making them wrongly directly used ones.
*/
void BKE_library_main_rebuild_hierarchy(Main *bmain);

View File

@ -43,6 +43,7 @@
#include "BKE_lib_override.hh"
#include "BKE_lib_query.hh"
#include "BKE_lib_remap.hh"
#include "BKE_library.hh"
#include "BKE_main.hh"
#include "BKE_main_namemap.hh"
#include "BKE_material.h"
@ -1916,6 +1917,8 @@ void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context,
}
FOREACH_MAIN_ID_END;
BKE_library_main_rebuild_hierarchy(bmain);
/* Resync overrides if needed. */
if (!USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) {
BlendFileReadReport report{};

View File

@ -77,6 +77,8 @@
# include "BLI_time_utildefines.h"
#endif
using blender::Vector;
using namespace blender::bke::id;
static CLG_LogRef LOG = {"bke.lib_id"};
@ -2165,43 +2167,40 @@ static int *id_order_get(ID *id)
}
}
static int id_order_compare(const void *a, const void *b)
static bool id_order_compare(ID *a, ID *b)
{
ID *id_a = static_cast<ID *>(((LinkData *)a)->data);
ID *id_b = static_cast<ID *>(((LinkData *)b)->data);
int *order_a = id_order_get(id_a);
int *order_b = id_order_get(id_b);
int *order_a = id_order_get(a);
int *order_b = id_order_get(b);
if (order_a && order_b) {
if (*order_a < *order_b) {
return -1;
return true;
}
if (*order_a > *order_b) {
return 1;
return false;
}
}
return strcmp(id_a->name, id_b->name);
return strcmp(a->name, b->name) <= 0;
}
void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb)
Vector<ID *> BKE_id_ordered_list(const ListBase *lb)
{
BLI_listbase_clear(ordered_lb);
Vector<ID *> ordered;
LISTBASE_FOREACH (ID *, id, lb) {
BLI_addtail(ordered_lb, BLI_genericNodeN(id));
ordered.append(id);
}
BLI_listbase_sort(ordered_lb, id_order_compare);
std::sort(ordered.begin(), ordered.end(), id_order_compare);
int num = 0;
LISTBASE_FOREACH (LinkData *, link, ordered_lb) {
int *order = id_order_get(static_cast<ID *>(link->data));
if (order) {
*order = num++;
for (const int i : ordered.index_range()) {
if (int *order = id_order_get(ordered[i])) {
*order = i;
}
}
return ordered;
}
void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after)

View File

@ -29,6 +29,7 @@
#include "BKE_lib_id.hh"
#include "BKE_lib_override.hh"
#include "BKE_lib_remap.hh"
#include "BKE_library.hh"
#include "BKE_main.hh"
#include "BKE_main_namemap.hh"
@ -210,9 +211,15 @@ void BKE_id_free_us(Main *bmain, void *idv) /* test users */
}
if (id->us == 0) {
const bool is_lib = GS(id->name) == ID_LI;
BKE_libblock_unlink(bmain, id, false);
BKE_id_free(bmain, id);
if (is_lib) {
BKE_library_main_rebuild_hierarchy(bmain);
}
}
}
@ -220,6 +227,8 @@ static size_t id_delete(Main *bmain,
blender::Set<ID *> &ids_to_delete,
const int extra_remapping_flags)
{
bool has_deleted_library = false;
/* Used by batch tagged deletion, when we call BKE_id_free then, id is no more in Main database,
* and has already properly unlinked its other IDs usages.
* UI users are always cleared in BKE_libblock_remap_locked() call, so we can always skip it. */
@ -318,6 +327,10 @@ static size_t id_delete(Main *bmain,
* remapping code, depending on order in which these are handled). */
id->us = ID_FAKE_USERS(id);
if (!has_deleted_library && GS(id->name) == ID_LI) {
has_deleted_library = true;
}
id_free(bmain, id, free_flag, false);
}
@ -325,6 +338,10 @@ static size_t id_delete(Main *bmain,
BKE_layer_collection_resync_allow();
BKE_main_collection_sync_remap(bmain);
if (has_deleted_library) {
BKE_library_main_rebuild_hierarchy(bmain);
}
bmain->is_memfile_undo_written = false;
return size_t(ids_to_delete.size());
}

View File

@ -14,6 +14,8 @@
#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
#include "BLI_set.hh"
#include "BLT_translation.hh"
@ -132,3 +134,158 @@ void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
BLI_path_abs(lib->filepath_abs, blendfile_path);
}
}
static void rebuild_hierarchy_best_parent_find(Main *bmain,
blender::Set<Library *> &directly_used_libs,
Library *lib)
{
BLI_assert(!directly_used_libs.contains(lib));
Library *best_parent_lib = nullptr;
bool do_break = false;
ListBase *lb;
ID *id_iter;
FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
FOREACH_MAIN_LISTBASE_ID_BEGIN (lb, id_iter) {
if (!ID_IS_LINKED(id_iter) || id_iter->lib != lib) {
continue;
}
MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
BLI_ghash_lookup(bmain->relations->relations_from_pointers, id_iter));
for (MainIDRelationsEntryItem *item = entry->from_ids; item; item = item->next) {
ID *from_id = item->id_pointer.from;
if (!ID_IS_LINKED(from_id)) {
BLI_assert_unreachable();
continue;
}
Library *from_id_lib = from_id->lib;
if (from_id_lib == lib) {
continue;
}
if (directly_used_libs.contains(from_id_lib)) {
/* Found the first best possible candidate, no need to search further. */
BLI_assert(best_parent_lib == nullptr || best_parent_lib->temp_index > 0);
best_parent_lib = from_id_lib;
do_break = true;
break;
}
if (!from_id_lib->parent) {
rebuild_hierarchy_best_parent_find(bmain, directly_used_libs, from_id_lib);
}
if (!best_parent_lib || best_parent_lib->temp_index > from_id_lib->temp_index) {
best_parent_lib = from_id_lib;
if (best_parent_lib->temp_index == 0) {
/* Found the first best possible candidate, no need to search further. */
BLI_assert(directly_used_libs.contains(best_parent_lib));
do_break = true;
break;
}
}
}
if (do_break) {
break;
}
}
FOREACH_MAIN_LISTBASE_ID_END;
if (do_break) {
break;
}
}
FOREACH_MAIN_LISTBASE_END;
/* NOTE: It may happen that no parent library is found, e.g. if after deleting a directly used
* library, its indirect dependency is still around, but none of its linked IDs are used by local
* data. */
if (best_parent_lib) {
lib->parent = best_parent_lib;
lib->temp_index = best_parent_lib->temp_index + 1;
}
else {
lib->parent = nullptr;
lib->temp_index = 0;
directly_used_libs.add(lib);
}
}
void BKE_library_main_rebuild_hierarchy(Main *bmain)
{
BKE_main_relations_create(bmain, 0);
/* Find all libraries with directly linked IDs (i.e. IDs used by local data). */
blender::Set<Library *> directly_used_libs;
ID *id_iter;
FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
if (!ID_IS_LINKED(id_iter)) {
continue;
}
id_iter->lib->temp_index = 0;
if (directly_used_libs.contains(id_iter->lib)) {
continue;
}
MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
BLI_ghash_lookup(bmain->relations->relations_from_pointers, id_iter));
for (MainIDRelationsEntryItem *item = entry->from_ids; item; item = item->next) {
if (!ID_IS_LINKED(item->id_pointer.from)) {
directly_used_libs.add(id_iter->lib);
id_iter->lib->parent = nullptr;
break;
}
}
}
FOREACH_MAIN_ID_END;
LISTBASE_FOREACH (Library *, lib_iter, &bmain->libraries) {
/* A directly used library. */
if (directly_used_libs.contains(lib_iter)) {
BLI_assert(lib_iter->temp_index == 0);
continue;
}
/* Assume existing parent is still valid, since it was not cleared in previous loop above.
* Just compute 'hierarchy value' in temp index, if needed. */
if (lib_iter->parent) {
if (lib_iter->temp_index > 0) {
continue;
}
blender::Vector<Library *> parent_libraries;
for (Library *parent_lib_iter = lib_iter;
parent_lib_iter && parent_lib_iter->temp_index == 0;
parent_lib_iter = parent_lib_iter->parent)
{
parent_libraries.append(parent_lib_iter);
}
int parent_temp_index = parent_libraries.last()->temp_index + int(parent_libraries.size()) -
1;
for (Library *parent_lib_iter : parent_libraries) {
BLI_assert(parent_lib_iter != parent_libraries.last() ||
parent_lib_iter->temp_index == parent_temp_index);
parent_lib_iter->temp_index = parent_temp_index--;
}
continue;
}
/* Otherwise, it's an indirectly used library with no known parent, another loop is needed to
* ansure all knwon hierarcy has valid indices when trying to find the best valid parent
* library. */
}
/* For all libraries known to be indirect, but without a known parent, find a best valid parent
* (i.e. a 'most directly used' library). */
LISTBASE_FOREACH (Library *, lib_iter, &bmain->libraries) {
/* A directly used library. */
if (directly_used_libs.contains(lib_iter)) {
BLI_assert(lib_iter->temp_index == 0);
continue;
}
if (lib_iter->parent) {
BLI_assert(lib_iter->temp_index > 0);
}
else {
BLI_assert(lib_iter->temp_index == 0);
rebuild_hierarchy_best_parent_find(bmain, directly_used_libs, lib_iter);
}
}
BKE_main_relations_free(bmain);
}

View File

@ -97,6 +97,8 @@
#include "UI_string_search.hh"
#include "interface_intern.hh"
using blender::Vector;
/* we may want to make this optional, disable for now. */
// #define USE_OP_RESET_BUT
@ -1659,11 +1661,7 @@ static void template_ID_tabs(const bContext *C,
uiBlock *block = uiLayoutGetBlock(layout);
const uiStyle *style = UI_style_get_dpi();
ListBase ordered;
BKE_id_ordered_list(&ordered, template_id->idlb);
LISTBASE_FOREACH (LinkData *, link, &ordered) {
ID *id = static_cast<ID *>(link->data);
for (ID *id : BKE_id_ordered_list(template_id->idlb)) {
const int name_width = UI_fontstyle_string_width(&style->widget, id->name + 2);
const int but_width = name_width + UI_UNIT_X;
@ -1689,8 +1687,6 @@ static void template_ID_tabs(const bContext *C,
UI_but_drawflag_enable(tab, but_align);
}
BLI_freelistN(&ordered);
if (flag & UI_ID_ADD_NEW) {
const bool editable = RNA_property_editable(&template_id->ptr, template_id->prop);
uiBut *but;
@ -3378,14 +3374,18 @@ struct RNAUpdateCb {
PropertyRNA *prop;
};
static void rna_update_cb(bContext *C, void *arg_cb, void * /*arg*/)
static void rna_update_cb(bContext &C, const RNAUpdateCb &cb)
{
RNAUpdateCb *cb = (RNAUpdateCb *)arg_cb;
/* we call update here on the pointer property, this way the
* owner of the curve mapping can still define its own update
* and notifier, even if the CurveMapping struct is shared. */
RNA_property_update(C, &cb->ptr, cb->prop);
RNA_property_update(&C, &const_cast<PointerRNA &>(cb.ptr), cb.prop);
}
static void rna_update_cb(bContext *C, void *arg_cb, void * /*arg*/)
{
RNAUpdateCb *cb = (RNAUpdateCb *)arg_cb;
rna_update_cb(*C, *cb);
}
enum {
@ -3553,33 +3553,22 @@ static uiBlock *colorband_tools_func(bContext *C, ARegion *region, void *arg_cb)
return block;
}
static void colorband_add_cb(bContext *C, void *cb_v, void *coba_v)
static void colorband_add(bContext &C, const RNAUpdateCb &cb, ColorBand &coba)
{
ColorBand *coba = static_cast<ColorBand *>(coba_v);
float pos = 0.5f;
if (coba->tot > 1) {
if (coba->cur > 0) {
pos = (coba->data[coba->cur - 1].pos + coba->data[coba->cur].pos) * 0.5f;
if (coba.tot > 1) {
if (coba.cur > 0) {
pos = (coba.data[coba.cur - 1].pos + coba.data[coba.cur].pos) * 0.5f;
}
else {
pos = (coba->data[coba->cur + 1].pos + coba->data[coba->cur].pos) * 0.5f;
pos = (coba.data[coba.cur + 1].pos + coba.data[coba.cur].pos) * 0.5f;
}
}
if (BKE_colorband_element_add(coba, pos)) {
rna_update_cb(C, cb_v, nullptr);
ED_undo_push(C, "Add Color Ramp Stop");
}
}
static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v)
{
ColorBand *coba = static_cast<ColorBand *>(coba_v);
if (BKE_colorband_element_remove(coba, coba->cur)) {
ED_undo_push(C, "Delete Color Ramp Stop");
rna_update_cb(C, cb_v, nullptr);
if (BKE_colorband_element_add(&coba, pos)) {
rna_update_cb(C, cb);
ED_undo_push(&C, "Add Color Ramp Stop");
}
}
@ -3598,7 +3587,7 @@ static void colorband_buttons_layout(uiLayout *layout,
uiBlock *block,
ColorBand *coba,
const rctf *butr,
RNAUpdateCb *cb,
const RNAUpdateCb &cb,
int expand)
{
uiBut *bt;
@ -3606,7 +3595,7 @@ static void colorband_buttons_layout(uiLayout *layout,
const float xs = butr->xmin;
const float ys = butr->ymin;
PointerRNA ptr = RNA_pointer_create(cb->ptr.owner_id, &RNA_ColorRamp, coba);
PointerRNA ptr = RNA_pointer_create(cb.ptr.owner_id, &RNA_ColorRamp, coba);
uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
@ -3629,7 +3618,7 @@ static void colorband_buttons_layout(uiLayout *layout,
0,
0,
TIP_("Add a new color stop to the color ramp"));
UI_but_funcN_set(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
UI_but_func_set(bt, [coba, cb](bContext &C) { colorband_add(C, cb, *coba); });
bt = uiDefIconTextBut(block,
UI_BTYPE_BUT,
@ -3646,9 +3635,14 @@ static void colorband_buttons_layout(uiLayout *layout,
0,
0,
TIP_("Delete the active position"));
UI_but_funcN_set(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
UI_but_func_set(bt, [coba, cb](bContext &C) {
if (BKE_colorband_element_remove(coba, coba->cur)) {
rna_update_cb(C, cb);
ED_undo_push(&C, "Delete Color Ramp Stop");
}
});
RNAUpdateCb *tools_cb = static_cast<RNAUpdateCb *>(MEM_dupallocN(cb));
RNAUpdateCb *tools_cb = MEM_new<RNAUpdateCb>(__func__, cb);
bt = uiDefIconBlockBut(block,
colorband_tools_func,
tools_cb,
@ -3692,14 +3686,14 @@ static void colorband_buttons_layout(uiLayout *layout,
0,
0,
"");
UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), nullptr);
UI_but_func_set(bt, [cb](bContext &C) { rna_update_cb(C, cb); });
row = uiLayoutRow(layout, false);
if (coba->tot) {
CBData *cbd = coba->data + coba->cur;
ptr = RNA_pointer_create(cb->ptr.owner_id, &RNA_ColorRampElement, cbd);
ptr = RNA_pointer_create(cb.ptr.owner_id, &RNA_ColorRampElement, cbd);
if (!expand) {
split = uiLayoutSplit(layout, 0.3f, false);
@ -3770,7 +3764,7 @@ static void colorband_buttons_layout(uiLayout *layout,
}
if (STREQ(prop_identifier, "color")) {
UI_but_funcN_set(but, rna_update_cb, MEM_dupallocN(cb), nullptr);
UI_but_func_set(bt, [cb](bContext &C) { rna_update_cb(C, cb); });
}
}
}
@ -3789,10 +3783,6 @@ void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname
return;
}
RNAUpdateCb *cb = MEM_cnew<RNAUpdateCb>("RNAUpdateCb");
cb->ptr = *ptr;
cb->prop = prop;
rctf rect;
rect.xmin = 0;
rect.xmax = 10.0f * UI_UNIT_X;
@ -3804,11 +3794,10 @@ void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname
ID *id = cptr.owner_id;
UI_block_lock_set(block, (id && ID_IS_LINKED(id)), ERROR_LIBDATA_MESSAGE);
colorband_buttons_layout(layout, block, static_cast<ColorBand *>(cptr.data), &rect, cb, expand);
colorband_buttons_layout(
layout, block, static_cast<ColorBand *>(cptr.data), &rect, RNAUpdateCb{*ptr, prop}, expand);
UI_block_lock_clear(block);
MEM_freeN(cb);
}
/** \} */
@ -4169,10 +4158,8 @@ static bool curvemap_can_zoom_in(CurveMapping *cumap)
return BLI_rctf_size_x(&cumap->curr) > CURVE_ZOOM_MAX * BLI_rctf_size_x(&cumap->clipr);
}
static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void * /*arg*/)
static void curvemap_buttons_zoom_in(bContext *C, CurveMapping *cumap)
{
CurveMapping *cumap = static_cast<CurveMapping *>(cumap_v);
if (curvemap_can_zoom_in(cumap)) {
const float dx = 0.1154f * BLI_rctf_size_x(&cumap->curr);
cumap->curr.xmin += dx;
@ -4185,9 +4172,8 @@ static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void * /*arg*/)
ED_region_tag_redraw(CTX_wm_region(C));
}
static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void * /*unused*/)
static void curvemap_buttons_zoom_out(bContext *C, CurveMapping *cumap)
{
CurveMapping *cumap = static_cast<CurveMapping *>(cumap_v);
float d, d1;
if (curvemap_can_zoom_out(cumap)) {
@ -4229,23 +4215,6 @@ static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void * /*unuse
ED_region_tag_redraw(CTX_wm_region(C));
}
static void curvemap_buttons_setclip(bContext * /*C*/, void *cumap_v, void * /*arg*/)
{
CurveMapping *cumap = static_cast<CurveMapping *>(cumap_v);
BKE_curvemapping_changed(cumap, false);
}
static void curvemap_buttons_delete(bContext *C, void *cb_v, void *cumap_v)
{
CurveMapping *cumap = static_cast<CurveMapping *>(cumap_v);
BKE_curvemap_remove(cumap->cm + cumap->cur, SELECT);
BKE_curvemapping_changed(cumap, false);
rna_update_cb(C, cb_v, nullptr);
}
/* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
static uiBlock *curvemap_clipping_func(bContext *C, ARegion *region, void *cumap_v)
{
@ -4270,7 +4239,7 @@ static uiBlock *curvemap_clipping_func(bContext *C, ARegion *region, void *cumap
0.0,
0.0,
"");
UI_but_func_set(bt, curvemap_buttons_setclip, cumap, nullptr);
UI_but_func_set(bt, [cumap](bContext & /*C*/) { BKE_curvemapping_changed(cumap, false); });
UI_block_align_begin(block);
bt = uiDefButF(block,
@ -4514,33 +4483,9 @@ static void curvemap_tools_handle_auto_clamped(bContext *C, void *cumap_v, void
curvemap_tools_dofunc(C, cumap_v, UICURVE_FUNC_HANDLE_AUTO_ANIM);
}
static void curvemap_buttons_redraw(bContext *C, void * /*arg1*/, void * /*arg2*/)
static void curvemap_buttons_redraw(bContext &C)
{
ED_region_tag_redraw(CTX_wm_region(C));
}
static void curvemap_buttons_update(bContext *C, void *arg1_v, void *cumap_v)
{
CurveMapping *cumap = static_cast<CurveMapping *>(cumap_v);
BKE_curvemapping_changed(cumap, true);
rna_update_cb(C, arg1_v, nullptr);
}
static void curvemap_buttons_reset(bContext *C, void *cb_v, void *cumap_v)
{
CurveMapping *cumap = static_cast<CurveMapping *>(cumap_v);
cumap->preset = CURVE_PRESET_LINE;
for (int a = 0; a < CM_TOT; a++) {
BKE_curvemap_reset(cumap->cm + a, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_POSITIVE);
}
cumap->black[0] = cumap->black[1] = cumap->black[2] = 0.0f;
cumap->white[0] = cumap->white[1] = cumap->white[2] = 1.0f;
BKE_curvemapping_set_black_white(cumap, nullptr, nullptr);
BKE_curvemapping_changed(cumap, false);
rna_update_cb(C, cb_v, nullptr);
ED_region_tag_redraw(CTX_wm_region(&C));
}
/**
@ -4555,7 +4500,7 @@ static void curvemap_buttons_layout(uiLayout *layout,
bool brush,
bool neg_slope,
bool tone,
RNAUpdateCb *cb)
const RNAUpdateCb &cb)
{
CurveMapping *cumap = static_cast<CurveMapping *>(ptr->data);
CurveMap *cm = &cumap->cm[cumap->cur];
@ -4583,17 +4528,17 @@ static void curvemap_buttons_layout(uiLayout *layout,
if (cumap->cm[0].curve) {
bt = uiDefButI(
block, UI_BTYPE_ROW, 0, "X", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
UI_but_func_set(bt, curvemap_buttons_redraw, nullptr, nullptr);
UI_but_func_set(bt, curvemap_buttons_redraw);
}
if (cumap->cm[1].curve) {
bt = uiDefButI(
block, UI_BTYPE_ROW, 0, "Y", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
UI_but_func_set(bt, curvemap_buttons_redraw, nullptr, nullptr);
UI_but_func_set(bt, curvemap_buttons_redraw);
}
if (cumap->cm[2].curve) {
bt = uiDefButI(
block, UI_BTYPE_ROW, 0, "Z", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
UI_but_func_set(bt, curvemap_buttons_redraw, nullptr, nullptr);
UI_but_func_set(bt, curvemap_buttons_redraw);
}
}
else if (labeltype == 'c') {
@ -4616,22 +4561,22 @@ static void curvemap_buttons_layout(uiLayout *layout,
0.0,
0.0,
"");
UI_but_func_set(bt, curvemap_buttons_redraw, nullptr, nullptr);
UI_but_func_set(bt, curvemap_buttons_redraw);
}
if (cumap->cm[0].curve) {
bt = uiDefButI(
block, UI_BTYPE_ROW, 0, IFACE_("R"), 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
UI_but_func_set(bt, curvemap_buttons_redraw, nullptr, nullptr);
UI_but_func_set(bt, curvemap_buttons_redraw);
}
if (cumap->cm[1].curve) {
bt = uiDefButI(
block, UI_BTYPE_ROW, 0, IFACE_("G"), 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
UI_but_func_set(bt, curvemap_buttons_redraw, nullptr, nullptr);
UI_but_func_set(bt, curvemap_buttons_redraw);
}
if (cumap->cm[2].curve) {
bt = uiDefButI(
block, UI_BTYPE_ROW, 0, IFACE_("B"), 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
UI_but_func_set(bt, curvemap_buttons_redraw, nullptr, nullptr);
UI_but_func_set(bt, curvemap_buttons_redraw);
}
}
else if (labeltype == 'h') {
@ -4642,17 +4587,17 @@ static void curvemap_buttons_layout(uiLayout *layout,
if (cumap->cm[0].curve) {
bt = uiDefButI(
block, UI_BTYPE_ROW, 0, IFACE_("H"), 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
UI_but_func_set(bt, curvemap_buttons_redraw, nullptr, nullptr);
UI_but_func_set(bt, curvemap_buttons_redraw);
}
if (cumap->cm[1].curve) {
bt = uiDefButI(
block, UI_BTYPE_ROW, 0, IFACE_("S"), 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
UI_but_func_set(bt, curvemap_buttons_redraw, nullptr, nullptr);
UI_but_func_set(bt, curvemap_buttons_redraw);
}
if (cumap->cm[2].curve) {
bt = uiDefButI(
block, UI_BTYPE_ROW, 0, IFACE_("V"), 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
UI_but_func_set(bt, curvemap_buttons_redraw, nullptr, nullptr);
UI_but_func_set(bt, curvemap_buttons_redraw);
}
}
else {
@ -4683,7 +4628,7 @@ static void curvemap_buttons_layout(uiLayout *layout,
0.0,
0.0,
TIP_("Zoom in"));
UI_but_func_set(bt, curvemap_buttons_zoom_in, cumap, nullptr);
UI_but_func_set(bt, [cumap](bContext &C) { curvemap_buttons_zoom_in(&C, cumap); });
if (!curvemap_can_zoom_in(cumap)) {
UI_but_disable(bt, "");
}
@ -4703,7 +4648,7 @@ static void curvemap_buttons_layout(uiLayout *layout,
0.0,
0.0,
TIP_("Zoom out"));
UI_but_func_set(bt, curvemap_buttons_zoom_out, cumap, nullptr);
UI_but_func_set(bt, [cumap](bContext &C) { curvemap_buttons_zoom_out(&C, cumap); });
if (!curvemap_can_zoom_out(cumap)) {
UI_but_disable(bt, "");
}
@ -4713,7 +4658,7 @@ static void curvemap_buttons_layout(uiLayout *layout,
bt = uiDefIconBlockBut(
block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, dx, TIP_("Clipping Options"));
bt->drawflag &= ~UI_BUT_ICON_LEFT;
UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), nullptr);
UI_but_func_set(bt, [cb](bContext &C) { rna_update_cb(C, cb); });
if (brush && neg_slope) {
bt = uiDefIconBlockBut(block,
@ -4739,9 +4684,9 @@ static void curvemap_buttons_layout(uiLayout *layout,
bt = uiDefIconBlockBut(
block, curvemap_tools_posslope_func, cumap, 0, ICON_NONE, 0, 0, dx, dx, TIP_("Tools"));
}
UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), nullptr);
UI_but_func_set(bt, [cb](bContext &C) { rna_update_cb(C, cb); });
UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), nullptr);
UI_block_funcN_set(block, rna_update_cb, MEM_new<RNAUpdateCb>(__func__, cb), nullptr);
/* Curve itself. */
const int size = max_ii(uiLayoutGetWidth(layout), UI_UNIT_X);
@ -4839,7 +4784,10 @@ static void curvemap_buttons_layout(uiLayout *layout,
}
/* Curve handle position */
UI_block_funcN_set(block, curvemap_buttons_update, MEM_dupallocN(cb), cumap);
UI_but_func_set(bt, [cumap, cb](bContext &C) {
BKE_curvemapping_changed(cumap, true);
rna_update_cb(C, cb);
});
bt = uiDefButF(block,
UI_BTYPE_NUM,
0,
@ -4884,7 +4832,11 @@ static void curvemap_buttons_layout(uiLayout *layout,
0.0,
0.0,
TIP_("Delete points"));
UI_but_funcN_set(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
UI_but_func_set(bt, [cumap, cb](bContext &C) {
BKE_curvemap_remove(cumap->cm + cumap->cur, SELECT);
BKE_curvemapping_changed(cumap, false);
rna_update_cb(C, cb);
});
if (point_last_or_first) {
UI_but_flag_enable(bt, UI_BUT_DISABLED);
}
@ -4913,7 +4865,19 @@ static void curvemap_buttons_layout(uiLayout *layout,
0,
0,
TIP_("Reset Black/White point and curves"));
UI_but_funcN_set(bt, curvemap_buttons_reset, MEM_dupallocN(cb), cumap);
UI_but_func_set(bt, [cumap, cb](bContext &C) {
cumap->preset = CURVE_PRESET_LINE;
for (int a = 0; a < CM_TOT; a++) {
BKE_curvemap_reset(cumap->cm + a, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_POSITIVE);
}
cumap->black[0] = cumap->black[1] = cumap->black[2] = 0.0f;
cumap->white[0] = cumap->white[1] = cumap->white[2] = 1.0f;
BKE_curvemapping_set_black_white(cumap, nullptr, nullptr);
BKE_curvemapping_changed(cumap, false);
rna_update_cb(C, cb);
});
}
UI_block_funcN_set(block, nullptr, nullptr, nullptr);
@ -4946,18 +4910,13 @@ void uiTemplateCurveMapping(uiLayout *layout,
return;
}
RNAUpdateCb *cb = MEM_cnew<RNAUpdateCb>("RNAUpdateCb");
cb->ptr = *ptr;
cb->prop = prop;
ID *id = cptr.owner_id;
UI_block_lock_set(block, (id && ID_IS_LINKED(id)), ERROR_LIBDATA_MESSAGE);
curvemap_buttons_layout(layout, &cptr, type, levels, brush, neg_slope, tone, cb);
curvemap_buttons_layout(
layout, &cptr, type, levels, brush, neg_slope, tone, RNAUpdateCb{*ptr, prop});
UI_block_lock_clear(block);
MEM_freeN(cb);
}
/** \} */
@ -5155,10 +5114,8 @@ static bool CurveProfile_can_zoom_out(CurveProfile *profile)
return BLI_rctf_size_x(&profile->view_rect) < BLI_rctf_size_x(&profile->clip_rect);
}
static void CurveProfile_buttons_zoom_in(bContext *C, void *profile_v, void * /*arg*/)
static void CurveProfile_buttons_zoom_in(bContext *C, CurveProfile *profile)
{
CurveProfile *profile = static_cast<CurveProfile *>(profile_v);
if (CurveProfile_can_zoom_in(profile)) {
const float dx = 0.1154f * BLI_rctf_size_x(&profile->view_rect);
profile->view_rect.xmin += dx;
@ -5171,10 +5128,8 @@ static void CurveProfile_buttons_zoom_in(bContext *C, void *profile_v, void * /*
ED_region_tag_redraw(CTX_wm_region(C));
}
static void CurveProfile_buttons_zoom_out(bContext *C, void *profile_v, void * /*arg*/)
static void CurveProfile_buttons_zoom_out(bContext *C, CurveProfile *profile)
{
CurveProfile *profile = static_cast<CurveProfile *>(profile_v);
if (CurveProfile_can_zoom_out(profile)) {
float d = 0.15f * BLI_rctf_size_x(&profile->view_rect);
float d1 = d;
@ -5215,51 +5170,7 @@ static void CurveProfile_buttons_zoom_out(bContext *C, void *profile_v, void * /
ED_region_tag_redraw(CTX_wm_region(C));
}
static void CurveProfile_clipping_toggle(bContext *C, void *cb_v, void *profile_v)
{
CurveProfile *profile = static_cast<CurveProfile *>(profile_v);
profile->flag ^= PROF_USE_CLIP;
BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
rna_update_cb(C, cb_v, nullptr);
}
static void CurveProfile_buttons_reverse(bContext *C, void *cb_v, void *profile_v)
{
CurveProfile *profile = static_cast<CurveProfile *>(profile_v);
BKE_curveprofile_reverse(profile);
BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
rna_update_cb(C, cb_v, nullptr);
}
static void CurveProfile_buttons_delete(bContext *C, void *cb_v, void *profile_v)
{
CurveProfile *profile = static_cast<CurveProfile *>(profile_v);
BKE_curveprofile_remove_by_flag(profile, SELECT);
BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
rna_update_cb(C, cb_v, nullptr);
}
static void CurveProfile_buttons_update(bContext *C, void *arg1_v, void *profile_v)
{
CurveProfile *profile = static_cast<CurveProfile *>(profile_v);
BKE_curveprofile_update(profile, PROF_UPDATE_REMOVE_DOUBLES | PROF_UPDATE_CLIP);
rna_update_cb(C, arg1_v, nullptr);
}
static void CurveProfile_buttons_reset(bContext *C, void *arg1_v, void *profile_v)
{
CurveProfile *profile = static_cast<CurveProfile *>(profile_v);
BKE_curveprofile_reset(profile);
BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
rna_update_cb(C, arg1_v, nullptr);
}
static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUpdateCb *cb)
static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, const RNAUpdateCb &cb)
{
CurveProfile *profile = static_cast<CurveProfile *>(ptr->data);
uiBut *bt;
@ -5283,7 +5194,7 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
UI_UNIT_X,
UI_UNIT_X,
"");
UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), nullptr);
UI_but_func_set(bt, [cb](bContext &C) { rna_update_cb(C, cb); });
/* Show a "re-apply" preset button when it has been changed from the preset. */
if (profile->flag & PROF_DIRTY_PRESET) {
@ -5304,7 +5215,11 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
0.0,
0.0,
TIP_("Reapply and update the preset, removing changes"));
UI_but_funcN_set(bt, CurveProfile_buttons_reset, MEM_dupallocN(cb), profile);
UI_but_func_set(bt, [profile, cb](bContext &C) {
BKE_curveprofile_reset(profile);
BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
rna_update_cb(C, cb);
});
}
}
@ -5329,7 +5244,7 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
0.0,
0.0,
TIP_("Zoom in"));
UI_but_func_set(bt, CurveProfile_buttons_zoom_in, profile, nullptr);
UI_but_func_set(bt, [profile](bContext &C) { CurveProfile_buttons_zoom_in(&C, profile); });
if (!CurveProfile_can_zoom_in(profile)) {
UI_but_disable(bt, "");
}
@ -5349,7 +5264,7 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
0.0,
0.0,
TIP_("Zoom out"));
UI_but_func_set(bt, CurveProfile_buttons_zoom_out, profile, nullptr);
UI_but_func_set(bt, [profile](bContext &C) { CurveProfile_buttons_zoom_out(&C, profile); });
if (!CurveProfile_can_zoom_out(profile)) {
UI_but_disable(bt, "");
}
@ -5373,7 +5288,11 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
0.0,
0.0,
TIP_("Reverse Path"));
UI_but_funcN_set(bt, CurveProfile_buttons_reverse, MEM_dupallocN(cb), profile);
UI_but_func_set(bt, [profile, cb](bContext &C) {
BKE_curveprofile_reverse(profile);
BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
rna_update_cb(C, cb);
});
/* Clipping toggle */
const int icon = (profile->flag & PROF_USE_CLIP) ? ICON_CLIPUV_HLT : ICON_CLIPUV_DEHLT;
@ -5391,7 +5310,11 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
0.0,
0.0,
TIP_("Toggle Profile Clipping"));
UI_but_funcN_set(bt, CurveProfile_clipping_toggle, MEM_dupallocN(cb), profile);
UI_but_func_set(bt, [profile, cb](bContext &C) {
profile->flag ^= PROF_USE_CLIP;
BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
rna_update_cb(C, cb);
});
/* Reset view, reset curve */
bt = uiDefIconBlockBut(block,
@ -5404,9 +5327,9 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
UI_UNIT_X,
UI_UNIT_X,
TIP_("Tools"));
UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), nullptr);
UI_but_func_set(bt, [cb](bContext &C) { rna_update_cb(C, cb); });
UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), nullptr);
UI_block_funcN_set(block, rna_update_cb, MEM_new<RNAUpdateCb>(__func__, cb), nullptr);
/* The path itself */
int path_width = max_ii(uiLayoutGetWidth(layout), UI_UNIT_X);
@ -5494,7 +5417,10 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
"");
UI_but_number_step_size_set(bt, 1);
UI_but_number_precision_set(bt, 5);
UI_but_funcN_set(bt, CurveProfile_buttons_update, MEM_dupallocN(cb), profile);
UI_but_func_set(bt, [profile, cb](bContext &C) {
BKE_curveprofile_update(profile, PROF_UPDATE_REMOVE_DOUBLES | PROF_UPDATE_CLIP);
rna_update_cb(C, cb);
});
if (point_last_or_first) {
UI_but_flag_enable(bt, UI_BUT_DISABLED);
}
@ -5512,7 +5438,10 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
"");
UI_but_number_step_size_set(bt, 1);
UI_but_number_precision_set(bt, 5);
UI_but_funcN_set(bt, CurveProfile_buttons_update, MEM_dupallocN(cb), profile);
UI_but_func_set(bt, [profile, cb](bContext &C) {
BKE_curveprofile_update(profile, PROF_UPDATE_REMOVE_DOUBLES | PROF_UPDATE_CLIP);
rna_update_cb(C, cb);
});
if (point_last_or_first) {
UI_but_flag_enable(bt, UI_BUT_DISABLED);
}
@ -5532,7 +5461,11 @@ static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, RNAUp
0.0,
0.0,
TIP_("Delete points"));
UI_but_funcN_set(bt, CurveProfile_buttons_delete, MEM_dupallocN(cb), profile);
UI_but_func_set(bt, [profile, cb](bContext &C) {
BKE_curveprofile_remove_by_flag(profile, SELECT);
BKE_curveprofile_update(profile, PROF_UPDATE_NONE);
rna_update_cb(C, cb);
});
if (point_last_or_first) {
UI_but_flag_enable(bt, UI_BUT_DISABLED);
}
@ -5567,19 +5500,12 @@ void uiTemplateCurveProfile(uiLayout *layout, PointerRNA *ptr, const char *propn
return;
}
/* Share update functionality with the CurveMapping widget template. */
RNAUpdateCb *cb = MEM_cnew<RNAUpdateCb>("RNAUpdateCb");
cb->ptr = *ptr;
cb->prop = prop;
ID *id = cptr.owner_id;
UI_block_lock_set(block, (id && ID_IS_LINKED(id)), ERROR_LIBDATA_MESSAGE);
CurveProfile_buttons_layout(layout, &cptr, cb);
CurveProfile_buttons_layout(layout, &cptr, RNAUpdateCb{*ptr, prop});
UI_block_lock_clear(block);
MEM_freeN(cb);
}
/** \} */

View File

@ -76,6 +76,8 @@
#include "screen_intern.h" /* own module include */
using blender::Vector;
#define KM_MODAL_CANCEL 1
#define KM_MODAL_APPLY 2
#define KM_MODAL_SNAP_ON 3
@ -5788,34 +5790,26 @@ static int space_workspace_cycle_invoke(bContext *C, wmOperator *op, const wmEve
Main *bmain = CTX_data_main(C);
const eScreenCycle direction = eScreenCycle(RNA_enum_get(op->ptr, "direction"));
WorkSpace *workspace_src = WM_window_get_active_workspace(win);
WorkSpace *workspace_dst = nullptr;
ListBase ordered;
BKE_id_ordered_list(&ordered, &bmain->workspaces);
LISTBASE_FOREACH (LinkData *, link, &ordered) {
if (link->data == workspace_src) {
if (direction == SPACE_CONTEXT_CYCLE_PREV) {
workspace_dst = static_cast<WorkSpace *>((link->prev) ? link->prev->data : nullptr);
}
else {
workspace_dst = static_cast<WorkSpace *>((link->next) ? link->next->data : nullptr);
}
}
}
if (workspace_dst == nullptr) {
LinkData *link = static_cast<LinkData *>(
(direction == SPACE_CONTEXT_CYCLE_PREV) ? ordered.last : ordered.first);
workspace_dst = static_cast<WorkSpace *>(link->data);
}
BLI_freelistN(&ordered);
if (workspace_src == workspace_dst) {
Vector<ID *> ordered = BKE_id_ordered_list(&bmain->workspaces);
if (ordered.size() == 1) {
return OPERATOR_CANCELLED;
}
const int index = ordered.first_index_of(&workspace_src->id);
WorkSpace *workspace_dst = nullptr;
switch (direction) {
case SPACE_CONTEXT_CYCLE_PREV:
workspace_dst = reinterpret_cast<WorkSpace *>(index == 0 ? ordered.last() :
ordered[index - 1]);
break;
case SPACE_CONTEXT_CYCLE_NEXT:
workspace_dst = reinterpret_cast<WorkSpace *>(
index == ordered.index_range().last() ? ordered.first() : ordered[index + 1]);
break;
}
win->workspace_hook->temp_workspace_store = workspace_dst;
WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, workspace_dst);
win->workspace_hook->temp_workspace_store = nullptr;

View File

@ -45,6 +45,8 @@
#include "screen_intern.h"
using blender::Vector;
/* -------------------------------------------------------------------- */
/** \name Workspace API
*
@ -242,23 +244,16 @@ bool ED_workspace_delete(WorkSpace *workspace, Main *bmain, bContext *C, wmWindo
return false;
}
ListBase ordered;
BKE_id_ordered_list(&ordered, &bmain->workspaces);
WorkSpace *prev = nullptr, *next = nullptr;
LISTBASE_FOREACH (LinkData *, link, &ordered) {
if (link->data == workspace) {
prev = static_cast<WorkSpace *>(link->prev ? link->prev->data : nullptr);
next = static_cast<WorkSpace *>(link->next ? link->next->data : nullptr);
break;
}
}
BLI_freelistN(&ordered);
BLI_assert((prev != nullptr) || (next != nullptr));
Vector<ID *> ordered = BKE_id_ordered_list(&bmain->workspaces);
const int index = ordered.first_index_of(&workspace->id);
WorkSpace *new_active = reinterpret_cast<WorkSpace *>(index == 0 ? ordered[1] :
ordered[index - 1]);
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
WorkSpace *workspace_active = WM_window_get_active_workspace(win);
if (workspace_active == workspace) {
ED_workspace_change((prev != nullptr) ? prev : next, C, wm, win);
ED_workspace_change(new_active, C, wm, win);
}
}