Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

View File

@@ -0,0 +1,744 @@
/* SPDX-FileCopyrightText: 2014 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup wm
*/
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
#include "BLI_math_matrix.h"
#include "BLI_math_vector.h"
#include "BKE_context.hh"
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "RNA_prototypes.hh"
#include "BKE_global.hh"
#include "BKE_idprop.hh"
#include "BKE_main.hh"
#include "WM_api.hh"
#include "WM_toolsystem.hh"
#include "WM_types.hh"
#include "ED_screen.hh"
#include "ED_view3d.hh"
#ifdef WITH_PYTHON
# include "BPY_extern.hh"
#endif
/* Own includes. */
#include "wm_gizmo_intern.hh"
#include "wm_gizmo_wmapi.hh"
namespace blender {
static void wm_gizmo_register(wmGizmoGroup *gzgroup, wmGizmo *gz);
/**
* \note Follow #wm_operator_create convention.
*/
static wmGizmo *wm_gizmo_create(const wmGizmoType *gzt, PointerRNA *properties)
{
BLI_assert(gzt != nullptr);
BLI_assert(gzt->struct_size >= sizeof(wmGizmo));
/* FIXME: Old C-style allocation is not trivial to port to C++ here, because actual allocation
* depends on the 'subtype' of gizmo. The whole gizmo type hierarchy should probably be moved to
* proper C++ virtual inheritance at some point. */
wmGizmo *gz = static_cast<wmGizmo *>(MEM_new_zeroed(gzt->struct_size, __func__));
new (gz) wmGizmo();
gz->type = gzt;
/* Initialize properties, either copy or create. */
gz->ptr = MEM_new<PointerRNA>("wmGizmoPtrRNA");
if (properties && properties->data) {
gz->properties = IDP_CopyProperty(static_cast<const IDProperty *>(properties->data));
}
else {
gz->properties = bke::idprop::create_group("wmGizmoProperties").release();
}
*gz->ptr = RNA_pointer_create_discrete(
static_cast<ID *>(G_MAIN->wm.first), gzt->srna, gz->properties);
WM_gizmo_properties_sanitize(gz->ptr, false);
unit_m4(gz->matrix_space);
unit_m4(gz->matrix_basis);
unit_m4(gz->matrix_offset);
gz->drag_part = -1;
/* Only ensure expected size for the target properties array. Actual initialization of these
* happen separately (see e.g. #WM_gizmo_target_property_def_rna and related). */
gz->target_properties.resize(gzt->target_property_defs_len);
return gz;
}
wmGizmo *WM_gizmo_new_ptr(const wmGizmoType *gzt, wmGizmoGroup *gzgroup, PointerRNA *properties)
{
wmGizmo *gz = wm_gizmo_create(gzt, properties);
wm_gizmo_register(gzgroup, gz);
if (gz->type->setup != nullptr) {
gz->type->setup(gz);
}
return gz;
}
wmGizmo *WM_gizmo_new(const StringRef idname, wmGizmoGroup *gzgroup, PointerRNA *properties)
{
const wmGizmoType *gzt = WM_gizmotype_find(idname, false);
return WM_gizmo_new_ptr(gzt, gzgroup, properties);
}
/**
* Initialize default values and allocate needed memory for members.
*/
static void gizmo_init(wmGizmo *gz)
{
const float color_default[4] = {1.0f, 1.0f, 1.0f, 1.0f};
gz->scale_basis = 1.0f;
gz->line_width = 1.0f;
/* Defaults. */
copy_v4_v4(gz->color, color_default);
copy_v4_v4(gz->color_hi, color_default);
}
/**
* Register \a gizmo.
*
* \note Not to be confused with type registration from RNA.
*/
static void wm_gizmo_register(wmGizmoGroup *gzgroup, wmGizmo *gz)
{
gizmo_init(gz);
wm_gizmogroup_gizmo_register(gzgroup, gz);
}
void WM_gizmo_free(wmGizmo *gz)
{
if (gz->type->free != nullptr) {
gz->type->free(gz);
}
#ifdef WITH_PYTHON
if (gz->py_instance) {
/* Do this first in case there are any `__del__` functions or
* similar that use properties. */
BPY_DECREF_RNA_INVALIDATE(gz->py_instance);
}
#endif
for (wmGizmoOpElem &gzop : gz->op_data) {
WM_operator_properties_free(&gzop.ptr);
}
if (gz->ptr != nullptr) {
WM_gizmo_properties_free(gz->ptr);
MEM_delete(gz->ptr);
}
for (wmGizmoProperty &gz_prop : gz->target_properties) {
if (gz_prop.custom_func.free_fn) {
gz_prop.custom_func.free_fn(gz, &gz_prop);
}
}
MEM_delete(gz);
}
void WM_gizmo_unlink(ListBaseT<wmGizmo> *gizmolist, wmGizmoMap *gzmap, wmGizmo *gz, bContext *C)
{
if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) {
wm_gizmomap_highlight_set(gzmap, C, nullptr, 0);
}
if (gz->state & WM_GIZMO_STATE_MODAL) {
wm_gizmomap_modal_set(gzmap, C, gz, nullptr, false);
}
/* Unlink instead of setting so we don't run callbacks. */
if (gz->state & WM_GIZMO_STATE_SELECT) {
WM_gizmo_select_unlink(gzmap, gz);
}
if (gizmolist) {
BLI_remlink(gizmolist, gz);
}
BLI_assert(gzmap->gzmap_context.highlight != gz);
BLI_assert(gzmap->gzmap_context.modal != gz);
WM_gizmo_free(gz);
}
/* -------------------------------------------------------------------- */
/** \name Gizmo Creation API
*
* API for defining data on gizmo creation.
*
* \{ */
wmGizmoOpElem *WM_gizmo_operator_get(wmGizmo *gz, int part_index)
{
if ((part_index >= 0) && (part_index < gz->op_data.size())) {
return &gz->op_data[part_index];
}
return nullptr;
}
PointerRNA *WM_gizmo_operator_set(wmGizmo *gz,
int part_index,
wmOperatorType *ot,
IDProperty *properties)
{
BLI_assert(part_index < 255);
if (part_index >= gz->op_data.size()) {
gz->op_data.resize(part_index + 1);
}
wmGizmoOpElem &gzop = gz->op_data[part_index];
gzop.type = ot;
if (gzop.ptr.data) {
WM_operator_properties_free(&gzop.ptr);
}
gzop.ptr = WM_operator_properties_create_ptr(ot);
if (properties) {
gzop.ptr.data = properties;
}
return &gzop.ptr;
}
wmOperatorStatus WM_gizmo_operator_invoke(bContext *C,
wmGizmo *gz,
wmGizmoOpElem *gzop,
const wmEvent *event)
{
if (gz->flag & WM_GIZMO_OPERATOR_TOOL_INIT) {
/* Merge tool-settings into the gizmo properties. */
PointerRNA tref_ptr;
bToolRef *tref = WM_toolsystem_ref_from_context(C);
if (tref && WM_toolsystem_ref_properties_get_from_operator(tref, gzop->type, &tref_ptr)) {
if (gzop->ptr.data == nullptr) {
gzop->ptr.data = bke::idprop::create_group("wmOperatorProperties").release();
}
IDP_MergeGroup(static_cast<IDProperty *>(gzop->ptr.data),
static_cast<const IDProperty *>(tref_ptr.data),
false);
}
}
return WM_operator_name_call_ptr(
C, gzop->type, wm::OpCallContext::InvokeDefault, &gzop->ptr, event);
}
static void wm_gizmo_set_matrix_rotation_from_z_axis__internal(float matrix[4][4],
const float z_axis[3])
{
/* Old code, seems we can use simpler method. */
#if 0
const float z_global[3] = {0.0f, 0.0f, 1.0f};
float rot[3][3];
rotation_between_vecs_to_mat3(rot, z_global, z_axis);
copy_v3_v3(matrix[0], rot[0]);
copy_v3_v3(matrix[1], rot[1]);
copy_v3_v3(matrix[2], rot[2]);
#else
normalize_v3_v3(matrix[2], z_axis);
ortho_basis_v3v3_v3(matrix[0], matrix[1], matrix[2]);
#endif
}
static void wm_gizmo_set_matrix_rotation_from_yz_axis__internal(float matrix[4][4],
const float y_axis[3],
const float z_axis[3])
{
normalize_v3_v3(matrix[1], y_axis);
normalize_v3_v3(matrix[2], z_axis);
cross_v3_v3v3(matrix[0], matrix[1], matrix[2]);
normalize_v3(matrix[0]);
}
void WM_gizmo_set_matrix_rotation_from_z_axis(wmGizmo *gz, const float z_axis[3])
{
wm_gizmo_set_matrix_rotation_from_z_axis__internal(gz->matrix_basis, z_axis);
}
void WM_gizmo_set_matrix_rotation_from_yz_axis(wmGizmo *gz,
const float y_axis[3],
const float z_axis[3])
{
wm_gizmo_set_matrix_rotation_from_yz_axis__internal(gz->matrix_basis, y_axis, z_axis);
}
void WM_gizmo_set_matrix_location(wmGizmo *gz, const float origin[3])
{
copy_v3_v3(gz->matrix_basis[3], origin);
}
void WM_gizmo_set_matrix_offset_rotation_from_z_axis(wmGizmo *gz, const float z_axis[3])
{
wm_gizmo_set_matrix_rotation_from_z_axis__internal(gz->matrix_offset, z_axis);
}
void WM_gizmo_set_matrix_offset_rotation_from_yz_axis(wmGizmo *gz,
const float y_axis[3],
const float z_axis[3])
{
wm_gizmo_set_matrix_rotation_from_yz_axis__internal(gz->matrix_offset, y_axis, z_axis);
}
void WM_gizmo_set_matrix_offset_location(wmGizmo *gz, const float offset[3])
{
copy_v3_v3(gz->matrix_offset[3], offset);
}
void WM_gizmo_set_flag(wmGizmo *gz, const int flag, const bool enable)
{
if (enable) {
gz->flag |= eWM_GizmoFlag(flag);
}
else {
gz->flag &= ~eWM_GizmoFlag(flag);
}
}
void WM_gizmo_set_scale(wmGizmo *gz, const float scale)
{
gz->scale_basis = scale;
}
void WM_gizmo_set_line_width(wmGizmo *gz, const float line_width)
{
gz->line_width = line_width;
}
void WM_gizmo_get_color(const wmGizmo *gz, float color[4])
{
copy_v4_v4(color, gz->color);
}
void WM_gizmo_set_color(wmGizmo *gz, const float color[4])
{
copy_v4_v4(gz->color, color);
}
void WM_gizmo_get_color_highlight(const wmGizmo *gz, float color_hi[4])
{
copy_v4_v4(color_hi, gz->color_hi);
}
void WM_gizmo_set_color_highlight(wmGizmo *gz, const float color_hi[4])
{
copy_v4_v4(gz->color_hi, color_hi);
}
/** \} */ /* Gizmo Creation API. */
/* -------------------------------------------------------------------- */
/** \name Gizmo Callback Assignment
* \{ */
void WM_gizmo_set_fn_custom_modal(wmGizmo *gz, wmGizmoFnModal fn)
{
gz->custom_modal = fn;
}
/** \} */
/* -------------------------------------------------------------------- */
bool wm_gizmo_select_set_ex(
wmGizmoMap *gzmap, wmGizmo *gz, bool select, bool use_array, bool use_callback)
{
bool changed = false;
if (select) {
if ((gz->state & WM_GIZMO_STATE_SELECT) == 0) {
if (use_array) {
wm_gizmomap_select_array_push_back(gzmap, gz);
}
gz->state |= WM_GIZMO_STATE_SELECT;
changed = true;
}
}
else {
if (gz->state & WM_GIZMO_STATE_SELECT) {
if (use_array) {
wm_gizmomap_select_array_remove(gzmap, gz);
}
gz->state &= ~WM_GIZMO_STATE_SELECT;
changed = true;
}
}
/* In the case of unlinking we only want to remove from the array
* and not write to the external state. */
if (use_callback && changed) {
if (gz->type->select_refresh) {
gz->type->select_refresh(gz);
}
}
return changed;
}
bool WM_gizmo_select_unlink(wmGizmoMap *gzmap, wmGizmo *gz)
{
return wm_gizmo_select_set_ex(gzmap, gz, false, true, false);
}
bool WM_gizmo_select_set(wmGizmoMap *gzmap, wmGizmo *gz, bool select)
{
return wm_gizmo_select_set_ex(gzmap, gz, select, true, true);
}
bool WM_gizmo_highlight_set(wmGizmoMap *gzmap, wmGizmo *gz)
{
return wm_gizmomap_highlight_set(gzmap, nullptr, gz, gz ? gz->highlight_part : 0);
}
bool wm_gizmo_select_and_highlight(bContext *C, wmGizmoMap *gzmap, wmGizmo *gz)
{
if (WM_gizmo_select_set(gzmap, gz, true)) {
wm_gizmomap_highlight_set(gzmap, C, gz, gz->highlight_part);
return true;
}
return false;
}
void WM_gizmo_modal_set_from_setup(
wmGizmoMap *gzmap, bContext *C, wmGizmo *gz, int part_index, const wmEvent *event)
{
gz->highlight_part = part_index;
WM_gizmo_highlight_set(gzmap, gz);
if (false) {
wm_gizmomap_modal_set(gzmap, C, gz, event, true);
}
else {
/* WEAK: but it works. */
WM_operator_name_call(
C, "GIZMOGROUP_OT_gizmo_tweak", wm::OpCallContext::InvokeDefault, nullptr, event);
}
}
void WM_gizmo_modal_set_while_modal(wmGizmoMap *gzmap,
bContext *C,
wmGizmo *gz,
const wmEvent *event)
{
if (gzmap->gzmap_context.modal) {
wm_gizmomap_modal_set(gzmap, C, gzmap->gzmap_context.modal, event, false);
}
if (gz) {
wm_gizmo_calculate_scale(gz, C);
/* Set `highlight_part` to -1 to skip operator invocation. */
const int highlight_part = gz->highlight_part;
gz->highlight_part = -1;
wm_gizmomap_modal_set(gzmap, C, gz, event, true);
gz->highlight_part = highlight_part;
}
}
void wm_gizmo_calculate_scale(wmGizmo *gz, const bContext *C)
{
const RegionView3D *rv3d = CTX_wm_region_view3d(C);
float scale = UI_SCALE_FAC;
if ((gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_SCALE) == 0) {
scale *= U.gizmo_size;
if (rv3d) {
/* #ED_view3d_pixel_size includes #U.pixelsize, remove it. */
float matrix_world[4][4];
if (gz->type->matrix_basis_get) {
float matrix_basis[4][4];
gz->type->matrix_basis_get(gz, matrix_basis);
mul_m4_m4m4(matrix_world, gz->matrix_space, matrix_basis);
}
else {
mul_m4_m4m4(matrix_world, gz->matrix_space, gz->matrix_basis);
}
/* Exclude matrix_offset from scale. */
scale *= ED_view3d_pixel_size_no_ui_scale(rv3d, matrix_world[3]);
}
}
gz->scale_final = gz->scale_basis * scale;
}
static void gizmo_update_prop_data(wmGizmo *gz)
{
/* Gizmo property might have been changed, so update gizmo. */
if (gz->type->property_update) {
for (wmGizmoProperty &gz_prop : gz->target_properties) {
if (WM_gizmo_target_property_is_valid(&gz_prop)) {
gz->type->property_update(gz, &gz_prop);
}
}
}
}
void wm_gizmo_update(wmGizmo *gz, const bContext *C, const bool refresh_map)
{
if (refresh_map) {
gizmo_update_prop_data(gz);
}
wm_gizmo_calculate_scale(gz, C);
}
int wm_gizmo_is_visible(wmGizmo *gz)
{
if (gz->flag & WM_GIZMO_HIDDEN) {
return 0;
}
if ((gz->state & WM_GIZMO_STATE_MODAL) &&
!(gz->flag & (WM_GIZMO_DRAW_MODAL | WM_GIZMO_DRAW_VALUE)))
{
/* Don't draw while modal (dragging). */
return 0;
}
if ((gz->flag & WM_GIZMO_DRAW_HOVER) && !(gz->state & WM_GIZMO_STATE_HIGHLIGHT) &&
!(gz->state & WM_GIZMO_STATE_SELECT)) /* Still draw selected gizmos. */
{
/* Update but don't draw. */
return WM_GIZMO_IS_VISIBLE_UPDATE;
}
return WM_GIZMO_IS_VISIBLE_UPDATE | WM_GIZMO_IS_VISIBLE_DRAW;
}
void WM_gizmo_calc_matrix_final_params(const wmGizmo *gz,
const wmGizmoMatrixParams *params,
float r_mat[4][4])
{
const float (*const matrix_space)[4] = params->matrix_space ? params->matrix_space :
gz->matrix_space;
const float (*const matrix_basis)[4] = params->matrix_basis ? params->matrix_basis :
gz->matrix_basis;
const float (*const matrix_offset)[4] = params->matrix_offset ? params->matrix_offset :
gz->matrix_offset;
const float *scale_final = params->scale_final ? params->scale_final : &gz->scale_final;
float final_matrix[4][4];
if (params->matrix_basis == nullptr && gz->type->matrix_basis_get) {
gz->type->matrix_basis_get(gz, final_matrix);
}
else {
copy_m4_m4(final_matrix, matrix_basis);
}
if (gz->flag & WM_GIZMO_DRAW_NO_SCALE) {
mul_m4_m4m4(final_matrix, final_matrix, matrix_offset);
}
else {
if (gz->flag & WM_GIZMO_DRAW_OFFSET_SCALE) {
mul_mat3_m4_fl(final_matrix, *scale_final);
mul_m4_m4m4(final_matrix, final_matrix, matrix_offset);
}
else {
mul_m4_m4m4(final_matrix, final_matrix, matrix_offset);
mul_mat3_m4_fl(final_matrix, *scale_final);
}
}
mul_m4_m4m4(r_mat, matrix_space, final_matrix);
}
void WM_gizmo_calc_matrix_final_no_offset(const wmGizmo *gz, float r_mat[4][4])
{
float mat_identity[4][4];
unit_m4(mat_identity);
wmGizmoMatrixParams params{};
params.matrix_space = nullptr;
params.matrix_basis = nullptr;
params.matrix_offset = mat_identity;
params.scale_final = nullptr;
WM_gizmo_calc_matrix_final_params(gz, &params, r_mat);
}
void WM_gizmo_calc_matrix_final(const wmGizmo *gz, float r_mat[4][4])
{
wmGizmoMatrixParams params{};
params.matrix_space = nullptr;
params.matrix_basis = nullptr;
params.matrix_offset = nullptr;
params.scale_final = nullptr;
WM_gizmo_calc_matrix_final_params(gz, &params, r_mat);
}
/* -------------------------------------------------------------------- */
/** \name Gizmo Property Access
*
* Matches `WM_operator_properties` conventions.
*
* \{ */
void WM_gizmo_properties_create_ptr(PointerRNA *ptr, wmGizmoType *gzt)
{
*ptr = RNA_pointer_create_discrete(nullptr, gzt->srna, nullptr);
}
void WM_gizmo_properties_create(PointerRNA *ptr, const StringRef gtstring)
{
const wmGizmoType *gzt = WM_gizmotype_find(gtstring, false);
if (gzt) {
WM_gizmo_properties_create_ptr(ptr, const_cast<wmGizmoType *>(gzt));
}
else {
*ptr = RNA_pointer_create_discrete(nullptr, RNA_GizmoProperties, nullptr);
}
}
void WM_gizmo_properties_alloc(PointerRNA **ptr, IDProperty **properties, const StringRef gtstring)
{
if (*properties == nullptr) {
*properties = bke::idprop::create_group("wmOpItemProp").release();
}
if (*ptr == nullptr) {
*ptr = MEM_new<PointerRNA>("wmOpItemPtr");
WM_gizmo_properties_create(*ptr, gtstring);
}
(*ptr)->data = *properties;
}
void WM_gizmo_properties_sanitize(PointerRNA *ptr, const bool no_context)
{
RNA_STRUCT_BEGIN (ptr, prop) {
switch (RNA_property_type(prop)) {
case PROP_ENUM:
if (no_context) {
RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
}
else {
RNA_def_property_clear_flag(prop, PROP_ENUM_NO_CONTEXT);
}
break;
case PROP_POINTER: {
StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
/* Recurse into gizmo properties. */
if (RNA_struct_is_a(ptype, RNA_GizmoProperties)) {
PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
WM_gizmo_properties_sanitize(&opptr, no_context);
}
break;
}
default:
break;
}
}
RNA_STRUCT_END;
}
bool WM_gizmo_properties_default(PointerRNA *ptr, const bool do_update)
{
bool changed = false;
RNA_STRUCT_BEGIN (ptr, prop) {
switch (RNA_property_type(prop)) {
case PROP_POINTER: {
StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
if (ptype != RNA_Struct) {
PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
changed |= WM_gizmo_properties_default(&opptr, do_update);
}
break;
}
default:
if ((do_update == false) || (RNA_property_is_set(ptr, prop) == false)) {
if (RNA_property_reset(ptr, prop, -1)) {
changed = true;
}
}
break;
}
}
RNA_STRUCT_END;
return changed;
}
void WM_gizmo_properties_reset(wmGizmo *gz)
{
if (gz->ptr->data) {
PropertyRNA *iterprop;
iterprop = RNA_struct_iterator_property(gz->type->srna);
RNA_PROP_BEGIN (gz->ptr, itemptr, iterprop) {
PropertyRNA *prop = static_cast<PropertyRNA *>(itemptr.data);
if ((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) {
const char *identifier = RNA_property_identifier(prop);
RNA_struct_system_idprops_unset(gz->ptr, identifier);
}
}
RNA_PROP_END;
}
}
void WM_gizmo_properties_clear(PointerRNA *ptr)
{
IDProperty *properties = static_cast<IDProperty *>(ptr->data);
if (properties) {
IDP_ClearProperty(properties);
}
}
void WM_gizmo_properties_free(PointerRNA *ptr)
{
IDProperty *properties = static_cast<IDProperty *>(ptr->data);
if (properties) {
IDP_FreeProperty(properties);
ptr->data = nullptr; /* Just in case. */
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name General Utilities
* \{ */
bool WM_gizmo_group_is_modal(const wmGizmoGroup *gzgroup)
{
wmGizmo *gz = WM_gizmomap_get_modal(gzgroup->parent_gzmap);
if (gz && gz->parent_gzgroup == gzgroup) {
return true;
}
return false;
}
bool WM_gizmo_context_check_drawstep(const bContext *C, eWM_GizmoFlagMapDrawStep step)
{
switch (step) {
case WM_GIZMOMAP_DRAWSTEP_2D: {
break;
}
case WM_GIZMOMAP_DRAWSTEP_3D: {
wmWindowManager *wm = CTX_wm_manager(C);
if (ED_screen_animation_playing(wm)) {
return false;
}
break;
}
}
return true;
}
/** \} */
} // namespace blender

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,178 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup wm
*/
#include <cstdio>
#include "BLI_vector_set.hh"
#include "MEM_guardedalloc.h"
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "RNA_prototypes.hh"
#include "WM_types.hh"
/* Own includes. */
#include "wm_gizmo_intern.hh"
#include "wm_gizmo_wmapi.hh"
namespace blender {
/* -------------------------------------------------------------------- */
/** \name GizmoGroup Type Append
*
* \note This follows conventions from #WM_operatortype_find #WM_operatortype_append & friends.
* \{ */
static auto &get_gizmo_group_type_map()
{
struct IDNameGetter {
StringRef operator()(const wmGizmoGroupType *value) const
{
return StringRef(value->idname);
}
};
static CustomIDVectorSet<wmGizmoGroupType *, IDNameGetter> map;
return map;
}
wmGizmoGroupType *WM_gizmogrouptype_find(const StringRef idname, bool quiet)
{
if (!idname.is_empty()) {
if (wmGizmoGroupType *const *gzgt = get_gizmo_group_type_map().lookup_key_ptr_as(idname)) {
return *gzgt;
}
if (!quiet) {
printf("search for unknown gizmo group '%s'\n", std::string(idname).c_str());
}
}
else {
if (!quiet) {
printf("search for empty gizmo group\n");
}
}
return nullptr;
}
static wmGizmoGroupType *wm_gizmogrouptype_append__begin()
{
wmGizmoGroupType *gzgt = MEM_new_zeroed<wmGizmoGroupType>("gizmogrouptype");
gzgt->srna = RNA_def_struct_ptr(&RNA_blender_rna_get(), "", RNA_GizmoGroupProperties);
#if 0
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
#endif
return gzgt;
}
static void wm_gizmogrouptype_append__end(wmGizmoGroupType *gzgt)
{
BLI_assert(gzgt->name != nullptr);
BLI_assert(gzgt->idname != nullptr);
RNA_def_struct_identifier(&RNA_blender_rna_get(), gzgt->srna, gzgt->idname);
gzgt->type_update_flag |= WM_GIZMOMAPTYPE_KEYMAP_INIT;
/* If not set, use default. */
if (gzgt->setup_keymap == nullptr) {
if (gzgt->flag & WM_GIZMOGROUPTYPE_SELECT) {
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_select;
}
else {
gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic;
}
}
get_gizmo_group_type_map().add(gzgt);
}
wmGizmoGroupType *WM_gizmogrouptype_append(void (*wtfunc)(wmGizmoGroupType *))
{
wmGizmoGroupType *gzgt = wm_gizmogrouptype_append__begin();
wtfunc(gzgt);
wm_gizmogrouptype_append__end(gzgt);
return gzgt;
}
wmGizmoGroupType *WM_gizmogrouptype_append_ptr(void (*wtfunc)(wmGizmoGroupType *, void *),
void *userdata)
{
wmGizmoGroupType *gzgt = wm_gizmogrouptype_append__begin();
wtfunc(gzgt, userdata);
wm_gizmogrouptype_append__end(gzgt);
return gzgt;
}
wmGizmoGroupTypeRef *WM_gizmogrouptype_append_and_link(wmGizmoMapType *gzmap_type,
void (*wtfunc)(wmGizmoGroupType *))
{
wmGizmoGroupType *gzgt = WM_gizmogrouptype_append(wtfunc);
gzgt->gzmap_params.spaceid = gzmap_type->spaceid;
gzgt->gzmap_params.regionid = gzmap_type->regionid;
return WM_gizmomaptype_group_link_ptr(gzmap_type, gzgt);
}
/**
* Free but don't remove from the global list.
*/
static void gizmogrouptype_free(wmGizmoGroupType *gzgt)
{
/* Python gizmo group, allocates its own string. */
if (gzgt->rna_ext.srna) {
MEM_delete(gzgt->idname);
}
MEM_delete(gzgt);
}
void WM_gizmo_group_type_free_ptr(wmGizmoGroupType *gzgt)
{
BLI_assert(gzgt == WM_gizmogrouptype_find(gzgt->idname, false));
get_gizmo_group_type_map().remove(gzgt);
gizmogrouptype_free(gzgt);
/* XXX, TODO: update the world! */
}
bool WM_gizmo_group_type_free(const StringRef idname)
{
wmGizmoGroupType *const *gzgt = get_gizmo_group_type_map().lookup_key_ptr_as(idname);
if (gzgt == nullptr) {
return false;
}
WM_gizmo_group_type_free_ptr(*gzgt);
return true;
}
void wm_gizmogrouptype_free()
{
for (wmGizmoGroupType *gzgt : get_gizmo_group_type_map()) {
gizmogrouptype_free(gzgt);
}
get_gizmo_group_type_map().clear();
}
void wm_gizmogrouptype_init()
{
/* Reserve size is set based on blender default setup. */
get_gizmo_group_type_map().reserve(128);
}
/** \} */
} // namespace blender

View File

@@ -0,0 +1,164 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup wm
*/
#pragma once
#include "DNA_listBase.h"
#include "WM_gizmo_types.hh"
#include "BLI_vector.hh"
namespace blender {
struct wmGizmoMap;
struct wmGizmoGroupType;
struct wmGizmoMapType;
struct wmGizmoType;
struct wmKeyConfig;
struct wmWindowManager;
#include "wm_gizmo_fn.hh"
/* -------------------------------------------------------------------- */
/* #wmGizmo. */
/**
* Add/Remove \a gizmo to selection.
* Reallocates memory for selected gizmos so better not call for selecting multiple ones.
*
* \return if the selection has changed.
*/
bool wm_gizmo_select_set_ex(
wmGizmoMap *gzmap, wmGizmo *gz, bool select, bool use_array, bool use_callback);
bool wm_gizmo_select_and_highlight(bContext *C, wmGizmoMap *gzmap, wmGizmo *gz);
void wm_gizmo_calculate_scale(wmGizmo *gz, const bContext *C);
void wm_gizmo_update(wmGizmo *gz, const bContext *C, bool refresh_map);
int wm_gizmo_is_visible(wmGizmo *gz);
enum {
WM_GIZMO_IS_VISIBLE_UPDATE = (1 << 0),
WM_GIZMO_IS_VISIBLE_DRAW = (1 << 1),
};
/* -------------------------------------------------------------------- */
/* #wmGizmoGroup. */
enum {
TWEAK_MODAL_CANCEL = 1,
TWEAK_MODAL_CONFIRM,
TWEAK_MODAL_PRECISION_ON,
TWEAK_MODAL_PRECISION_OFF,
TWEAK_MODAL_SNAP_ON,
TWEAK_MODAL_SNAP_OFF,
};
/**
* Create a new gizmo-group from \a gzgt.
*/
wmGizmoGroup *wm_gizmogroup_new_from_type(wmGizmoMap *gzmap, wmGizmoGroupType *gzgt);
void wm_gizmogroup_free(bContext *C, wmGizmoGroup *gzgroup);
/**
* Add \a gizmo to \a gzgroup and make sure its name is unique within the group.
*/
void wm_gizmogroup_gizmo_register(wmGizmoGroup *gzgroup, wmGizmo *gz);
wmGizmoGroup *wm_gizmogroup_find_by_type(const wmGizmoMap *gzmap, const wmGizmoGroupType *gzgt);
wmGizmo *wm_gizmogroup_find_intersected_gizmo(wmWindowManager *wm,
const wmGizmoGroup *gzgroup,
bContext *C,
int event_modifier,
const int mval[2],
int *r_part);
/**
* Adds all gizmos of \a gzgroup that can be selected to the head of \a listbase.
* Added items need freeing!
*/
void wm_gizmogroup_intersectable_gizmos_to_list(wmWindowManager *wm,
wmGizmoGroup *gzgroup,
int event_modifier,
Vector<wmGizmo *, 128> *r_visible_gizmos);
bool wm_gizmogroup_is_visible_in_drawstep(const wmGizmoGroup *gzgroup,
eWM_GizmoFlagMapDrawStep drawstep);
void wm_gizmogrouptype_setup_keymap(wmGizmoGroupType *gzgt, wmKeyConfig *keyconf);
wmKeyMap *wm_gizmogroup_tweak_modal_keymap(wmKeyConfig *keyconf);
/* -------------------------------------------------------------------- */
/* #wmGizmoMap. */
struct wmGizmoMapSelectState {
struct wmGizmo **items;
int len, len_alloc;
};
struct wmGizmoMap {
wmGizmoMapType *type;
ListBaseT<wmGizmoGroup> groups;
/* Private, update tagging (enum defined in C source). */
char update_flag[WM_GIZMOMAP_DRAWSTEP_MAX];
/** Private, true when not yet used. */
bool is_init;
/** When set, one of the items in 'groups' has #wmGizmoGroup.tag_remove set. */
bool tag_remove_group;
/** When set, the event system re-calculates highlight even without cursor motion. */
bool tag_highlight_pending;
/**
* \brief Gizmo map runtime context
*
* Contains information about this gizmo-map. Currently
* highlighted gizmo, currently selected gizmos, ...
*/
struct {
/** We redraw the gizmo-map when this changes. */
wmGizmo *highlight;
/** User has clicked this gizmo and it gets all input. */
wmGizmo *modal;
/** Array for all selected gizmos. */
wmGizmoMapSelectState select;
/** Cursor location at point of entering modal (see: #WM_GIZMO_MOVE_CURSOR). */
int event_xy[2];
short event_grabcursor;
/** Until we have nice cursor push/pop API. */
int last_cursor;
} gzmap_context;
};
/**
* This is a container for all gizmo types that can be instantiated in a region.
* (similar to drop-boxes).
*
* \note There is only ever one of these for every (area, region) combination.
*/
struct wmGizmoMapType {
wmGizmoMapType *next, *prev;
short spaceid, regionid;
/* Types of gizmo-groups for this gizmo-map type. */
ListBaseT<wmGizmoGroupTypeRef> grouptype_refs;
/* #eGizmoMapTypeUpdateFlags. */
eWM_GizmoFlagMapTypeUpdateFlag type_update_flag;
};
void wm_gizmomap_select_array_clear(wmGizmoMap *gzmap);
/**
* Deselect all selected gizmos in \a gzmap.
* \return if selection has changed.
*/
bool wm_gizmomap_deselect_all(wmGizmoMap *gzmap);
void wm_gizmomap_select_array_shrink(wmGizmoMap *gzmap, int len_subtract);
void wm_gizmomap_select_array_push_back(wmGizmoMap *gzmap, wmGizmo *gz);
void wm_gizmomap_select_array_remove(wmGizmoMap *gzmap, wmGizmo *gz);
} // namespace blender

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,332 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup wm
*/
#include "BLI_listbase.h"
#include "BKE_context.hh"
#include "MEM_guardedalloc.h"
#include "RNA_access.hh"
#include "WM_message.hh"
#include "WM_types.hh"
#include "ED_keyframes_edit.hh"
#include "ED_screen.hh"
#include "ANIM_keyframing.hh"
namespace blender {
/* Own includes. */
/* -------------------------------------------------------------------- */
/** \name Property Definition
* \{ */
wmGizmoProperty *WM_gizmo_target_property_find(wmGizmo *gz, const char *idname)
{
int index = BLI_findstringindex(
&gz->type->target_property_defs, idname, offsetof(wmGizmoPropertyType, idname));
if (index != -1) {
return &gz->target_properties[index];
}
return nullptr;
}
void WM_gizmo_target_property_def_rna_ptr(wmGizmo *gz,
const wmGizmoPropertyType *gz_prop_type,
PointerRNA *ptr,
PropertyRNA *prop,
int index)
{
wmGizmoProperty *gz_prop = &gz->target_properties[gz_prop_type->index_in_type];
/* If gizmo evokes an operator we cannot use it for property manipulation. */
BLI_assert(gz->op_data.is_empty());
BLI_assert(prop != nullptr);
gz_prop->type = gz_prop_type;
gz_prop->ptr = *ptr;
gz_prop->prop = prop;
gz_prop->index = index;
if (gz->type->property_update) {
gz->type->property_update(gz, gz_prop);
}
}
void WM_gizmo_target_property_def_rna(
wmGizmo *gz, const char *idname, PointerRNA *ptr, const char *propname, int index)
{
const wmGizmoPropertyType *gz_prop_type = WM_gizmotype_target_property_find(gz->type, idname);
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
if (prop == nullptr) {
RNA_warning("%s: %s.%s not found", __func__, RNA_struct_identifier(ptr->type), propname);
}
WM_gizmo_target_property_def_rna_ptr(gz, gz_prop_type, ptr, prop, index);
}
void WM_gizmo_target_property_def_func_ptr(wmGizmo *gz,
const wmGizmoPropertyType *gz_prop_type,
const wmGizmoPropertyFnParams *params)
{
wmGizmoProperty *gz_prop = &gz->target_properties[gz_prop_type->index_in_type];
/* If gizmo evokes an operator we cannot use it for property manipulation. */
BLI_assert(gz->op_data.is_empty());
gz_prop->type = gz_prop_type;
gz_prop->custom_func.value_get_fn = params->value_get_fn;
gz_prop->custom_func.value_set_fn = params->value_set_fn;
gz_prop->custom_func.range_get_fn = params->range_get_fn;
gz_prop->custom_func.free_fn = params->free_fn;
gz_prop->custom_func.foreach_rna_prop_fn = params->foreach_rna_prop_fn;
gz_prop->custom_func.user_data = params->user_data;
if (gz->type->property_update) {
gz->type->property_update(gz, gz_prop);
}
}
void WM_gizmo_target_property_def_func(wmGizmo *gz,
const char *idname,
const wmGizmoPropertyFnParams *params)
{
const wmGizmoPropertyType *gz_prop_type = WM_gizmotype_target_property_find(gz->type, idname);
WM_gizmo_target_property_def_func_ptr(gz, gz_prop_type, params);
}
void WM_gizmo_target_property_clear_rna_ptr(wmGizmo *gz, const wmGizmoPropertyType *gz_prop_type)
{
wmGizmoProperty *gz_prop = &gz->target_properties[gz_prop_type->index_in_type];
/* If gizmo evokes an operator we cannot use it for property manipulation. */
BLI_assert(gz->op_data.is_empty());
*gz_prop = {};
}
void WM_gizmo_target_property_clear_rna(wmGizmo *gz, const char *idname)
{
const wmGizmoPropertyType *gz_prop_type = WM_gizmotype_target_property_find(gz->type, idname);
WM_gizmo_target_property_clear_rna_ptr(gz, gz_prop_type);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Property Access
* \{ */
bool WM_gizmo_target_property_is_valid_any(const wmGizmo *gz)
{
for (const wmGizmoProperty &gz_prop : gz->target_properties) {
if (WM_gizmo_target_property_is_valid(&gz_prop)) {
return true;
}
}
return false;
}
bool WM_gizmo_target_property_is_valid(const wmGizmoProperty *gz_prop)
{
return ((gz_prop->prop != nullptr) ||
(gz_prop->custom_func.value_get_fn && gz_prop->custom_func.value_set_fn));
}
float WM_gizmo_target_property_float_get(const wmGizmo *gz, wmGizmoProperty *gz_prop)
{
if (gz_prop->custom_func.value_get_fn) {
float value = 0.0f;
BLI_assert(gz_prop->type->array_length == 1);
gz_prop->custom_func.value_get_fn(gz, gz_prop, &value);
return value;
}
if (gz_prop->index == -1) {
return RNA_property_float_get(&gz_prop->ptr, gz_prop->prop);
}
return RNA_property_float_get_index(&gz_prop->ptr, gz_prop->prop, gz_prop->index);
}
void WM_gizmo_target_property_float_set(bContext *C,
const wmGizmo *gz,
wmGizmoProperty *gz_prop,
const float value)
{
if (gz_prop->custom_func.value_set_fn) {
BLI_assert(gz_prop->type->array_length == 1);
gz_prop->custom_func.value_set_fn(gz, gz_prop, &value);
return;
}
/* Reset property. */
if (gz_prop->index == -1) {
RNA_property_float_set(&gz_prop->ptr, gz_prop->prop, value);
}
else {
RNA_property_float_set_index(&gz_prop->ptr, gz_prop->prop, gz_prop->index, value);
}
RNA_property_update(C, &gz_prop->ptr, gz_prop->prop);
}
void WM_gizmo_target_property_float_get_array(const wmGizmo *gz,
wmGizmoProperty *gz_prop,
float *value)
{
if (gz_prop->custom_func.value_get_fn) {
gz_prop->custom_func.value_get_fn(gz, gz_prop, value);
return;
}
RNA_property_float_get_array(&gz_prop->ptr, gz_prop->prop, value);
}
void WM_gizmo_target_property_float_set_array(bContext *C,
const wmGizmo *gz,
wmGizmoProperty *gz_prop,
const float *value)
{
if (gz_prop->custom_func.value_set_fn) {
gz_prop->custom_func.value_set_fn(gz, gz_prop, value);
return;
}
RNA_property_float_set_array(&gz_prop->ptr, gz_prop->prop, value);
RNA_property_update(C, &gz_prop->ptr, gz_prop->prop);
}
bool WM_gizmo_target_property_float_range_get(const wmGizmo *gz,
wmGizmoProperty *gz_prop,
float range[2])
{
if (gz_prop->custom_func.value_get_fn) {
if (gz_prop->custom_func.range_get_fn) {
gz_prop->custom_func.range_get_fn(gz, gz_prop, range);
return true;
}
return false;
}
float step, precision;
RNA_property_float_ui_range(
&gz_prop->ptr, gz_prop->prop, &range[0], &range[1], &step, &precision);
return true;
}
int WM_gizmo_target_property_array_length(const wmGizmo * /*gz*/, wmGizmoProperty *gz_prop)
{
if (gz_prop->custom_func.value_get_fn) {
return gz_prop->type->array_length;
}
return RNA_property_array_length(&gz_prop->ptr, gz_prop->prop);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Property Define
* \{ */
const wmGizmoPropertyType *WM_gizmotype_target_property_find(const wmGizmoType *gzt,
const char *idname)
{
return static_cast<const wmGizmoPropertyType *>(
BLI_findstring(&gzt->target_property_defs, idname, offsetof(wmGizmoPropertyType, idname)));
}
void WM_gizmotype_target_property_def(wmGizmoType *gzt,
const char *idname,
int data_type,
int array_length)
{
BLI_assert(WM_gizmotype_target_property_find(gzt, idname) == nullptr);
const uint idname_size = strlen(idname) + 1;
wmGizmoPropertyType *gz_prop_type = static_cast<wmGizmoPropertyType *>(
MEM_new_zeroed(sizeof(wmGizmoPropertyType) + idname_size, __func__));
memcpy(gz_prop_type->idname, idname, idname_size);
gz_prop_type->data_type = data_type;
gz_prop_type->array_length = array_length;
gz_prop_type->index_in_type = gzt->target_property_defs_len;
gzt->target_property_defs_len += 1;
BLI_addtail(&gzt->target_property_defs, gz_prop_type);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Property Utilities
* \{ */
void WM_gizmo_do_msg_notify_tag_refresh(bContext * /*C*/,
wmMsgSubscribeKey * /*msg_key*/,
wmMsgSubscribeValue *msg_val)
{
ARegion *region = static_cast<ARegion *>(msg_val->owner);
wmGizmoMap *gzmap = static_cast<wmGizmoMap *>(msg_val->user_data);
/* Could possibly avoid a full redraw and only tag for editor overlays
* redraw in some cases, see #ED_region_tag_redraw_editor_overlays(). */
ED_region_tag_redraw(region);
WM_gizmomap_tag_refresh(gzmap);
}
void WM_gizmo_target_property_subscribe_all(wmGizmo *gz, wmMsgBus *mbus, ARegion *region)
{
for (wmGizmoProperty &gz_prop : gz->target_properties) {
if (WM_gizmo_target_property_is_valid(&gz_prop)) {
if (gz_prop.prop) {
{
wmMsgSubscribeValue value{};
value.owner = region;
value.user_data = region;
value.notify = ED_region_do_msg_notify_tag_redraw;
WM_msg_subscribe_rna(mbus, &gz_prop.ptr, gz_prop.prop, &value, __func__);
}
{
wmMsgSubscribeValue value{};
value.owner = region;
value.user_data = gz->parent_gzgroup->parent_gzmap;
value.notify = WM_gizmo_do_msg_notify_tag_refresh;
WM_msg_subscribe_rna(mbus, &gz_prop.ptr, gz_prop.prop, &value, __func__);
}
}
}
}
}
void WM_gizmo_target_property_anim_autokey(bContext *C,
const wmGizmo * /*gz*/,
wmGizmoProperty *gz_prop)
{
if (gz_prop->prop != nullptr) {
Scene *scene = CTX_data_scene(C);
const float cfra = float(scene->r.cfra);
ANIM_deselect_keys_in_animation_editors(C);
animrig::autokeyframe_property(
C, scene, &gz_prop->ptr, gz_prop->prop, gz_prop->index, cfra, false);
}
else if (gz_prop->custom_func.foreach_rna_prop_fn) {
Scene *scene = CTX_data_scene(C);
auto autokey_fn = [C, scene](PointerRNA &ptr, PropertyRNA *prop, int index) {
animrig::autokeyframe_property(C, scene, &ptr, prop, index, float(scene->r.cfra), false);
};
ANIM_deselect_keys_in_animation_editors(C);
gz_prop->custom_func.foreach_rna_prop_fn(gz_prop, autokey_fn);
}
}
/** \} */
} // namespace blender

View File

@@ -0,0 +1,190 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup wm
*/
#include <cstdio>
#include "BLI_listbase.h"
#include "BLI_vector_set.hh"
#include "BKE_main.hh"
#include "BKE_screen.hh"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "MEM_guardedalloc.h"
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "RNA_prototypes.hh"
#include "WM_types.hh"
#include "ED_screen.hh"
/* Own includes. */
#include "wm_gizmo_intern.hh"
#include "wm_gizmo_wmapi.hh"
namespace blender {
/* -------------------------------------------------------------------- */
/** \name Gizmo Type Append
*
* \note This follows conventions from #WM_operatortype_find #WM_operatortype_append & friends.
* \{ */
static auto &get_gizmo_type_map()
{
struct IDNameGetter {
StringRef operator()(const wmGizmoType *value) const
{
return StringRef(value->idname);
}
};
static CustomIDVectorSet<wmGizmoType *, IDNameGetter> map;
return map;
}
const wmGizmoType *WM_gizmotype_find(const StringRef idname, bool quiet)
{
if (!idname.is_empty()) {
if (wmGizmoType *const *gzt = get_gizmo_type_map().lookup_key_ptr_as(idname)) {
return *gzt;
}
if (!quiet) {
printf("search for unknown gizmo '%s'\n", std::string(idname).c_str());
}
}
else {
if (!quiet) {
printf("search for empty gizmo\n");
}
}
return nullptr;
}
static wmGizmoType *wm_gizmotype_append__begin()
{
wmGizmoType *gzt = MEM_new_zeroed<wmGizmoType>("gizmotype");
gzt->srna = RNA_def_struct_ptr(&RNA_blender_rna_get(), "", RNA_GizmoProperties);
#if 0
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
#endif
return gzt;
}
static void wm_gizmotype_append__end(wmGizmoType *gzt)
{
BLI_assert(gzt->struct_size >= sizeof(wmGizmo));
RNA_def_struct_identifier(&RNA_blender_rna_get(), gzt->srna, gzt->idname);
get_gizmo_type_map().add(gzt);
}
void WM_gizmotype_append(void (*gtfunc)(wmGizmoType *))
{
wmGizmoType *gzt = wm_gizmotype_append__begin();
gtfunc(gzt);
wm_gizmotype_append__end(gzt);
}
void WM_gizmotype_append_ptr(void (*gtfunc)(wmGizmoType *, void *), void *userdata)
{
wmGizmoType *mt = wm_gizmotype_append__begin();
gtfunc(mt, userdata);
wm_gizmotype_append__end(mt);
}
void WM_gizmotype_free_ptr(wmGizmoType *gzt)
{
/* Python gizmo, allocates its own string. */
if (gzt->rna_ext.srna) {
MEM_delete(gzt->idname);
}
gzt->target_property_defs.free_no_destruct();
MEM_delete(gzt);
}
/**
* \param C: May be nullptr.
*/
static void gizmotype_unlink(bContext *C, Main *bmain, wmGizmoType *gzt)
{
/* Free instances. */
for (bScreen *screen = static_cast<bScreen *>(bmain->screens.first); screen;
screen = static_cast<bScreen *>(screen->id.next))
{
for (ScrArea &area : screen->areabase) {
for (SpaceLink &sl : area.spacedata) {
ListBaseT<ARegion> *lb = (&sl == area.spacedata.first) ? &area.regionbase : &sl.regionbase;
for (ARegion &region : *lb) {
wmGizmoMap *gzmap = region.runtime->gizmo_map;
if (gzmap) {
for (wmGizmoGroup &gzgroup : gzmap->groups) {
for (wmGizmo *gz = static_cast<wmGizmo *>(gzgroup.gizmos.first), *gz_next; gz;
gz = gz_next)
{
gz_next = gz->next;
BLI_assert(gzgroup.parent_gzmap == gzmap);
if (gz->type == gzt) {
WM_gizmo_unlink(&gzgroup.gizmos, gzgroup.parent_gzmap, gz, C);
ED_region_tag_redraw_editor_overlays(&region);
}
}
}
}
}
}
}
}
}
void WM_gizmotype_remove_ptr(bContext *C, Main *bmain, wmGizmoType *gzt)
{
BLI_assert(gzt == WM_gizmotype_find(gzt->idname, false));
get_gizmo_type_map().remove(gzt);
gizmotype_unlink(C, bmain, gzt);
}
bool WM_gizmotype_remove(bContext *C, Main *bmain, const StringRef idname)
{
wmGizmoType *const *gzt = get_gizmo_type_map().lookup_key_ptr_as(idname);
if (gzt == nullptr) {
return false;
}
WM_gizmotype_remove_ptr(C, bmain, *gzt);
return true;
}
void wm_gizmotype_free()
{
for (wmGizmoType *gzt : get_gizmo_type_map()) {
WM_gizmotype_free_ptr(gzt);
}
get_gizmo_type_map().clear();
}
void wm_gizmotype_init()
{
/* Reserve size is set based on blender default setup. */
get_gizmo_type_map().reserve(128);
}
/** \} */
} // namespace blender