UI: Consistent Menu/Block/Popup Content Ordering #109798

Merged
Harley Acheson merged 13 commits from Harley/blender:MenuDirection into main 2023-08-31 20:25:02 +02:00
10 changed files with 212 additions and 146 deletions
Showing only changes of commit c087876482 - Show all commits

View File

@ -16,6 +16,9 @@
*/
#ifdef __cplusplus
# include <optional>
extern "C" {
#endif
@ -211,6 +214,12 @@ struct PreviewImage *BKE_previewimg_id_ensure(struct ID *id);
*/
void BKE_previewimg_ensure(struct PreviewImage *prv, int size);
const char *BKE_previewimg_deferred_filepath_get(const struct PreviewImage *prv);
#ifdef __cplusplus
extern "C++" std::optional<int> BKE_previewimg_deferred_thumb_source_get(
const struct PreviewImage *prv);
#endif
/**
* Create an #ImBuf holding a copy of the preview image buffer in \a prv.
* \note The returned image buffer has to be free'd (#IMB_freeImBuf()).

View File

@ -11,6 +11,7 @@
struct Main;
struct ModifierData;
struct Object;
namespace blender {
class fstream;

View File

@ -8,6 +8,7 @@
#pragma once
#include "BLI_array.hh"
#include "BLI_bitmap.h"
#include "BLI_offset_indices.hh"
#include "BLI_sys_types.h"
@ -115,66 +116,66 @@ struct SubdivCCG {
*
* TODO(sergey): Make sure the whole descriptor is valid, including all the
* displacement attached to the surface. */
Subdiv *subdiv;
Subdiv *subdiv = nullptr;
/* A level at which geometry was subdivided. This is what defines grid
* resolution. It is NOT the topology refinement level. */
int level;
int level = -1;
/* Resolution of grid. All grids have matching resolution, and resolution
* is same as ptex created for non-quad faces. */
int grid_size;
int grid_size = -1;
/* Size of a single element of a grid (including coordinate and all the other layers).
* Measured in bytes. */
int grid_element_size;
int grid_element_size = -1;
/* Grids represent limit surface, with displacement applied. Grids are
* corresponding to face-corners of coarse mesh, each grid has
* grid_size^2 elements.
*/
/* Indexed by a grid index, points to a grid data which is stored in
* grids_storage. */
CCGElem **grids;
CCGElem **grids = nullptr;
/* Flat array of all grids' data. */
unsigned char *grids_storage;
int num_grids;
unsigned char *grids_storage = nullptr;
int num_grids = -1;
/* Loose edges, each array element contains grid_size elements
* corresponding to vertices created by subdividing coarse edges. */
CCGElem **edges;
int num_edges;
CCGElem **edges = nullptr;
int num_edges = -1;
/* Loose vertices. Every element corresponds to a loose vertex from a coarse
* mesh, every coarse loose vertex corresponds to a single subdivided
* element. */
CCGElem *vertices;
int num_vertices;
CCGElem *vertices = nullptr;
int num_vertices = -1;
/* Denotes which layers present in the elements.
*
* Grids always has coordinates, followed by extra layers which are set to
* truth here.
*/
bool has_normal;
bool has_mask;
bool has_normal = false;
bool has_mask = false;
/* Offsets of corresponding data layers in the elements. */
int normal_offset;
int mask_offset;
int normal_offset = -1;
int mask_offset = -1;
/* Faces from which grids are emitted. */
int num_faces;
SubdivCCGFace *faces;
int num_faces = -1;
SubdivCCGFace *faces = nullptr;
/* Indexed by grid index, points to corresponding face from `faces`. */
SubdivCCGFace **grid_faces;
SubdivCCGFace **grid_faces = nullptr;
/* Edges which are adjacent to faces.
* Used for faster grid stitching, in the cost of extra memory.
*/
int num_adjacent_edges;
SubdivCCGAdjacentEdge *adjacent_edges;
int num_adjacent_edges = -1;
SubdivCCGAdjacentEdge *adjacent_edges = nullptr;
/* Vertices which are adjacent to faces
* Used for faster grid stitching, in the cost of extra memory.
*/
int num_adjacent_vertices;
SubdivCCGAdjacentVertex *adjacent_vertices;
int num_adjacent_vertices = -1;
SubdivCCGAdjacentVertex *adjacent_vertices = nullptr;
DMFlagMat *grid_flag_mats;
BLI_bitmap **grid_hidden;
DMFlagMat *grid_flag_mats = nullptr;
BLI_bitmap **grid_hidden = nullptr;
/* TODO(sergey): Consider adding some accessors to a "decoded" geometry,
* to make integration with draw manager and such easy.
@ -189,15 +190,15 @@ struct SubdivCCG {
* such use-related flags in a more or less generic structure. */
struct {
/* Corresponds to MULTIRES_COORDS_MODIFIED. */
bool coords;
bool coords = false;
/* Corresponds to MULTIRES_HIDDEN_MODIFIED. */
bool hidden;
bool hidden = false;
} dirty;
/* Cached values, are not supposed to be accessed directly. */
struct {
/* Indexed by face, indicates index of the first grid which corresponds to the face. */
int *start_face_grid_index;
int *start_face_grid_index = nullptr;
} cache_;
};

