Compare commits

...

26 Commits

Author SHA1 Message Date
6fd45a110c Only hide preview image while dragging over 3D View
Make the preview hide and unhide depending on if the user drags over the
3D View. In there the preview is too much visual noice, together with
the bounding box and snapping plane we draw there.
2021-10-11 16:39:52 +02:00
b1a319f4e0 Properly set rotation when dropping
Didn't respect the rotation mode before.
2021-10-11 15:57:30 +02:00
793f65f426 Adapt to changes in master 2021-10-11 15:40:03 +02:00
7c8ad97115 Merge branch 'master' into asset-browser-snap-dragging 2021-10-11 10:57:33 +02:00
1d44fc58a0 Merge branch 'master' into asset-browser-snap-dragging 2021-09-14 16:47:32 +02:00
76a212f947 Merge branch 'master' into asset-browser-snap-dragging 2021-09-13 18:14:14 +02:00
eedde9db74 Adjustments to drag info drawing
* Change the "Add Named Object" drag into string to "Add Object". The "Named"
  part is kinda useless info and relates to an implementation detail.
* Draw drag info closer to the cursor. Looked quite off before.
2021-06-13 23:48:06 +02:00
e20266b949 Merge branch 'master' into asset-browser-snap-dragging 2021-06-13 22:06:02 +02:00
2ef120ace0 Fix merge error after last merge 2021-06-13 22:03:43 +02:00
4ac48b1390 Merge branch 'master' into asset-browser-snap-dragging 2021-06-05 18:01:27 +02:00
99cc9df257 Merge branch 'master' into asset-browser-snap-dragging 2021-05-21 02:52:24 +02:00
Severin
513328602d Merge remote-tracking branch 'origin/master' into asset-browser-snap-dragging 2021-05-11 13:16:53 +02:00
279f271a0a Snap based on the bounding box when dropping, not origin
This makes the dropping use the object's bounding box for snapping, so
that it matches the bounding box we draw while dragging.

Not that this may have to be optional in future, there may be valid
cases to use the origin instead of the bounding box for snapping.
2021-05-06 21:45:08 +02:00
f00d24e2c1 Merge remote-tracking branch 'origin/master' into asset-browser-snap-dragging 2021-05-06 14:34:42 +02:00
963826d8a1 Merge remote-tracking branch 'origin/master' into asset-browser-snap-dragging 2021-05-04 17:33:04 +02:00
3fdd579e7c Merge remote-tracking branch 'origin/master' into asset-browser-snap-dragging 2021-05-04 16:56:32 +02:00
bc4c9fea77 Fix crash when dragging emtpy into the 3D View 2021-04-30 20:35:36 +02:00
ac96c8a898 Merge branch 'master' into asset-browser-snap-dragging 2021-04-30 12:43:08 +02:00
78008642ae Show a bounding box for object assets while dragging
Note: Object assets have to be saved with this commit or later for the bounding
box to appear.

Basic idea is:
* Store the bounding box (and related info) in the asset metadata.
* The bounding box has to be updated and written to custom properties of the
  asset metadata.
* There's a new `AssetTypeInfo` struct, to set asset type dependent callbacks
  or data (in future). ID types can conveniently define asset-type info as part
  of their `IDTypeInfo` definition.
* The asset-type info can contain a custom callback to be executed before the
  asset is saved. This is how the object can write its custom asset metadata.
* The dropbox can also register a callback to set properties for its
  gizmo-group now. Used to copy
* The "placement plane" gizmo is scaled to the bounding box size too.
* For local ID assets, the data should be accessed directly, so the file
  doesn't have to be saved to get the bounding box updated.

Also:
* Added proper gizmo group custom property support to C (was already supported
  in Python, or in C with some hacking).
* Store the basis matrix (world matrix without parent or constraint transforms)
  in the custom asset metadata. Used by the placement gizmo to scale the
  bounding box to match the result visually when dropping.
* The preview image is disabled while dragging objects over the 3D view.
* The bounding box always snaps with its lower edge (Z axis) to the surface.
  Snapping with other axes can be added still.
* However, actually dropping the object still uses the origin, so the drop
  position may not match what the bounding box indicated. This could be changed
  to also use the bounding box instead. Or the drawn bounding box should be
  translated to respect the origin position.
2021-04-30 02:25:33 +02:00
5df6caa7f3 Merge remote-tracking branch 'origin/master' into asset-browser-snap-dragging 2021-04-29 18:50:29 +02:00
2a00e16682 Merge remote-tracking branch 'origin/master' into asset-browser-snap-dragging 2021-04-28 22:48:13 +02:00
948d1b0284 Merge remote-tracking branch 'origin/master' into asset-browser-snap-dragging 2021-04-26 21:02:09 +02:00
8a8208bd95 Merge remote-tracking branch 'origin/master' into asset-browser-snap-dragging 2021-04-26 14:38:41 +02:00
fcc42b3d46 Basic snapping support for dropping objects
Uses the same snapping logic as the placement plane from the Add Object
tool, which means it matches the plane that we already draw as a
preview.

This is quite primitive at this point - you can't change options for the
snapping like the up-axis or the snapping target - but it already feels
quite great.
Another limitation is that it uses the origin of the dropped object to
place it, the bounding box should give better results in practice. This
is something we can add.
2021-04-22 12:03:30 +02:00
8cc294a315 Merge branch 'master' into asset-browser-snap-dragging 2021-04-22 10:15:57 +02:00
8ddf9f06ab Initial prototype for snapping plane feedback while dragging assets
Shows the same grid overlay as the Add Object tool when dragging an
asset into a 3D view. Uses the gizmo-system for that.
How visibility of gizmo-groups is managed is rather tricky, for now I
hacked things a bit to work. I have ideas to make this nicer.

Besides that, this is generally a design that I think can work in
master: Just like tools, drop-boxes can set a gizmo-group to use while
they are active. If the gizmo-group supports usage while dragging, it is
drawn.
2021-04-21 19:20:35 +02:00
31 changed files with 791 additions and 86 deletions

View File