View File

@ -15,6 +15,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_ID.h"
#include "DNA_brush_types.h"
#include "DNA_collection_types.h"
#include "DNA_gpencil_legacy_types.h"
@ -85,6 +86,24 @@ struct DeferredIconDeleteNode {
/* Protected by gIconMutex. */
static LockfreeLinkList g_icon_delete_queue;
class PreviewImageDeferred : public PreviewImage {
public:
const std::string filepath;
const ThumbSource source;
/* Behavior is undefined if \a prv is not a deferred preview (#PRV_TAG_DEFFERED not set). */
static PreviewImageDeferred &from_base(PreviewImage &prv);
static const PreviewImageDeferred &from_base(const PreviewImage &prv);
PreviewImageDeferred(blender::StringRef filepath, ThumbSource source);
PreviewImageDeferred(const PreviewImageDeferred &) = delete;
/* Delete through #BKE_previewimg_free()! */
~PreviewImageDeferred() = delete;
/* Keep this type non-copyable since ownership of #PreviewImage can be ambiguous (#PreviewImage
* allows shallow copies). */
PreviewImageDeferred &operator=(const PreviewImageDeferred &) = delete;
};
static void icon_free(void *val)
{
Icon *icon = (Icon *)val;
@ -230,40 +249,40 @@ void BKE_icons_deferred_free()
BLI_linklist_lockfree_clear(&g_icon_delete_queue, MEM_freeN);
}
static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
PreviewImage::PreviewImage()
{
PreviewImage *prv_img = (PreviewImage *)MEM_mallocN(sizeof(PreviewImage) + deferred_data_size,
"img_prv");
memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */
if (deferred_data_size) {
prv_img->tag |= PRV_TAG_DEFFERED;
}
/* Zero initialize */
memset(this, 0, sizeof(*this));
for (int i = 0; i < NUM_ICON_SIZES; i++) {
prv_img->flag[i] |= PRV_CHANGED;
prv_img->changed_timestamp[i] = 0;
flag[i] |= PRV_CHANGED;
changed_timestamp[i] = 0;
}
return prv_img;
}
static PreviewImage *previewimg_deferred_create(const char *filepath, int source)
PreviewImageDeferred &PreviewImageDeferred::from_base(PreviewImage &prv)
{
/* We pack needed data for lazy loading (source type, in a single char, and filepath). */
const size_t deferred_data_size = strlen(filepath) + 2;
char *deferred_data;
return static_cast<PreviewImageDeferred &>(prv);
}
const PreviewImageDeferred &PreviewImageDeferred::from_base(const PreviewImage &prv)
{
return static_cast<const PreviewImageDeferred &>(prv);
}
PreviewImage *prv = previewimg_create_ex(deferred_data_size);
deferred_data = (char *)PRV_DEFERRED_DATA(prv);
deferred_data[0] = source;
memcpy(&deferred_data[1], filepath, deferred_data_size - 1);
PreviewImageDeferred::PreviewImageDeferred(blender::StringRef filepath, ThumbSource source)
: PreviewImage(), filepath(filepath), source(source)
{
tag |= PRV_TAG_DEFFERED;
}
return prv;
static PreviewImageDeferred *previewimg_deferred_create(const char *filepath, ThumbSource source)
{
return MEM_new<PreviewImageDeferred>(__func__, filepath, source);
}
PreviewImage *BKE_previewimg_create()
{
return previewimg_create_ex(0);
return MEM_new<PreviewImage>(__func__);
}
void BKE_previewimg_freefunc(void *link)
@ -272,27 +291,38 @@ void BKE_previewimg_freefunc(void *link)
if (!prv) {
return;
}
for (int i = 0; i < NUM_ICON_SIZES; i++) {
if (prv->rect[i]) {
MEM_freeN(prv->rect[i]);
}
if (prv->gputexture[i]) {
GPU_texture_free(prv->gputexture[i]);
}
}
MEM_freeN(prv);
BKE_previewimg_free(&prv);
}
void BKE_previewimg_free(PreviewImage **prv)
{
if (prv && (*prv)) {
BKE_previewimg_freefunc(*prv);
for (int i = 0; i < NUM_ICON_SIZES; i++) {
if ((*prv)->rect[i]) {
MEM_freeN((*prv)->rect[i]);
}
if ((*prv)->gputexture[i]) {
GPU_texture_free((*prv)->gputexture[i]);
}
}
if ((*prv)->tag & PRV_TAG_DEFFERED) {
PreviewImageDeferred &this_deferred = PreviewImageDeferred::from_base(**prv);
std::destroy_at(&this_deferred.filepath);
}
MEM_delete(*prv);
*prv = nullptr;
}
}
/** Handy override for the deferred type (derives from #PreviewImage). */
static void BKE_previewimg_free(PreviewImageDeferred **prv)
{
PreviewImage *prv_base = *prv;
BKE_previewimg_free(&prv_base);
*prv = nullptr;
}
void BKE_previewimg_clear_single(PreviewImage *prv, enum eIconSizes size)
{
MEM_SAFE_FREE(prv->rect[size]);
@ -442,7 +472,7 @@ void BKE_previewimg_deferred_release(PreviewImage *prv)
if (prv->icon_id) {
BKE_icon_delete(prv->icon_id);
}
BKE_previewimg_freefunc(prv);
BKE_previewimg_free(&prv);
}
PreviewImage *BKE_previewimg_cached_get(const char *name)
@ -475,19 +505,19 @@ PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
{
BLI_assert(BLI_thread_is_main());
PreviewImage *prv = nullptr;
PreviewImageDeferred *prv = nullptr;
void **prv_p;
prv_p = BLI_ghash_lookup_p(gCachedPreviews, name);
if (prv_p) {
prv = *(PreviewImage **)prv_p;
prv = static_cast<PreviewImageDeferred *>(*prv_p);
BLI_assert(prv);
BLI_assert(prv->tag & PRV_TAG_DEFFERED);
}
if (prv && force_update) {
const char *prv_deferred_data = (char *)PRV_DEFERRED_DATA(prv);
if ((int(prv_deferred_data[0]) == source) && STREQ(&prv_deferred_data[1], filepath)) {
if ((prv->source == source) && (prv->filepath == filepath)) {
/* If same filepath, no need to re-allocate preview, just clear it up. */
BKE_previewimg_clear(prv);
}
@ -497,7 +527,7 @@ PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
}
if (!prv) {
prv = previewimg_deferred_create(filepath, source);
prv = previewimg_deferred_create(filepath, ThumbSource(source));
force_update = true;
}
@ -536,13 +566,10 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
return;
}
ImBuf *thumb;
char *prv_deferred_data = (char *)PRV_DEFERRED_DATA(prv);
int source = prv_deferred_data[0];
char *filepath = &prv_deferred_data[1];
PreviewImageDeferred &prv_deferred = PreviewImageDeferred::from_base(*prv);
int icon_w, icon_h;
thumb = IMB_thumb_manage(filepath, THB_LARGE, (ThumbSource)source);
ImBuf *thumb = IMB_thumb_manage(prv_deferred.filepath.c_str(), THB_LARGE, prv_deferred.source);
if (!thumb) {
return;
}
@ -578,6 +605,26 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size)
IMB_freeImBuf(thumb);
}
const char *BKE_previewimg_deferred_filepath_get(const PreviewImage *prv)
{
if ((prv->tag & PRV_TAG_DEFFERED) == 0) {
return nullptr;
}
const PreviewImageDeferred &prv_deferred = PreviewImageDeferred::from_base(*prv);
return prv_deferred.filepath.c_str();
}
std::optional<int> BKE_previewimg_deferred_thumb_source_get(const PreviewImage *prv)
{
if ((prv->tag & PRV_TAG_DEFFERED) == 0) {
return std::nullopt;
}
const PreviewImageDeferred &prv_deferred = PreviewImageDeferred::from_base(*prv);
return prv_deferred.source;
}
ImBuf *BKE_previewimg_to_imbuf(PreviewImage *prv, const int size)
{
const uint w = prv->w[size];

View File

@ -529,7 +529,7 @@ SubdivCCG *BKE_subdiv_to_ccg(Subdiv *subdiv,
SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator)
{
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
SubdivCCG *subdiv_ccg = MEM_cnew<SubdivCCG>(__func__);
SubdivCCG *subdiv_ccg = MEM_new<SubdivCCG>(__func__);
subdiv_ccg->subdiv = subdiv;
subdiv_ccg->level = bitscan_forward_i(settings->resolution - 1);
subdiv_ccg->grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg->level);
@ -613,7 +613,7 @@ void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg)
}
MEM_SAFE_FREE(subdiv_ccg->adjacent_vertices);
MEM_SAFE_FREE(subdiv_ccg->cache_.start_face_grid_index);
MEM_freeN(subdiv_ccg);
MEM_delete(subdiv_ccg);
}
void BKE_subdiv_ccg_key(CCGKey *key, const SubdivCCG *subdiv_ccg, int level)

View File

@ -1809,14 +1809,17 @@ void PreviewLoadJob::run_fn(void *customdata, bool *stop, bool *do_update, float
PreviewImage *preview = request->preview;
const char *deferred_data = static_cast<char *>(PRV_DEFERRED_DATA(preview));
const ThumbSource source = static_cast<ThumbSource>(deferred_data[0]);
const char *filepath = &deferred_data[1];
const std::optional<int> source = BKE_previewimg_deferred_thumb_source_get(preview);
const char *filepath = BKE_previewimg_deferred_filepath_get(preview);
if (!source || !filepath) {
continue;
}
// printf("loading deferred %d×%d preview for %s\n", request->sizex, request->sizey, filepath);
IMB_thumb_path_lock(filepath);
ImBuf *thumb = IMB_thumb_manage(filepath, THB_LARGE, source);
ImBuf *thumb = IMB_thumb_manage(filepath, THB_LARGE, ThumbSource(*source));
IMB_thumb_path_unlock(filepath);
if (thumb) {

View File

@ -343,48 +343,41 @@ static void region_draw_azones(ScrArea *area, ARegion *region)
GPU_blend(GPU_BLEND_NONE);
}
static void region_draw_status_text(ScrArea *area, ARegion *region)
static void region_draw_status_text(ScrArea * /*area*/, ARegion *region)
{
bool overlap = ED_region_is_overlap(area->spacetype, region->regiontype);
float header_color[4];
UI_GetThemeColor4fv(TH_HEADER_ACTIVE, header_color);
if (overlap) {
GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f);
}
else {
UI_ThemeClearColor(TH_HEADER);
/* Clear the region from the buffer. */
GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f);
/* Fill with header color. */
if (header_color[3] > 0.0f) {
const rctf rect = {0.0f, float(region->winx), 0.0f, float(region->winy)};
UI_draw_roundbox_4fv(&rect, true, 0.0f, header_color);
}
int fontid = BLF_set_default();
const float width = BLF_width(fontid, region->headerstr, BLF_DRAW_STR_DUMMY_MAX);
const float x = UI_UNIT_X;
const int fontid = BLF_set_default();
const float x = 12.0f * UI_SCALE_FAC;
const float y = 0.4f * UI_UNIT_Y;
GPU_blend(GPU_BLEND_ALPHA);
if (overlap) {
const float pad = 2.0f * UI_SCALE_FAC;
const float x1 = x - (UI_UNIT_X - pad);
const float x2 = x + width + (UI_UNIT_X - pad);
const float y1 = pad;
const float y2 = region->winy - pad;
GPU_blend(GPU_BLEND_ALPHA);
float color[4] = {0.0f, 0.0f, 0.0f, 0.5f};
if (header_color[3] < 0.3f) {
/* Draw a background behind the text for extra contrast. */
const float width = BLF_width(fontid, region->headerstr, BLF_DRAW_STR_DUMMY_MAX);
const float pad = 5.0f * UI_SCALE_FAC;
const float x1 = x - pad;
const float x2 = x + width + pad;
const float y1 = 3.0f * UI_SCALE_FAC;
const float y2 = region->winy - (4.0f * UI_SCALE_FAC);
float color[4] = {0.0f, 0.0f, 0.0f, 0.3f};
UI_GetThemeColor3fv(TH_BACK, color);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
rctf rect{};
rect.xmin = x1;
rect.xmax = x2;
rect.ymin = y1;
rect.ymax = y2;
UI_draw_roundbox_aa(&rect, true, 4.0f, color);
UI_FontThemeColor(fontid, TH_TEXT);
}
else {
UI_FontThemeColor(fontid, TH_TEXT);
const rctf rect = {x1, x2, y1, y2};
UI_draw_roundbox_4fv(&rect, true, 4.0f * UI_SCALE_FAC, color);
}
UI_FontThemeColor(fontid, TH_TEXT);
BLF_position(fontid, x, y, 0.0f);
BLF_draw(fontid, region->headerstr, BLF_DRAW_STR_DUMMY_MAX);
}
@ -818,20 +811,31 @@ void ED_area_status_text(ScrArea *area, const char *str)
return;
}
ARegion *ar = nullptr;
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_HEADER) {
if (str) {
if (region->headerstr == nullptr) {
region->headerstr = static_cast<char *>(MEM_mallocN(UI_MAX_DRAW_STR, "headerprint"));
}
BLI_strncpy(region->headerstr, str, UI_MAX_DRAW_STR);
BLI_str_rstrip(region->headerstr);
}
else {
MEM_SAFE_FREE(region->headerstr);
}
ED_region_tag_redraw(region);
if (region->regiontype == RGN_TYPE_HEADER && region->visible) {
ar = region;
}
else if (region->regiontype == RGN_TYPE_TOOL_HEADER && region->visible) {
/* Prefer tool header when we also have a header. */
ar = region;
break;
}
}
if (ar) {
if (str) {
if (ar->headerstr == nullptr) {
ar->headerstr = static_cast<char *>(MEM_mallocN(UI_MAX_DRAW_STR, "headerprint"));
}
BLI_strncpy(ar->headerstr, str, UI_MAX_DRAW_STR);
BLI_str_rstrip(ar->headerstr);
}
else {
MEM_SAFE_FREE(ar->headerstr);
}
ED_region_tag_redraw(ar);
}
}