@@ -20,6 +20,7 @@
#pragma once
#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h"
#include "DNA_asset_types.h"
@@ -29,11 +30,23 @@ extern "C" {
#endif
struct AssetLibraryReference;
struct AssetMetaData;
struct BlendDataReader;
struct BlendWriter;
struct ID;
struct IDProperty;
struct PreviewImage;
typedef void (*PreSaveFn)(void *asset_ptr, struct AssetMetaData *asset_data);
typedef struct AssetTypeInfo {
/**
* For local assets (assets in the current .blend file), a callback to execute before the file is
* saved.
*/
PreSaveFn pre_save_fn;
} AssetTypeInfo;
struct AssetMetaData *BKE_asset_metadata_create(void);
void BKE_asset_metadata_free(struct AssetMetaData **asset_data);
@@ -56,6 +69,10 @@ void BKE_asset_metadata_catalog_id_set(struct AssetMetaData *asset_data,
void BKE_asset_library_reference_init_default(struct AssetLibraryReference *library_ref);
void BKE_asset_metadata_idprop_ensure(struct AssetMetaData *asset_data, struct IDProperty *prop);
struct IDProperty *BKE_asset_metadata_idprop_find(const struct AssetMetaData *asset_data,
const char *name) ATTR_WARN_UNUSED_RESULT;
struct PreviewImage *BKE_asset_metadata_preview_get_from_id(const struct AssetMetaData *asset_data,
const struct ID *owner_id);

View File

@@ -228,6 +228,11 @@ typedef struct IDTypeInfo {
* \note Currently needed for some update operation on point caches.
*/
IDTypeLibOverrideApplyPost lib_override_apply_post;
/**
* Callbacks for assets, based on the type of asset.
*/
struct AssetTypeInfo *asset_type_info;
} IDTypeInfo;
/* ********** Declaration of each IDTypeInfo. ********** */

View File

@@ -244,9 +244,9 @@ void BKE_main_library_weak_reference_remove_item(struct GHash *library_weak_refe
#define FOREACH_MAIN_LISTBASE_ID_BEGIN(_lb, _id) \
{ \
ID *_id_next = (_lb)->first; \
ID *_id_next = (ID *)(_lb)->first; \
for ((_id) = _id_next; (_id) != NULL; (_id) = _id_next) { \
_id_next = (_id)->next;
_id_next = (ID *)(_id)->next;
#define FOREACH_MAIN_LISTBASE_ID_END \
} \

View File

@@ -159,6 +159,7 @@ struct Object *BKE_object_duplicate(struct Main *bmain,
void BKE_object_obdata_size_init(struct Object *ob, const float size);
void BKE_object_scale_to_vec3(const struct Object *ob, float r_scale[3]);
void BKE_object_scale_to_mat3(struct Object *ob, float r_mat[3][3]);
void BKE_object_rot_to_mat3(const struct Object *ob, float r_mat[3][3], bool use_drot);
void BKE_object_mat3_to_rot(struct Object *ob, float r_mat[3][3], bool use_compat);

View File

@@ -140,6 +140,25 @@ void BKE_asset_metadata_catalog_id_set(struct AssetMetaData *asset_data,
trimmed_id.copy(asset_data->catalog_simple_name, max_simple_name_length);
}
void BKE_asset_metadata_idprop_ensure(AssetMetaData *asset_data, IDProperty *prop)
{
if (!asset_data->properties) {
IDPropertyTemplate val = {0};
asset_data->properties = IDP_New(IDP_GROUP, &val, "AssetMetaData.properties");
}
/* Important: The property may already exist. For now just allow always allow a newly allocated
* property, and replace the existing one as a way of updating. */
IDP_ReplaceInGroup(asset_data->properties, prop);
}
IDProperty *BKE_asset_metadata_idprop_find(const AssetMetaData *asset_data, const char *name)
{
if (!asset_data->properties) {
return nullptr;
}
return IDP_GetPropertyFromGroup(asset_data->properties, name);
}
/* Queries -------------------------------------------- */
PreviewImage *BKE_asset_metadata_preview_get_from_id(const AssetMetaData *UNUSED(asset_data),
@@ -169,6 +188,7 @@ void BKE_asset_metadata_write(BlendWriter *writer, AssetMetaData *asset_data)
void BKE_asset_metadata_read(BlendDataReader *reader, AssetMetaData *asset_data)
{
/* asset_data itself has been read already. */
asset_data->local_type_info = nullptr;
if (asset_data->properties) {
BLO_read_data_address(reader, &asset_data->properties);

View File

@@ -82,6 +82,7 @@
#include "BKE_anim_visualization.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_asset.h"
#include "BKE_camera.h"
#include "BKE_collection.h"
#include "BKE_constraint.h"
@@ -1145,6 +1146,57 @@ static void object_lib_override_apply_post(ID *id_dst, ID *UNUSED(id_src))
BLI_freelistN(&pidlist);
}
static IDProperty *object_asset_boundbox_hint_property(Object *ob)
{
BoundBox *boundbox = BKE_object_boundbox_get(ob);
if (!boundbox) {
return NULL;
}
IDPropertyTemplate idprop = {0};
idprop.array.len = sizeof(boundbox->vec) / sizeof(**boundbox->vec);
idprop.array.type = IDP_FLOAT;
IDProperty *property = IDP_New(IDP_ARRAY, &idprop, "boundbox_hint");
memcpy(IDP_Array(property), boundbox->vec, sizeof(boundbox->vec));
return property;
}
static IDProperty *object_asset_matrix_basis_property(Object *ob)
{
float mat[4][4];
IDPropertyTemplate idprop = {0};
idprop.array.len = sizeof(mat) / sizeof(**mat);
idprop.array.type = IDP_FLOAT;
IDProperty *property = IDP_New(IDP_ARRAY, &idprop, "matrix_basis");
BKE_object_to_mat4(ob, (float(*)[])IDP_Array(property));
return property;
}
static void object_asset_pre_save(void *asset_ptr, struct AssetMetaData *asset_data)
{
Object *ob = asset_ptr;
BLI_assert(GS(ob->id.name) == ID_OB);
/* Update bounding-box hint for the asset. */
IDProperty *boundbox_prop = object_asset_boundbox_hint_property(ob);
if (boundbox_prop) {
BKE_asset_metadata_idprop_ensure(asset_data, boundbox_prop);
}
/* Base matrix (object matrix without parent or constraint transforms). */
IDProperty *base_matrix_prop = object_asset_matrix_basis_property(ob);
if (base_matrix_prop) {
BKE_asset_metadata_idprop_ensure(asset_data, base_matrix_prop);
}
}
AssetTypeInfo AssetType_OB = {
.pre_save_fn = object_asset_pre_save,
};
IDTypeInfo IDType_ID_OB = {
.id_code = ID_OB,
.id_filter = FILTER_ID_OB,
@@ -1171,6 +1223,8 @@ IDTypeInfo IDType_ID_OB = {
.blend_read_undo_preserve = NULL,
.lib_override_apply_post = object_lib_override_apply_post,
.asset_type_info = &AssetType_OB,
};
void BKE_object_workob_clear(Object *workob)
@@ -3033,10 +3087,15 @@ void BKE_object_obdata_size_init(struct Object *ob, const float size)
/** \name Object Matrix Get/Set API
* \{ */
void BKE_object_scale_to_vec3(const Object *ob, float r_scale[3])
{
mul_v3_v3v3(r_scale, ob->scale, ob->dscale);
}
void BKE_object_scale_to_mat3(Object *ob, float mat[3][3])
{
float vec[3];
mul_v3_v3v3(vec, ob->scale, ob->dscale);
BKE_object_scale_to_vec3(ob, vec);
size_to_mat3(mat, vec);
}

View File

@@ -2211,6 +2211,9 @@ static void direct_link_id_common(
if (id->asset_data) {
BLO_read_data_address(reader, &id->asset_data);
BKE_asset_metadata_read(reader, id->asset_data);
/* Restore runtime asset type info. */
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
id->asset_data->local_type_info = id_type->asset_type_info;
}
/* Link direct data of ID properties. */

View File

@@ -26,6 +26,7 @@ extern "C" {
struct ID;
struct bContext;
struct Main;
/**
* Mark the datablock as asset.
@@ -45,6 +46,8 @@ bool ED_asset_mark_id(const struct bContext *C, struct ID *id);
* \return whether the asset metadata was actually removed; false when the ID was not an asset. */
bool ED_asset_clear_id(struct ID *id);
void ED_assets_pre_save(struct Main *bmain);
bool ED_asset_can_mark_single_from_context(const struct bContext *C);
#ifdef __cplusplus

View File

@@ -25,7 +25,9 @@
#include "BKE_asset.h"
#include "BKE_context.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BLO_readfile.h"
@@ -51,7 +53,9 @@ bool ED_asset_mark_id(const bContext *C, ID *id)
id_fake_user_set(id);
const IDTypeInfo *id_type_info = BKE_idtype_get_info_from_id(id);
id->asset_data = BKE_asset_metadata_create();
id->asset_data->local_type_info = id_type_info->asset_type_info;
UI_icon_render_id(C, nullptr, id, ICON_SIZE_PREVIEW, true);
@@ -75,6 +79,21 @@ bool ED_asset_clear_id(ID *id)
return true;
}
void ED_assets_pre_save(struct Main *bmain)
{
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (!id->asset_data || !id->asset_data->local_type_info) {
continue;
}
if (id->asset_data->local_type_info->pre_save_fn) {
id->asset_data->local_type_info->pre_save_fn(id, id->asset_data);
}
}
FOREACH_MAIN_ID_END;
}
bool ED_asset_can_mark_single_from_context(const bContext *C)
{
/* Context needs a "id" pointer to be set for #ASSET_OT_mark()/#ASSET_OT_clear() to use. */

View File

@@ -16,9 +16,6 @@
/** \file
* \ingroup editors
*
* The public API for assets is defined in dedicated headers. This is a utility file that just
* includes all of these.
*/
#pragma once

View File

@@ -40,6 +40,7 @@ void ED_gizmotypes_preselect_3d(void);
void ED_gizmotypes_primitive_3d(void);
void ED_gizmotypes_blank_3d(void);
void ED_gizmotypes_snap_3d(void);
void ED_gizmotypes_placement_3d(void);
struct ARegion;
struct Depsgraph;

View File

@@ -42,6 +42,12 @@ bool ED_gizmo_poll_or_unlink_delayed_from_tool_ex(const struct bContext *C,
bool ED_gizmo_poll_or_unlink_delayed_from_tool(const struct bContext *C,
struct wmGizmoGroupType *gzgt);
bool ED_gizmo_poll_from_tool_ex(const struct bContext *C, const char *gzgt_idname);
bool ED_gizmo_poll_from_tool(const struct bContext *C, const struct wmGizmoGroupType *gzgt);
bool ED_gizmo_poll_from_dropbox_ex(const struct bContext *C, const char *gzgt_idname);
bool ED_gizmo_poll_from_dropbox(const struct bContext *C, const struct wmGizmoGroupType *gzgt);
#ifdef __cplusplus
}
#endif

View File

@@ -776,6 +776,30 @@ void ED_view3d_buttons_region_layout_ex(const struct bContext *C,
bool ED_view3d_local_collections_set(struct Main *bmain, struct View3D *v3d);
void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all);
/* view3d_placement.c */
enum ePlaceDirection {
/** Use the negative direction of the plane axis as up-axis for the
* boundbox snapping (snap with front, left or bottom side). */
PLACE_DIRECTION_NEG,
/** Use the positive direction of the plane axis as up-axis for the
* boundbox snapping (snap with back, right or top side). */
PLACE_DIRECTION_POS,
};
void ED_view3d_placement_plane_calc(struct bContext *C,
const int mval[2],
const int plane_axis,
float r_co_src[3],
float r_mat_orient[3][3]);
void ED_view3d_placement_plane_boundbox_calc(struct bContext *C,
const int mval[2],
const struct BoundBox *boundbox,
const enum ePlaceDirection direction,
const float scale[3],
float r_co_src[3],
float r_mat_orient[3][3]);
#ifdef WITH_XR_OPENXR
void ED_view3d_xr_mirror_update(const struct ScrArea *area,
const struct View3D *v3d,

View File

@@ -37,6 +37,7 @@ extern "C" {
struct ARegion;
struct AssetFilterSettings;
struct AssetHandle;
struct AssetMetaData;
struct AutoComplete;
struct EnumPropertyItem;
struct FileDirEntry;
@@ -780,6 +781,7 @@ void UI_but_drag_set_id(uiBut *but, struct ID *id);
void UI_but_drag_set_asset(uiBut *but,
const struct AssetHandle *asset,
const char *path,
struct AssetMetaData *metadata,
int import_type, /* eFileAssetImportType */
int icon,
struct ImBuf *imb,

View File

@@ -6279,12 +6279,13 @@ void UI_but_drag_set_id(uiBut *but, ID *id)
void UI_but_drag_set_asset(uiBut *but,
const AssetHandle *asset,
const char *path,
struct AssetMetaData *metadata,
int import_type,
int icon,
struct ImBuf *imb,
float scale)
{
wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, path, import_type);
wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, metadata, path, import_type);
/* FIXME: This is temporary evil solution to get scene/viewlayer/etc in the copy callback of the
* #wmDropBox.

View File

@@ -70,6 +70,7 @@ static void asset_view_item_but_drag_set(uiBut *but,
UI_but_drag_set_asset(but,
asset_handle,
BLI_strdup(blend_path),
ED_asset_handle_get_metadata(asset_handle),
FILE_ASSET_IMPORT_APPEND,
ED_asset_handle_get_preview_icon_id(asset_handle),
imbuf,

View File

@@ -3530,12 +3530,6 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
basen->object->visibility_flag &= ~OB_HIDE_VIEWPORT;
int mval[2];
if (object_add_drop_xy_get(C, op, &mval)) {
ED_object_location_from_view(C, basen->object->loc);
ED_view3d_cursor3d_position(C, mval, false, basen->object->loc);
}
/* object_add_duplicate_internal() doesn't deselect other objects, unlike object_add_common() or
* BKE_view_layer_base_deselect_all(). */
ED_object_base_deselect_all(view_layer, NULL, SEL_DESELECT);
@@ -3553,13 +3547,31 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
ED_outliner_select_sync_from_object_tag(C);
/* For the placement based on the bounding box to work, the object/object-data has to be
* evaulated first. */
int mval[2];
if (object_add_drop_xy_get(C, op, &mval)) {
Object *ob_eval = DEG_get_evaluated_object(CTX_data_ensure_evaluated_depsgraph(C),
basen->object);
BoundBox *boundbox = BKE_object_boundbox_get(ob_eval);
float rotmat[3][3];
float scale[3];
BKE_object_scale_to_vec3(basen->object, scale);
ED_view3d_placement_plane_boundbox_calc(
C, mval, boundbox, PLACE_DIRECTION_NEG, scale, basen->object->loc, rotmat);
BKE_object_mat3_to_rot(basen->object, rotmat, true);
DEG_id_tag_update(&basen->object->id, ID_RECALC_TRANSFORM);
}
return OPERATOR_FINISHED;
}
void OBJECT_OT_add_named(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add Named Object";
ot->name = "Add Object";
ot->description = "Add named object";
ot->idname = "OBJECT_OT_add_named";

View File

@@ -914,6 +914,14 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
if (WM_gizmo_highlight_set(gzmap, NULL)) {
ED_region_tag_redraw_no_rebuild(region_prev);
}
/* TODO deduplicate (wm_handlers_do_gizmo_handler().) */
const ListBase *groups = WM_gizmomap_group_list(gzmap);
LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, groups) {
if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_ATTACHED_TO_CURSOR) {
ED_region_tag_redraw_editor_overlays(region_prev);
}
}
}
}

View File

@@ -142,6 +142,7 @@ void ED_spacetypes_init(void)
ED_gizmotypes_cage_2d();
ED_gizmotypes_cage_3d();
ED_gizmotypes_snap_3d();
ED_gizmotypes_placement_3d();
/* Register types for operators and gizmos. */
const ListBase *spacetypes = BKE_spacetypes_list();

View File

@@ -190,6 +190,7 @@ static void file_draw_icon(const SpaceFile *sfile,
UI_but_drag_set_asset(but,
&(AssetHandle){.file_data = file},
BLI_strdup(blend_path),
file->asset_data,
asset_params->import_type,
icon,
preview_image,
@@ -504,6 +505,7 @@ static void file_draw_preview(const SpaceFile *sfile,
UI_but_drag_set_asset(but,
&(AssetHandle){.file_data = file},
BLI_strdup(blend_path),
file->asset_data,
asset_params->import_type,
icon,
imb,

View File

@@ -39,6 +39,7 @@
#include "BLT_translation.h"
#include "BKE_asset.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_global.h"
@@ -516,7 +517,12 @@ static bool view3d_drop_id_in_main_region_poll(bContext *C,
static bool view3d_ob_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
return view3d_drop_id_in_main_region_poll(C, drag, event, ID_OB);
if (view3d_drop_id_in_main_region_poll(C, drag, event, ID_OB)) {
drag->no_preview = true;
return true;
}
return false;
}
static bool view3d_collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
@@ -633,6 +639,45 @@ static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop)
RNA_boolean_set(drop->ptr, "duplicate", false);
}
static void view3d_ob_drag_gizmo_copy_local(wmDropBox *drop, Object *ob)
{
BoundBox *boundbox = BKE_object_boundbox_get(ob);
if (boundbox) {
RNA_float_set_array(drop->gizmo_group_ptr, "bound_box", (float *)boundbox->vec);
}
float matrix_basis[4][4];
BKE_object_to_mat4(ob, matrix_basis);
RNA_float_set_array(drop->gizmo_group_ptr, "matrix_basis", (float *)matrix_basis);
}
static void view3d_ob_drag_gizmo_copy_external(wmDrag *drag, wmDropBox *drop)
{
const struct AssetMetaData *meta_data = WM_drag_get_asset_meta_data(drag, ID_OB);
const IDProperty *boundbox_prop = BKE_asset_metadata_idprop_find(meta_data, "boundbox_hint");
if (boundbox_prop) {
BLI_assert(boundbox_prop->len == sizeof(((BoundBox *)NULL)->vec) / sizeof(float));
RNA_float_set_array(drop->gizmo_group_ptr, "bound_box", IDP_Array(boundbox_prop));
}
const IDProperty *matrix_basis_prop = BKE_asset_metadata_idprop_find(meta_data, "matrix_basis");
if (matrix_basis_prop) {
BLI_assert(matrix_basis_prop->len == sizeof(((Object *)NULL)->obmat) / sizeof(float));
RNA_float_set_array(drop->gizmo_group_ptr, "matrix_basis", IDP_Array(matrix_basis_prop));
}
}
static void view3d_ob_drag_gizmo_copy(wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_get_local_ID(drag, ID_OB);
if (id) {
view3d_ob_drag_gizmo_copy_local(drop, (Object *)id);
}
else {
view3d_ob_drag_gizmo_copy_external(drag, drop);
}
}
static void view3d_collection_drop_copy(wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, ID_GR);
@@ -694,13 +739,15 @@ static void view3d_lightcache_update(bContext *C)
static void view3d_dropboxes(void)
{
ListBase *lb = WM_dropboxmap_find("View3D", SPACE_VIEW3D, RGN_TYPE_WINDOW);
wmDropBox *dropbox;
WM_dropbox_add(lb,
"OBJECT_OT_add_named",
view3d_ob_drop_poll,
view3d_ob_drop_copy,
WM_drag_free_imported_drag_ID,
NULL);
dropbox = WM_dropbox_add(lb,
"OBJECT_OT_add_named",
view3d_ob_drop_poll,
view3d_ob_drop_copy,
WM_drag_free_imported_drag_ID,
NULL);
WM_dropbox_gizmogroup_set(dropbox, "VIEW3D_GGT_placement", view3d_ob_drag_gizmo_copy);
WM_dropbox_add(lb,
"OBJECT_OT_drop_named_material",
view3d_mat_drop_poll,

View File

@@ -30,12 +30,14 @@
#include "DNA_scene_types.h"
#include "DNA_vfont_types.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -64,7 +66,6 @@
static const char *view3d_gzgt_placement_id = "VIEW3D_GGT_placement";
static void preview_plane_cursor_setup(wmGizmoGroup *gzgroup);
static void preview_plane_cursor_visible_set(wmGizmoGroup *gzgroup, bool do_draw);
/**
@@ -377,6 +378,25 @@ static wmGizmoGroup *idp_gizmogroup_from_region(ARegion *region)
return gzmap ? WM_gizmomap_group_find(gzmap, view3d_gzgt_placement_id) : NULL;
}
static wmGizmo *idp_snap_gizmo_from_region(ARegion *region)
{
/* Assign snap gizmo which is may be used as part of the tool. */
wmGizmoGroup *gzgroup = idp_gizmogroup_from_region(region);
if ((gzgroup == NULL) || (gzgroup->gizmos.first == NULL)) {
return NULL;
}
return gzgroup->gizmos.first;
}
static void idp_paintcursor_from_gizmo_visible_set(wmGizmo *gz, bool visible)
{
/* Can be NULL when gizmos are disabled. */
if (gz->parent_gzgroup->customdata != NULL) {
preview_plane_cursor_visible_set(gz->parent_gzgroup, visible);
}
}
/**
* Calculate 3D view incremental (grid) snapping.
*
@@ -454,7 +474,7 @@ static void draw_line_loop(const float coords[][3], int coords_len, const float
float viewport[4];
GPU_viewport_size_get_f(viewport);
GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
GPU_batch_uniform_1f(batch, "lineWidth", GPU_line_width_get());
GPU_batch_draw(batch);
@@ -487,7 +507,7 @@ static void draw_line_pairs(const float coords_a[][3],
float viewport[4];
GPU_viewport_size_get_f(viewport);
GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
GPU_batch_uniform_1f(batch, "lineWidth", GPU_line_width_get());
GPU_batch_draw(batch);
@@ -535,7 +555,7 @@ static void draw_line_bounds(const BoundBox *bounds, const float color[4])
float viewport[4];
GPU_viewport_size_get_f(viewport);
GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
GPU_batch_uniform_1f(batch, "lineWidth", GPU_line_width_get());
GPU_batch_draw(batch);
@@ -1006,6 +1026,90 @@ static void view3d_interactive_add_calc_plane(bContext *C,
/** \} */
/* -------------------------------------------------------------------- */
/** \name Public Placement Plane Functionality
* \{ */
void ED_view3d_placement_plane_calc(bContext *C,
const int mval[2],
const int plane_axis,
float r_co_src[3],
float r_mat_orient[3][3])
{
Scene *scene = CTX_data_scene(C);
ARegion *region = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
/* TODO what if there is no snap gizmo? */
wmGizmo *snap_gizmo = idp_snap_gizmo_from_region(region);
const float mval_fl[] = {mval[0], mval[1]};
/* TODO Options here should be input parameters. */
view3d_interactive_add_calc_plane(C,
scene,
v3d,
region,
mval_fl,
snap_gizmo,
PLACE_SNAP_TO_GEOMETRY,
PLACE_DEPTH_SURFACE,
PLACE_ORIENT_SURFACE,
plane_axis,
false,
r_co_src,
r_mat_orient);
}
static void placement_plane_adjust_to_boundbox(const BoundBox *boundbox,
const enum ePlaceDirection direction,
const float scale[3],
const int plane_axis,
const float plane_mat_orient[3][3],
float r_co_src[3])
{
BLI_assert(ELEM(direction, PLACE_DIRECTION_NEG, PLACE_DIRECTION_POS));
const bool is_negative_up = scale[plane_axis] < 0;
/* Calculate the offset for all axes. */
float offset_vec[3] = {0};
{
/* Move the offset to put the return coordinate to the center of the bounding box. */
BKE_boundbox_calc_center_aabb(boundbox, offset_vec);
/* Push offset at the plane axis so the bounding box surface is where the snapping point is. */
float size[3];
BKE_boundbox_calc_size_aabb(boundbox, size);
offset_vec[plane_axis] -= size[plane_axis] * (is_negative_up ? -1 : 1);
/* Scale offset with the object scale. */
mul_v3_v3(offset_vec, scale);
if (direction == PLACE_DIRECTION_NEG) {
mul_v3_fl(offset_vec, -1);
}
}
/* Rotate the offset vector to the plane rotation. */
mul_v3_m3v3(offset_vec, plane_mat_orient, offset_vec);
/* Finally, add the rotated offset to the returned position. */
add_v3_v3(r_co_src, offset_vec);
}
void ED_view3d_placement_plane_boundbox_calc(bContext *C,
const int mval[2],
const BoundBox *boundbox,
const enum ePlaceDirection direction,
const float scale[3],
float r_co_src[3],
float r_mat_orient[3][3])
{
const int plane_axis = 2;
ED_view3d_placement_plane_calc(C, mval, plane_axis, r_co_src, r_mat_orient);
placement_plane_adjust_to_boundbox(
boundbox, direction, scale, plane_axis, r_mat_orient, r_co_src);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Add Object Modal Operator
* \{ */
@@ -1032,19 +1136,8 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv
struct InteractivePlaceData *ipd = op->customdata;
/* Assign snap gizmo which is may be used as part of the tool. */
{
wmGizmoGroup *gzgroup = idp_gizmogroup_from_region(ipd->region);
if (gzgroup != NULL) {
if (gzgroup->gizmos.first) {
ipd->snap_gizmo = gzgroup->gizmos.first;
}
/* Can be NULL when gizmos are disabled. */
if (gzgroup->customdata != NULL) {
preview_plane_cursor_visible_set(gzgroup, false);
}
}
}
ipd->snap_gizmo = idp_snap_gizmo_from_region(ipd->region);
idp_paintcursor_from_gizmo_visible_set(ipd->snap_gizmo, false);
/* For tweak events the snap target may have changed since dragging,
* update the snap target at the cursor location where tweak began.
@@ -1243,12 +1336,8 @@ static void view3d_interactive_add_exit(bContext *C, wmOperator *op)
ED_region_tag_redraw(ipd->region);
{
wmGizmoGroup *gzgroup = idp_gizmogroup_from_region(ipd->region);
if (gzgroup != NULL) {
if (gzgroup->customdata != NULL) {
preview_plane_cursor_visible_set(gzgroup, true);
}
}
wmGizmo *snap_gz = idp_snap_gizmo_from_region(ipd->region);
idp_paintcursor_from_gizmo_visible_set(snap_gz, true);
}
MEM_freeN(ipd);
@@ -1762,22 +1851,72 @@ static void WIDGETGROUP_placement_setup(const bContext *UNUSED(C), wmGizmoGroup
gizmo->flag |= WM_GIZMO_HIDDEN_KEYMAP;
}
/* Sets the gizmos custom-data which has its own free callback. */
preview_plane_cursor_setup(gzgroup);
{
const wmGizmoType *gzt_plane = WM_gizmotype_find("GIZMO_GT_placement_plane_3d", true);
gizmo = WM_gizmo_new_ptr(gzt_plane, gzgroup, NULL);
WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f});
/* Don't handle any events, this is for display only. */
gizmo->flag |= WM_GIZMO_HIDDEN_KEYMAP;
}
}
static void WIDGETGROUP_placement_draw_prepare(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
{
/* TODO only set for drag & drop. */
if (!gzgroup->ptr) {
return;
}
wmGizmo *gizmo_plane = ((wmGizmo *)gzgroup->gizmos.first)->next;
PropertyRNA *boundbox_prop = RNA_struct_find_property(gzgroup->ptr, "bound_box");
if (boundbox_prop && RNA_property_is_set(gzgroup->ptr, boundbox_prop)) {
float array[8][3];
RNA_property_float_get_array(gzgroup->ptr, boundbox_prop, (float *)array);
RNA_float_set_array(gizmo_plane->ptr, "bound_box", (float *)array);
}
PropertyRNA *matrix_basis_prop = RNA_struct_find_property(gzgroup->ptr, "matrix_basis");
if (matrix_basis_prop && RNA_property_is_set(gzgroup->ptr, matrix_basis_prop)) {
float array[4][4];
RNA_property_float_get_array(gzgroup->ptr, matrix_basis_prop, (float *)array);
RNA_float_set_array(gizmo_plane->ptr, "matrix_basis", (float *)array);
}
}
static bool WIDGETGROUP_placement_poll(const bContext *C, wmGizmoGroupType *gzgt)
{
return ED_gizmo_poll_from_dropbox(C, gzgt) || ED_gizmo_poll_from_tool(C, gzgt);
}
void VIEW3D_GGT_placement(wmGizmoGroupType *gzgt)
{
PropertyRNA *prop;
gzgt->name = "Placement Widget";
gzgt->idname = view3d_gzgt_placement_id;
gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL;
gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL |
WM_GIZMOGROUPTYPE_ATTACHED_TO_CURSOR;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool;
gzgt->poll = WIDGETGROUP_placement_poll;
gzgt->setup = WIDGETGROUP_placement_setup;
gzgt->draw_prepare = WIDGETGROUP_placement_draw_prepare;
const int boundbox_dimsize[] = {8, 3};
prop = RNA_def_property(gzgt->srna, "bound_box", PROP_FLOAT, PROP_NONE);
RNA_def_property_multi_array(prop, 2, boundbox_dimsize);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
const int matrix_dimsize[] = {4, 4};
prop = RNA_def_property(gzgt->srna, "matrix_basis", PROP_FLOAT, PROP_NONE);
RNA_def_property_multi_array(prop, 2, matrix_dimsize);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/** \} */
@@ -1819,13 +1958,7 @@ static void gizmo_plane_update_cursor(const bContext *C,
View3D *v3d = CTX_wm_view3d(C);
/* Assign snap gizmo which is may be used as part of the tool. */
wmGizmo *snap_gizmo = NULL;
{
wmGizmoGroup *gzgroup = idp_gizmogroup_from_region(region);
if ((gzgroup != NULL) && gzgroup->gizmos.first) {
snap_gizmo = gzgroup->gizmos.first;
}
}
wmGizmo *snap_gizmo = idp_snap_gizmo_from_region(region);
/* This ensures the snap gizmo has settings from this tool.
* This function call could be moved a more appropriate place,
@@ -1964,6 +2097,11 @@ struct PlacementCursor {
void *paintcursor;
float boundbox[8][3];
bool draw_boundbox;
float scale[3];
int plane_axis;
float matrix[4][4];
@@ -1972,9 +2110,8 @@ struct PlacementCursor {
float persmat_prev[4][4];
};
static void cursor_plane_draw(bContext *C, int x, int y, void *customdata)
static void cursor_plane_draw_ex(const bContext *C, const int mval[2], struct PlacementCursor *plc)
{
struct PlacementCursor *plc = (struct PlacementCursor *)customdata;
ARegion *region = CTX_wm_region(C);
const RegionView3D *rv3d = region->regiondata;
@@ -1994,6 +2131,9 @@ static void cursor_plane_draw(bContext *C, int x, int y, void *customdata)
return;
}
GPU_line_smooth(false);
GPU_line_width(1.0f);
/* Check this gizmo group is in the region. */
{
wmGizmoMap *gzmap = region->gizmo_map;
@@ -2004,8 +2144,6 @@ static void cursor_plane_draw(bContext *C, int x, int y, void *customdata)
}
}
const int mval[2] = {x - region->winrct.xmin, y - region->winrct.ymin};
/* Update matrix? */
if ((plc->mval_prev[0] != mval[0]) || (plc->mval_prev[1] != mval[1]) ||
!equals_m4m4(plc->persmat_prev, rv3d->persmat)) {
@@ -2055,17 +2193,29 @@ static void cursor_plane_draw(bContext *C, int x, int y, void *customdata)
}
/* Setup viewport & matrix. */
wmViewport(&region->winrct);
if (plc->paintcursor) {
/* Paint cursors are on window level, need to set the viewport. */
wmViewport(&region->winrct);
}
GPU_matrix_push_projection();
GPU_matrix_push();
GPU_matrix_projection_set(rv3d->winmat);
GPU_matrix_set(rv3d->viewmat);
const float scale_mod = U.gizmo_size * 2 * U.dpi_fac / U.pixelsize;
float final_scale;
if (plc->draw_boundbox) {
/* Take diagonal of lower face to make the size based on the boundbox. */
float lower_min[3], lower_max[3];
mul_v3_v3v3(lower_min, plc->boundbox[0], plc->scale);
mul_v3_v3v3(lower_max, plc->boundbox[6], plc->scale);
final_scale = len_v3v3(lower_min, lower_max);
}
else {
const float scale_mod = U.gizmo_size * 2 * U.dpi_fac / U.pixelsize;
final_scale = (scale_mod * pixel_size);
}
float final_scale = (scale_mod * pixel_size);
const int lines_subdiv = 10;
const int lines_subdiv = 10.0f;
int lines = lines_subdiv;
float final_scale_fade = final_scale;
@@ -2093,12 +2243,46 @@ static void cursor_plane_draw(bContext *C, int x, int y, void *customdata)
gizmo_plane_draw_grid(
lines, final_scale, final_scale_fade, plc->matrix, plc->plane_axis, color);
/* TODO support different plane axis (assumes Z right now). */
if (plc->draw_boundbox) {
float box_col[4] = {0.4f, 0.8f, 1.0f, 0.75f};
BoundBox bounds;
memcpy(bounds.vec, plc->boundbox, sizeof(bounds.vec));
float size[3];
BKE_boundbox_calc_size_aabb(&bounds, size);
float min[3] = {-size[0], -size[1], 0.0f};
float max[3] = {size[0], size[1], size[2] * 2};
mul_v3_v3(min, plc->scale);
mul_v3_v3(max, plc->scale);
BKE_boundbox_init_from_minmax(&bounds, min, max);
GPU_matrix_mul(plc->matrix);
/* Ensure the bounding-box points up. Matches how it will be placed eventualy. */
const bool negative_up = bounds.vec[1][2] < 0;
if (negative_up) {
GPU_matrix_scale_1f(-1.0f);
}
GPU_line_width(2.0f);
draw_line_bounds(&bounds, box_col);
}
/* Restore matrix. */
GPU_matrix_pop();
GPU_matrix_pop_projection();
}
}
static void cursor_plane_draw_cursor_fn(bContext *C, int x, int y, void *customdata)
{
struct PlacementCursor *plc = (struct PlacementCursor *)customdata;
const ARegion *region = CTX_wm_region(C);
const int mval[2] = {x - region->winrct.xmin, y - region->winrct.ymin};
cursor_plane_draw_ex(C, mval, plc);
}
static void preview_plane_cursor_free(void *customdata)
{
struct PlacementCursor *plc = customdata;
@@ -2111,13 +2295,13 @@ static void preview_plane_cursor_free(void *customdata)
MEM_freeN(plc);
}
static void preview_plane_cursor_setup(wmGizmoGroup *gzgroup)
static void UNUSED_FUNCTION(preview_plane_cursor_setup)(wmGizmoGroup *gzgroup)
{
BLI_assert(gzgroup->customdata == NULL);
struct PlacementCursor *plc = MEM_callocN(sizeof(*plc), __func__);
plc->gzgroup = gzgroup;
plc->paintcursor = WM_paint_cursor_activate(
SPACE_VIEW3D, RGN_TYPE_WINDOW, NULL, cursor_plane_draw, plc);
SPACE_VIEW3D, RGN_TYPE_WINDOW, NULL, cursor_plane_draw_cursor_fn, plc);
gzgroup->customdata = plc;
gzgroup->customdata_free = preview_plane_cursor_free;
@@ -2131,3 +2315,91 @@ static void preview_plane_cursor_visible_set(wmGizmoGroup *gzgroup, bool do_draw
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Placement Plane Gizmo
* \{ */
struct PlacementPlaneGizmo {
wmGizmo gizmo;
struct PlacementCursor *plc;
};
static void gizmo_placement_plane_setup(wmGizmo *gz)
{
struct PlacementPlaneGizmo *plane_gz = (struct PlacementPlaneGizmo *)gz;
plane_gz->plc = MEM_callocN(sizeof(*plane_gz->plc), __func__);
plane_gz->plc->gzgroup = gz->parent_gzgroup;
}
static void gizmo_placement_plane_free(wmGizmo *gz)
{
struct PlacementPlaneGizmo *plane_gz = (struct PlacementPlaneGizmo *)gz;
MEM_SAFE_FREE(plane_gz->plc);
}
static void gizmo_placement_plane_draw(const bContext *C, wmGizmo *gz)
{
struct PlacementPlaneGizmo *plane_gz = (struct PlacementPlaneGizmo *)gz;
struct PlacementCursor *plc = plane_gz->plc;
const wmWindow *win = CTX_wm_window(C);
plc->do_draw = true;
PropertyRNA *boundbox_prop = RNA_struct_find_property(gz->ptr, "bound_box");
if (RNA_property_is_set(gz->ptr, boundbox_prop)) {
RNA_property_float_get_array(gz->ptr, boundbox_prop, (float *)plc->boundbox);
plc->draw_boundbox = true;
}
else {
plc->draw_boundbox = false;
}
PropertyRNA *matrix_basis_prop = RNA_struct_find_property(gz->ptr, "matrix_basis");
if (RNA_property_is_set(gz->ptr, matrix_basis_prop)) {
float mat[4][4];
RNA_property_float_get_array(gz->ptr, matrix_basis_prop, (float *)mat);
mat4_to_size(plc->scale, mat);
}
else {
copy_v3_fl(plc->scale, 1.0f);
}
const wmEvent *eventstate = win->eventstate;
const ARegion *region = CTX_wm_region(C);
const int mval[2] = {eventstate->x - region->winrct.xmin, eventstate->y - region->winrct.ymin};
cursor_plane_draw_ex(C, mval, plc);
}
static void GIZMO_GT_placement_plane_3d(wmGizmoType *gzt)
{
PropertyRNA *prop;
/* identifiers */
gzt->idname = "GIZMO_GT_placement_plane_3d";
/* api callbacks */
gzt->setup = gizmo_placement_plane_setup;
gzt->draw = gizmo_placement_plane_draw;
gzt->free = gizmo_placement_plane_free;
gzt->struct_size = sizeof(struct PlacementPlaneGizmo);
const int boundbox_dimsize[] = {8, 3};
prop = RNA_def_property(gzt->srna, "bound_box", PROP_FLOAT, PROP_NONE);
RNA_def_property_multi_array(prop, 2, boundbox_dimsize);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
const int matrix_dimsize[] = {4, 4};
prop = RNA_def_property(gzt->srna, "matrix_basis", PROP_FLOAT, PROP_NONE);
RNA_def_property_multi_array(prop, 2, matrix_dimsize);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
void ED_gizmotypes_placement_3d(void)
{
WM_gizmotype_append(GIZMO_GT_placement_plane_3d);
}
/** \} */

View File

@@ -75,3 +75,27 @@ bool ED_gizmo_poll_or_unlink_delayed_from_tool(const bContext *C, wmGizmoGroupTy
{
return ED_gizmo_poll_or_unlink_delayed_from_tool_ex(C, gzgt, gzgt->idname);
}
bool ED_gizmo_poll_from_tool_ex(const bContext *C, const char *gzgt_idname)
{
bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
if ((tref_rt == NULL) || !STREQ(gzgt_idname, tref_rt->gizmo_group)) {
return false;
}
return true;
}
bool ED_gizmo_poll_from_tool(const bContext *C, const wmGizmoGroupType *gzgt)
{
return ED_gizmo_poll_from_tool_ex(C, gzgt->idname);
}
bool ED_gizmo_poll_from_dropbox_ex(const bContext *C, const char *gzgt_idname)
{
return WM_drag_with_gizmogroup_find(CTX_wm_manager(C), gzgt_idname) != NULL;
}
bool ED_gizmo_poll_from_dropbox(const bContext *C, const wmGizmoGroupType *gzgt)
{
return ED_gizmo_poll_from_dropbox_ex(C, gzgt->idname);
}

View File

@@ -56,6 +56,9 @@ typedef struct AssetFilterSettings {
* more than that from the file. So pointers to other IDs or ID data are strictly forbidden.
*/
typedef struct AssetMetaData {
/** Runtime type, to reference event callbacks. Only valid for local assets. */
struct AssetTypeInfo *local_type_info;
/** Custom asset meta-data. Cannot store pointers to IDs (#STRUCT_NO_DATABLOCK_IDPROPERTIES)! */
struct IDProperty *properties;

View File

@@ -735,6 +735,9 @@ struct wmDropBox *WM_dropbox_add(
void (*copy)(struct wmDrag *, struct wmDropBox *),
void (*cancel)(struct Main *, struct wmDrag *, struct wmDropBox *),
WMDropboxTooltipFunc tooltip);
void WM_dropbox_gizmogroup_set(struct wmDropBox *,
const char gizmo_group[MAX_NAME],
void (*copy_gizmo_group)(struct wmDrag *, struct wmDropBox *));
ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid);
/* ID drag and drop */
@@ -744,9 +747,11 @@ struct ID *WM_drag_get_local_ID_from_event(const struct wmEvent *event, short id
bool WM_drag_is_ID_type(const struct wmDrag *drag, int idcode);
wmDragAsset *WM_drag_create_asset_data(const struct AssetHandle *asset,
struct AssetMetaData *metadata,
const char *path,
int import_type);
struct wmDragAsset *WM_drag_get_asset_data(const struct wmDrag *drag, int idcode);
struct AssetMetaData *WM_drag_get_asset_meta_data(const struct wmDrag *drag, int idcode);
struct ID *WM_drag_get_local_ID_or_import_from_asset(const struct wmDrag *drag, int idcode);
void WM_drag_free_imported_drag_ID(struct Main *bmain,
@@ -759,6 +764,9 @@ void WM_drag_add_asset_list_item(wmDrag *drag,
const struct AssetHandle *asset);
const ListBase *WM_drag_asset_list_get(const wmDrag *drag);
const struct wmDrag *WM_drag_with_gizmogroup_find(
const struct wmWindowManager *wm, const char name[MAX_NAME]) ATTR_WARN_UNUSED_RESULT;
const char *WM_drag_get_item_name(struct wmDrag *drag);
/* Set OpenGL viewport and scissor */

View File

@@ -982,6 +982,7 @@ typedef struct wmDragAsset {
/* Always freed. */
const char *path;
int id_type;
struct AssetMetaData *metadata;
int import_type; /* eFileAssetImportType */
/* FIXME: This is temporary evil solution to get scene/view-layer/etc in the copy callback of the
@@ -1031,8 +1032,15 @@ typedef struct wmDrag {
float scale;
int sx, sy;
/** Don't draw the icon or image (`imb`). Can be set in the `poll()` callback of the drop-box. */
bool no_preview;
/** If filled, draws operator tooltip/operator name. */
char tooltip[200];
/** If set, draws gizmo group. */
char gizmo_group[64];
struct IDProperty *gizmo_group_prop;
unsigned int flags;
/** List of wmDragIDs, all are guaranteed to have the same ID type. */
@@ -1041,6 +1049,8 @@ typedef struct wmDrag {
ListBase asset_items;
} wmDrag;
typedef void (*wmDropBoxCopyFn)(struct wmDrag *, struct wmDropBox *);
/**
* Dropboxes are like keymaps, part of the screen/area/region definition.
* Allocation and free is on startup and exit.
@@ -1052,7 +1062,9 @@ typedef struct wmDropBox {
bool (*poll)(struct bContext *, struct wmDrag *, const wmEvent *);
/** Before exec, this copies drag info to #wmDrop properties. */
void (*copy)(struct wmDrag *, struct wmDropBox *);
wmDropBoxCopyFn copy;
/** Before `gizmo_group` is enabled, this copies drag info to #wmDrop gizmo-group properties. */
wmDropBoxCopyFn copy_gizmo_group;
/**
* If the operator is cancelled (returns `OPERATOR_CANCELLED`), this can be used for cleanup of
@@ -1068,15 +1080,18 @@ typedef struct wmDropBox {
* Not saved in file, so can be pointer.
*/
wmOperatorType *ot;
/** Operator properties, assigned to ptr->data and can be written to a file. */
struct IDProperty *properties;
/** RNA pointer to access properties. */
struct PointerRNA *ptr;
/** Default invoke. */
short opcontext;
/**
* If poll succeeds, gizmo is drawn.
*/
char gizmo_group[64];
struct PointerRNA *gizmo_group_ptr;
} wmDropBox;
/**

View File

@@ -155,6 +155,11 @@ typedef enum eWM_GizmoFlagGroupTypeFlag {
*/
WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK = (1 << 9),
/**
* Redraw the region's gizmos on mouse moves.
*/
WM_GIZMOGROUPTYPE_ATTACHED_TO_CURSOR = (1 << 9),
/**
* Cause continuous redraws, i.e. set the region redraw flag on every main loop iteration. This
* should really be avoided by using proper region redraw tagging, notifiers and the message-bus,
@@ -483,6 +488,9 @@ typedef struct wmGizmoGroup {
struct wmGizmoGroupType *type;
ListBase gizmos;
struct PointerRNA *ptr;
struct IDProperty *properties;
struct wmGizmoMap *parent_gzmap;
/** Python stores the class instance here. */

View File

@@ -37,6 +37,7 @@
#include "BLI_string.h"
#include "BKE_context.h"
#include "BKE_idprop.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_workspace.h"
@@ -122,6 +123,14 @@ void wm_gizmogroup_free(bContext *C, wmGizmoGroup *gzgroup)
MEM_freeN(gzgroup->reports);
}
if (gzgroup->ptr) {
gzgroup->properties = gzgroup->ptr->data;
MEM_freeN(gzgroup->ptr);
}
if (gzgroup->properties) {
IDP_FreeProperty(gzgroup->properties);
}
if (gzgroup->customdata_free) {
gzgroup->customdata_free(gzgroup->customdata);
}

View File

@@ -40,6 +40,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -130,6 +131,15 @@ wmDropBox *WM_dropbox_add(ListBase *lb,
return drop;
}
void WM_dropbox_gizmogroup_set(wmDropBox *drop,
const char gizmo_group[MAX_NAME],
wmDropBoxCopyFn copy_gizmo_group)
{
BLI_strncpy(drop->gizmo_group, gizmo_group, sizeof(drop->gizmo_group));
drop->copy_gizmo_group = copy_gizmo_group;
WM_gizmo_group_type_add(gizmo_group);
}
void wm_dropbox_free(void)
{
@@ -250,6 +260,25 @@ void WM_drag_free_list(struct ListBase *lb)
}
}
struct wmDropboxActiveInfo {
wmDropBox *drop;
/* Some string the operator sets (operator name or some tooltip). */
const char *operator_string;
const char *gizmo_group;
};
static void wm_gizmogroup_properties_create(PointerRNA *ptr, const char *gz_group_name)
{
const wmGizmoGroupType *gz_grouptype = WM_gizmogrouptype_find(gz_group_name, false);
if (gz_grouptype) {
RNA_pointer_create(NULL, gz_grouptype->srna, NULL, ptr);
}
else {
RNA_pointer_create(NULL, &RNA_GizmoGroupProperties, NULL, ptr);
}
}
static char *dropbox_tooltip(bContext *C, wmDrag *drag, const wmEvent *event, wmDropBox *drop)
{
char *tooltip = NULL;
@@ -264,6 +293,40 @@ static char *dropbox_tooltip(bContext *C, wmDrag *drag, const wmEvent *event, wm
return tooltip;
}
static void wm_gizmogroup_properties_alloc(PointerRNA **ptr,
IDProperty **properties,
const char *gz_group_name)
{
if (*properties == NULL) {
IDPropertyTemplate val = {0};
*properties = IDP_New(IDP_GROUP, &val, "wmGizmoGroupProp");
}
if (*ptr == NULL) {
*ptr = MEM_callocN(sizeof(PointerRNA), "wmGizmoGroupPtr");
wm_gizmogroup_properties_create(*ptr, gz_group_name);
}
(*ptr)->data = *properties;
}
static void dropbox_gizmo_activate(bContext *C, wmDrag *drag, wmDropBox *drop)
{
if (!STREQ(drag->gizmo_group, drop->gizmo_group)) {
if (drop->gizmo_group[0]) {
ARegion *region = CTX_wm_region(C);
wmGizmoGroup *gzgroup = WM_gizmomap_group_find(region->gizmo_map, drop->gizmo_group);
if (gzgroup) {
wm_gizmogroup_properties_alloc(&gzgroup->ptr, &gzgroup->properties, drop->gizmo_group);
WM_gizmo_properties_sanitize(gzgroup->ptr, 0);
drop->gizmo_group_ptr = gzgroup->ptr;
drop->copy_gizmo_group(drag, drop);
}
}
}
BLI_strncpy(drag->gizmo_group, drop->gizmo_group, sizeof(drag->gizmo_group));
}
static wmDropBox *dropbox_active(bContext *C,
ListBase *handlers,
wmDrag *drag,
@@ -285,11 +348,18 @@ static wmDropBox *dropbox_active(bContext *C,
return NULL;
}
/* return active operator tooltip/name when mouse is in box */
static char *wm_dropbox_active(bContext *C, wmDrag *drag, const wmEvent *event)
/* return active operator name when mouse is in box */
/**
* \returns Pointer to static `wmDropboxActiveInfo` data, when the mouse is in a box with a
* succeeding poll().
*/
static struct wmDropboxActiveInfo *wm_dropbox_active(bContext *C,
wmDrag *drag,
const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
wmDropBox *drop = dropbox_active(C, &win->handlers, drag, event);
if (!drop) {
ScrArea *area = CTX_wm_area(C);
drop = dropbox_active(C, &area->handlers, drag, event);
@@ -298,9 +368,15 @@ static char *wm_dropbox_active(bContext *C, wmDrag *drag, const wmEvent *event)
ARegion *region = CTX_wm_region(C);
drop = dropbox_active(C, &region->handlers, drag, event);
}
if (drop) {
return dropbox_tooltip(C, drag, event, drop);
static struct wmDropboxActiveInfo active_info;
active_info.drop = drop;
active_info.gizmo_group = drop->gizmo_group;
active_info.operator_string = dropbox_tooltip(C, drag, event, drop);
return &active_info;
}
return NULL;
}
@@ -316,19 +392,28 @@ static void wm_drop_operator_options(bContext *C, wmDrag *drag, const wmEvent *e
}
drag->tooltip[0] = 0;
/* Allow setting this in the `poll()`. */
drag->no_preview = false;
/* check buttons (XXX todo rna and value) */
if (UI_but_active_drop_name(C)) {
BLI_strncpy(drag->tooltip, IFACE_("Paste name"), sizeof(drag->tooltip));
drag->gizmo_group[0] = 0;
}
else {
char *tooltip = wm_dropbox_active(C, drag, event);
struct wmDropboxActiveInfo *active_info = wm_dropbox_active(C, drag, event);
if (tooltip) {
BLI_strncpy(drag->tooltip, tooltip, sizeof(drag->tooltip));
MEM_freeN(tooltip);
if (active_info && active_info->operator_string) {
BLI_strncpy(drag->tooltip, active_info->operator_string, sizeof(drag->tooltip));
MEM_freeN((char *)active_info->operator_string);
// WM_cursor_modal_set(win, WM_CURSOR_COPY);
}
if (active_info && active_info->gizmo_group) {
dropbox_gizmo_activate(C, drag, active_info->drop);
}
else {
drag->gizmo_group[0] = 0;
}
// else
// WM_cursor_modal_restore(win);
/* unsure about cursor type, feels to be too much */
@@ -406,11 +491,15 @@ bool WM_drag_is_ID_type(const wmDrag *drag, int idcode)
/**
* \note: Does not store \a asset in any way, so it's fine to pass a temporary.
*/
wmDragAsset *WM_drag_create_asset_data(const AssetHandle *asset, const char *path, int import_type)
wmDragAsset *WM_drag_create_asset_data(const AssetHandle *asset,
AssetMetaData *metadata,
const char *path,
int import_type)
{
wmDragAsset *asset_drag = MEM_mallocN(sizeof(*asset_drag), "wmDragAsset");
BLI_strncpy(asset_drag->name, ED_asset_handle_get_name(asset), sizeof(asset_drag->name));
asset_drag->metadata = metadata;
asset_drag->path = path;
asset_drag->id_type = ED_asset_handle_get_id_type(asset);
asset_drag->import_type = import_type;
@@ -434,6 +523,21 @@ wmDragAsset *WM_drag_get_asset_data(const wmDrag *drag, int idcode)
return (ELEM(idcode, 0, asset_drag->id_type)) ? asset_drag : NULL;
}
struct AssetMetaData *WM_drag_get_asset_meta_data(const wmDrag *drag, int idcode)
{
wmDragAsset *drag_asset = WM_drag_get_asset_data(drag, idcode);
if (drag_asset) {
return drag_asset->metadata;
}
ID *local_id = WM_drag_get_local_ID(drag, idcode);
if (local_id) {
return local_id->asset_data;
}
return NULL;
}
static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag)
{
const char *name = asset_drag->name;
@@ -565,11 +669,12 @@ void WM_drag_add_asset_list_item(
drag_asset->asset_data.local_id = local_id;
}
else {
AssetMetaData *metadata = ED_asset_handle_get_metadata(asset);
char asset_blend_path[FILE_MAX_LIBEXTRA];
ED_asset_handle_get_full_library_path(C, asset_library_ref, asset, asset_blend_path);
drag_asset->is_external = true;
drag_asset->asset_data.external_info = WM_drag_create_asset_data(
asset, BLI_strdup(asset_blend_path), FILE_ASSET_IMPORT_APPEND);
asset, metadata, BLI_strdup(asset_blend_path), FILE_ASSET_IMPORT_APPEND);
}
BLI_addtail(&drag->asset_items, drag_asset);
}
@@ -665,8 +770,12 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
int padding = 4 * UI_DPI_FAC;
/* image or icon */
int x, y;
if (drag->imb) {
int x = cursorx - 2 * padding;
int y = cursory - 2 * UI_DPI_FAC;
if (drag->no_preview) {
/* Pass. */
}
else if (drag->imb) {
x = cursorx - drag->sx / 2;
y = cursory - drag->sy / 2;
@@ -692,9 +801,6 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
}
}
else {
x = cursorx - 2 * padding;
y = cursory - 2 * UI_DPI_FAC;
if (rect) {
drag_rect_minmax(rect, x, y, x + iconsize, y + iconsize);
}
@@ -704,7 +810,7 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
}
/* item name */
if (drag->imb) {
if (!drag->no_preview && drag->imb) {
x = cursorx - drag->sx / 2;
y = cursory - drag->sy / 2 - iconsize;
}
@@ -755,3 +861,16 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
}
GPU_blend(GPU_BLEND_NONE);
}
/* ************** Queries ***************** */
const wmDrag *WM_drag_with_gizmogroup_find(const wmWindowManager *wm, const char name[MAX_NAME])
{
LISTBASE_FOREACH (const wmDrag *, drag, &wm->drags) {
if (STREQ(drag->gizmo_group, name)) {
return drag;
}
}
return NULL;
}

View File

@@ -2964,6 +2964,13 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
}
}
const ListBase *groups = WM_gizmomap_group_list(gzmap);
LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, groups) {
if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_ATTACHED_TO_CURSOR) {
ED_region_tag_redraw_editor_overlays(CTX_wm_region(C));
}
}
/* restore the area */
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
@@ -3080,6 +3087,10 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
action |= WM_HANDLER_BREAK;
if (drop->gizmo_group[0]) {
/* Redraw so gizmos disappear visually. */
ED_region_tag_redraw_editor_overlays(CTX_wm_region(C));
}
/* Free the drags. */
WM_drag_free_list(lb);
WM_drag_free_list(&single_lb);
@@ -3386,7 +3397,10 @@ static void wm_paintcursor_test(bContext *C, const wmEvent *event)
}
}
static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEvent *event)
static void wm_event_drag_and_drop_test(bContext *C,
wmWindowManager *wm,
wmWindow *win,
wmEvent *event)
{
bScreen *screen = WM_window_get_active_screen(win);
@@ -3398,6 +3412,7 @@ static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEv
screen->do_draw_drag = true;
}
else if (event->type == EVT_ESCKEY) {
ED_region_tag_redraw_editor_overlays(CTX_wm_region(C));
WM_drag_free_list(&wm->drags);
screen->do_draw_drag = true;
@@ -3673,7 +3688,7 @@ void wm_event_do_handlers(bContext *C)
}
/* Check dragging, creates new event or frees, adds draw tag. */
wm_event_drag_and_drop_test(wm, win, event);
wm_event_drag_and_drop_test(C, wm, win, event);
/* Builtin tweak, if action is break it removes tweak. */
wm_tweakevent_test(C, event, action);

View File

@@ -105,6 +105,7 @@
#include "IMB_imbuf_types.h"
#include "IMB_thumbs.h"
#include "ED_asset.h"
#include "ED_datafiles.h"
#include "ED_fileselect.h"
#include "ED_image.h"
@@ -1781,6 +1782,7 @@ static bool wm_file_write(bContext *C,
/* Call pre-save callbacks before writing preview,
* that way you can generate custom file thumbnail. */
BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_PRE);
ED_assets_pre_save(bmain);
/* Enforce full override check/generation on file save. */
BKE_lib_override_library_main_operations_create(bmain, true);
@@ -2098,6 +2100,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
}
BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_PRE);
ED_assets_pre_save(bmain);
/* check current window and close it if temp */
if (win && WM_window_is_temp_screen(win)) {