View File

@ -20,6 +20,7 @@
#include "transform_snap_object.hh"
using blender::float4x4;
using blender::IndexRange;
eSnapMode snapCurve(SnapObjectContext *sctx, Object *ob_eval, const float4x4 &obmat)
{
@ -50,9 +51,9 @@ eSnapMode snapCurve(SnapObjectContext *sctx, Object *ob_eval, const float4x4 &ob
0;
LISTBASE_FOREACH (Nurb *, nu, (use_obedit ? &cu->editnurb->nurbs : &cu->nurb)) {
for (int u = 0; u < nu->pntsu; u++) {
if (use_obedit) {
if (nu->bezt) {
if (nu->bezt) {
for (int u : blender::IndexRange(nu->pntsu)) {
if (use_obedit) {
if (nu->bezt[u].hide) {
/* Skip hidden. */
continue;
@ -62,7 +63,6 @@ eSnapMode snapCurve(SnapObjectContext *sctx, Object *ob_eval, const float4x4 &ob
if (is_selected && skip_selected) {
continue;
}
has_snap |= nearest2d.snap_point(nu->bezt[u].vec[1]);
/* Don't snap if handle is selected (moving),
* or if it is aligning to a moving handle. */
@ -78,7 +78,12 @@ eSnapMode snapCurve(SnapObjectContext *sctx, Object *ob_eval, const float4x4 &ob
has_snap |= nearest2d.snap_point(nu->bezt[u].vec[2]);
}
}
else {
has_snap |= nearest2d.snap_point(nu->bezt[u].vec[1]);
}
}
else if (nu->bp) {
for (int u : blender::IndexRange(nu->pntsu * nu->pntsv)) {
if (use_obedit) {
if (nu->bp[u].hide) {
/* Skip hidden. */
continue;
@ -88,20 +93,8 @@ eSnapMode snapCurve(SnapObjectContext *sctx, Object *ob_eval, const float4x4 &ob
if (is_selected && skip_selected) {
continue;
}
has_snap |= nearest2d.snap_point(nu->bp[u].vec);
}
}
else {
/* Curve is not visible outside editmode if nurb length less than two. */
if (nu->pntsu > 1) {
if (nu->bezt) {
has_snap |= nearest2d.snap_point(nu->bezt[u].vec[1]);
}
else {
has_snap |= nearest2d.snap_point(nu->bp[u].vec);
}
}
has_snap |= nearest2d.snap_point(nu->bp[u].vec);
}
}
}

View File

@ -604,6 +604,10 @@ enum {
PRV_TAG_DEFFERED_DELETE = (1 << 2),
};
/**
* This type allows shallow copies. Use #BKE_previewimg_free() to release contained resources.
* Don't call this for shallow copies (or the original instance will have dangling pointers).
*/
typedef struct PreviewImage {
/* All values of 2 are really NUM_ICON_SIZES */
unsigned int w[2];
@ -620,12 +624,17 @@ typedef struct PreviewImage {
/** Runtime data. */
short tag;
char _pad[2];
} PreviewImage;
#define PRV_DEFERRED_DATA(prv) \
(CHECK_TYPE_INLINE(prv, PreviewImage *), \
BLI_assert((prv)->tag & PRV_TAG_DEFFERED), \
(void *)((prv) + 1))
#ifdef __cplusplus
PreviewImage();
/* Shallow copy! Contained data is not copied. */
PreviewImage(const PreviewImage &) = default;
/* Don't free contained data to allow shallow copies. */
~PreviewImage() = default;
/* Shallow copy! Contained data is not copied. */
PreviewImage &operator=(const PreviewImage &) = default;
#endif
} PreviewImage;
#define ID_FAKE_USERS(id) ((((const ID *)id)->flag & LIB_FAKEUSER) ? 1 : 0)
#define ID_REAL_USERS(id) (((const ID *)id)->us - ID_FAKE_USERS(id))

View File

@ -160,7 +160,6 @@ struct Render : public BaseRender {
bool prepare_viewlayer(struct ViewLayer *view_layer, struct Depsgraph *depsgraph) override;
char name[RE_MAXNAME] = "";
int slot = 0;
/* state settings */
short flag = 0;
@ -183,7 +182,7 @@ struct Render : public BaseRender {
/* final picture width and height (within disprect) */
int rectx = 0, recty = 0;
/* Camera transform, only used by Freestyle. */
/* Camera transform. Used by Freestyle, Eevee, and other draw manager engines.. */
float winmat[4][4] = {{0}};
/* Clipping. */