Mesh: Replace auto smooth with node group #108014

Merged
Hans Goudey merged 149 commits from HooglyBoogly/blender:refactor-mesh-corner-normals-lazy into main 2023-10-20 16:54:20 +02:00
63 changed files with 550 additions and 272 deletions
Showing only changes of commit 8d6a65df15 - Show all commits

View File

@ -514,7 +514,7 @@ check_spelling_shaders: .FORCE
PYTHONIOENCODING=utf_8 $(PYTHON) \
"$(BLENDER_DIR)/tools/check_source/check_spelling.py" \
--cache-file=$(CHECK_SPELLING_CACHE) \
--match=".*\.(osl|msl|glsl)$$" \
--match=".*\.(osl|metal|msl|glsl)$$" \
"$(BLENDER_DIR)/intern/" \
"$(BLENDER_DIR)/source/"

View File

@ -12,6 +12,9 @@ if(DEFINED HIP_ROOT_DIR AND HIP_ROOT_DIR)
# Pass.
elseif(DEFINED ENV{HIP_ROOT_DIR})
set(HIP_ROOT_DIR $ENV{HIP_ROOT_DIR})
elseif(DEFINED ENV{HIP_PATH})
# Built-in environment variable from SDK.
set(HIP_ROOT_DIR $ENV{HIP_PATH})
else()
set(HIP_ROOT_DIR "")
endif()

View File

@ -12,6 +12,9 @@ if(DEFINED HIPRT_ROOT_DIR AND HIPRT_ROOT_DIR)
# Pass.
elseif(DEFINED ENV{HIPRT_ROOT_DIR})
set(HIPRT_ROOT_DIR $ENV{HIPRT_ROOT_DIR})
elseif(DEFINED ENV{HIP_PATH})
# Built-in environment variable from SDK.
set(HIPRT_ROOT_DIR $ENV{HIP_PATH})
else()
set(HIPRT_ROOT_DIR "")
endif()
@ -24,6 +27,7 @@ find_path(HIPRT_INCLUDE_DIR
NAMES
hiprt/hiprt.h
HINTS
${_hiprt_SEARCH_DIRS}/include
${_hiprt_SEARCH_DIRS}
)
@ -36,6 +40,7 @@ if(HIPRT_INCLUDE_DIR)
NAMES
hiprt${_hiprt_version}_amd_lib_win.bc
HINTS
${HIPRT_ROOT_DIR}/bin
${HIPRT_ROOT_DIR}/dist/bin/Release
NO_DEFAULT_PATH
)

View File

@ -2126,6 +2126,10 @@ def km_node_editor(params):
# Allow node selection with both for RMB select.
if params.select_mouse == 'RIGHTMOUSE':
items.extend(_template_node_select(type='LEFTMOUSE', value='PRESS', select_passthrough=True))
else:
items.extend([
op_tool_cycle("builtin.select_box", {"type": 'W', "value": 'PRESS'}),
])
else:
items.extend(_template_node_select(
type='RIGHTMOUSE', value=params.select_mouse_value, select_passthrough=True))

View File

@ -35,6 +35,29 @@ def geometry_node_group_empty_new():
return group
def geometry_node_group_empty_tool_new(context):
group = build_default_empty_geometry_node_group(data_("Tool"))
group.links.new(group.nodes[data_("Group Input")].outputs[0], group.nodes[data_("Group Output")].inputs[0])
group.asset_mark()
group.is_tool = True
ob_type = context.object.type if context.object else 'MESH'
if ob_type == 'CURVES':
group.is_type_curve = True
elif ob_type == 'POINTCLOUD':
group.is_type_point_cloud = True
else:
group.is_type_mesh = True
mode = context.object.mode if context.object else 'EDIT'
if mode in {'SCULPT', 'SCULPT_CURVES'}:
group.is_mode_sculpt = True
else:
group.is_mode_edit = True
return group
def geometry_modifier_poll(context):
ob = context.object
@ -276,9 +299,7 @@ class NewGeometryNodeGroupTool(Operator):
return space and space.type == 'NODE_EDITOR' and space.geometry_nodes_type == 'TOOL'
def execute(self, context):
group = geometry_node_group_empty_new()
group.asset_mark()
group.is_tool = True
group = geometry_node_group_empty_tool_new(context)
context.space_data.node_tree = group
return {'FINISHED'}

View File

@ -96,16 +96,10 @@ class DATA_UL_bone_collections(UIList):
class DATA_PT_bone_collections(ArmatureButtonsPanel, Panel):
bl_label = "Bone Collections"
@classmethod
def poll(cls, context):
ob = context.object
return (ob and ob.type == 'ARMATURE' and ob.pose)
def draw(self, context):
layout = self.layout
ob = context.object
arm = ob.data
arm = context.armature
active_bcoll = arm.collections.active
row = layout.row()
@ -243,6 +237,17 @@ class DATA_PT_custom_props_arm(ArmatureButtonsPanel, PropertyPanel, Panel):
_property_type = bpy.types.Armature
class DATA_PT_custom_props_bcoll(ArmatureButtonsPanel, PropertyPanel, Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
_context_path = "armature.collections.active"
_property_type = bpy.types.BoneCollection
bl_parent_id = "DATA_PT_bone_collections"
@classmethod
def poll(cls, context):
return context.armature and context.armature.collections.active
classes = (
DATA_PT_context_arm,
DATA_PT_skeleton,
@ -253,6 +258,7 @@ classes = (
DATA_PT_display,
DATA_PT_iksolver_itasc,
DATA_PT_custom_props_arm,
DATA_PT_custom_props_bcoll,
)
if __name__ == "__main__": # only for live edit.

View File

@ -29,6 +29,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
class OBJECT_MT_modifier_add(Menu):
bl_label = "Add Modifier"
bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, context):
layout = self.layout
@ -226,6 +227,7 @@ class AddModifierMenu(Operator):
@classmethod
def poll(cls, context):
# NOTE: This operator only exists to add a poll to the add modifier shortcut in the property editor.
space = context.space_data
return space and space.type == 'PROPERTIES' and space.context == "MODIFIER"

View File

@ -225,6 +225,7 @@ class NODE_MT_add(bpy.types.Menu):
bl_space_type = 'NODE_EDITOR'
bl_label = "Add"
bl_translation_context = i18n_contexts.operator_default
bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, context):
import nodeitems_utils
@ -234,27 +235,14 @@ class NODE_MT_add(bpy.types.Menu):
snode = context.space_data
if snode.tree_type == 'GeometryNodeTree':
props = layout.operator("node.add_search", text="Search...", icon='VIEWZOOM')
layout.separator()
layout.menu_contents("NODE_MT_geometry_node_add_all")
elif snode.tree_type == 'CompositorNodeTree':
props = layout.operator("node.add_search", text="Search...", icon='VIEWZOOM')
layout.separator()
layout.menu_contents("NODE_MT_compositor_node_add_all")
elif snode.tree_type == 'ShaderNodeTree':
props = layout.operator("node.add_search", text="Search...", icon='VIEWZOOM')
layout.separator()
layout.menu_contents("NODE_MT_shader_node_add_all")
elif snode.tree_type == 'TextureNodeTree':
props = layout.operator("node.add_search", text="Search...", icon='VIEWZOOM')
layout.separator()
layout.menu_contents("NODE_MT_texture_node_add_all")
elif nodeitems_utils.has_node_categories(context):
props = layout.operator("node.add_search", text="Search...", icon='VIEWZOOM')
props.use_transform = True
layout.separator()
# Actual node sub-menus are defined by draw functions from node categories.
nodeitems_utils.draw_node_categories_menu(self, context)

View File

@ -966,15 +966,9 @@ class SEQUENCER_MT_strip(Menu):
if has_sequencer:
if strip:
strip_type = strip.type
if strip_type != 'SOUND':
layout.separator()
layout.operator_menu_enum("sequencer.strip_video_modifier_add", "type", text="Add Modifier")
layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
else:
layout.separator()
layout.operator_menu_enum("sequencer.strip_sound_modifier_add", "type", text="Add Modifier")
layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
layout.separator()
layout.operator_menu_enum("sequencer.strip_modifier_add", "type", text="Add Modifier")
layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
if strip_type in {
'CROSS', 'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
@ -1112,18 +1106,16 @@ class SEQUENCER_MT_context_menu(Menu):
strip_type = strip.type
selected_sequences_count = selected_sequences_len(context)
layout.separator()
layout.operator_menu_enum("sequencer.strip_modifier_add", "type", text="Add Modifier")
layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
if strip_type != 'SOUND':
layout.separator()
layout.operator_menu_enum("sequencer.strip_video_modifier_add", "type", text="Add Modifier")
layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
if selected_sequences_count >= 2:
layout.separator()
col = layout.column()
col.menu("SEQUENCER_MT_add_transitions", text="Add Transition")
else:
layout.separator()
layout.operator_menu_enum("sequencer.strip_sound_modifier_add", "type", text="Add Modifier")
layout.operator("sequencer.strip_modifier_copy", text="Copy Modifiers to Selection")
if selected_sequences_count >= 2:
layout.separator()
layout.operator("sequencer.crossfade_sounds", text="Crossfade Sounds")

View File

@ -2448,6 +2448,7 @@ class VIEW3D_MT_grease_pencil_add(Menu):
class VIEW3D_MT_add(Menu):
bl_label = "Add"
bl_translation_context = i18n_contexts.operator_default
bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, context):
layout = self.layout

View File

@ -257,6 +257,15 @@ inline int2 face_find_adjecent_verts(const IndexRange face,
corner_verts[face_corner_next(face, corner)]};
}
/**
* Return the number of triangles needed to tessellate a face with \a face_size corners.
*/
inline int face_triangles_num(const int face_size)
{
BLI_assert(face_size > 2);
return face_size - 2;
}
/**
* Return the index of the edge's vertex that is not the \a vert.
* If neither edge vertex is equal to \a v, returns -1.

View File

@ -29,6 +29,9 @@ void BKE_previewimg_freefunc(void *link);
*/
void BKE_previewimg_free(PreviewImage **prv);
/** Must be called after reading a preview image from file. */
void BKE_previewimg_runtime_data_clear(PreviewImage *prv);
/**
* Clear the preview image or icon, but does not free it.
*/

View File

@ -405,6 +405,10 @@ enum class MenuTypeFlag {
* dependent, menu search has to scan it in different contexts.
*/
ContextDependent = (1 << 0),
/**
* Automatically start searching in the menu when pressing a key.
*/
SearchOnKeyPress = (1 << 1),
};
ENUM_OPERATORS(MenuTypeFlag, MenuTypeFlag::ContextDependent)

View File

@ -1104,7 +1104,7 @@ static BitVector<> looptri_no_hidden_map_get(const blender::OffsetIndices<int> f
int looptri_no_hidden_len = 0;
int looptri_index = 0;
for (const int64_t i : faces.index_range()) {
const int triangles_num = ME_FACE_TRI_TOT(faces[i].size());
const int triangles_num = blender::bke::mesh::face_triangles_num(faces[i].size());
if (hide_poly[i]) {
looptri_index += triangles_num;
}

View File

@ -273,6 +273,19 @@ static size_t id_delete(Main *bmain,
* code has some specific handling of 'no main' IDs that would be a problem in that
* case). */
id->tag |= tag;
/* Forcefully also delete shapekeys of the deleted ID if any, 'orphaned' shapekeys are
* not allowed in Blender and will cause lots of problem in modern code (liboverrides,
* warning on write & read, etc.). */
Key *shape_key = BKE_key_from_id(id);
if (shape_key && (shape_key->id.tag & tag) == 0) {
BLI_remlink(&bmain->shapekeys, &shape_key->id);
BKE_main_namemap_remove_name(bmain, &shape_key->id, shape_key->id.name + 2);
BLI_addtail(&tagged_deleted_ids, &shape_key->id);
BKE_id_remapper_add(id_remapper, &shape_key->id, nullptr);
shape_key->id.tag |= tag;
}
keep_looping = true;
}
}

View File

@ -80,6 +80,7 @@ static void library_blend_read_data(BlendDataReader * /*reader*/, ID *id)
lib->runtime.name_map = nullptr;
/* This is runtime data. */
lib->parent = nullptr;
lib->tag = 0;
}
IDTypeInfo IDType_ID_LI = {

View File

@ -286,7 +286,7 @@ void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
index_step = indices;
for (const int64_t i : faces.index_range()) {
map[i].indices = index_step;
index_step += ME_FACE_TRI_TOT(faces[i].size());
index_step += blender::bke::mesh::face_triangles_num(int(faces[i].size()));
}
/* Assign face-tessellation users. */

View File

@ -306,7 +306,7 @@ void looptris_calc_face_indices(const OffsetIndices<int> faces, MutableSpan<int>
for (const int64_t i : range) {
const IndexRange face = faces[i];
const int start = poly_to_tri_count(int(i), int(face.start()));
const int num = ME_FACE_TRI_TOT(int(face.size()));
const int num = face_triangles_num(int(face.size()));
looptri_faces.slice(start, num).fill(int(i));
}
});

View File

@ -369,9 +369,43 @@ static void socket_data_foreach_id(LibraryForeachIDData *data, bNodeTreeInterfac
namespace item_types {
using UidGeneratorFn = blender::FunctionRef<int()>;
static void item_copy(bNodeTreeInterfaceItem &dst,
const bNodeTreeInterfaceItem &src,
const int flag)
int flag,
UidGeneratorFn generate_uid);
/**
* Copy the source items and give each a new unique identifier.
* \param generate_uid: Optional generator function for new item UIDs, copies existing identifiers
* if null.
*/
static void panel_init(bNodeTreeInterfacePanel &panel,
const Span<const bNodeTreeInterfaceItem *> items_src,
const int flag,
UidGeneratorFn generate_uid)
{
panel.items_num = items_src.size();
panel.items_array = MEM_cnew_array<bNodeTreeInterfaceItem *>(panel.items_num, __func__);
/* Copy buffers. */
for (const int i : items_src.index_range()) {
const bNodeTreeInterfaceItem *item_src = items_src[i];
panel.items_array[i] = static_cast<bNodeTreeInterfaceItem *>(MEM_dupallocN(item_src));
item_types::item_copy(*panel.items_array[i], *item_src, flag, generate_uid);
}
}
/**
* Copy data from a source item.
* \param generate_uid: Optional generator function for new item UIDs, copies existing identifiers
* if null.
*/
static void item_copy(bNodeTreeInterfaceItem &dst,
const bNodeTreeInterfaceItem &src,
const int flag,
UidGeneratorFn generate_uid)
{
switch (dst.item_type) {
case NODE_INTERFACE_SOCKET: {
@ -385,7 +419,8 @@ static void item_copy(bNodeTreeInterfaceItem &dst,
dst_socket.description = BLI_strdup_null(src_socket.description);
dst_socket.socket_type = BLI_strdup(src_socket.socket_type);
dst_socket.default_attribute_name = BLI_strdup_null(src_socket.default_attribute_name);
dst_socket.identifier = BLI_strdup(src_socket.identifier);
dst_socket.identifier = generate_uid ? BLI_sprintfN("Socket_%d", generate_uid()) :
BLI_strdup(src_socket.identifier);
if (src_socket.properties) {
dst_socket.properties = IDP_CopyProperty_ex(src_socket.properties, flag);
}
@ -402,24 +437,9 @@ static void item_copy(bNodeTreeInterfaceItem &dst,
dst_panel.name = BLI_strdup(src_panel.name);
dst_panel.description = BLI_strdup_null(src_panel.description);
dst_panel.copy_from(src_panel.items(), flag);
break;
}
}
}
dst_panel.identifier = generate_uid ? generate_uid() : src_panel.identifier;
static void item_set_unique_identifier(const int uid, bNodeTreeInterfaceItem &item)
{
switch (item.item_type) {
case NODE_INTERFACE_SOCKET: {
bNodeTreeInterfaceSocket &socket = reinterpret_cast<bNodeTreeInterfaceSocket &>(item);
MEM_SAFE_FREE(socket.identifier);
socket.identifier = BLI_sprintfN("Socket_%d", uid);
break;
}
case NODE_INTERFACE_PANEL: {
bNodeTreeInterfacePanel &panel = reinterpret_cast<bNodeTreeInterfacePanel &>(item);
panel.identifier = uid;
panel_init(dst_panel, src_panel.items(), flag, generate_uid);
break;
}
}
@ -999,20 +1019,6 @@ static bNodeTreeInterfacePanel *make_panel(const int uid,
return new_panel;
}
void bNodeTreeInterfacePanel::copy_from(
const blender::Span<const bNodeTreeInterfaceItem *> items_src, int flag)
{
items_num = items_src.size();
items_array = MEM_cnew_array<bNodeTreeInterfaceItem *>(items_num, __func__);
/* Copy buffers. */
for (const int i : items_src.index_range()) {
const bNodeTreeInterfaceItem *item_src = items_src[i];
items_array[i] = static_cast<bNodeTreeInterfaceItem *>(MEM_dupallocN(item_src));
item_types::item_copy(*items_array[i], *item_src, flag);
}
}
void bNodeTreeInterface::init_data()
{
/* Root panel is allowed to contain child panels. */
@ -1021,7 +1027,7 @@ void bNodeTreeInterface::init_data()
void bNodeTreeInterface::copy_data(const bNodeTreeInterface &src, int flag)
{
this->root_panel.copy_from(src.root_panel.items(), flag);
item_types::panel_init(this->root_panel, src.root_panel.items(), flag, nullptr);
this->active_index = src.active_index;
}
@ -1188,8 +1194,7 @@ bNodeTreeInterfaceItem *bNodeTreeInterface::add_item_copy(const bNodeTreeInterfa
}
bNodeTreeInterfaceItem *citem = static_cast<bNodeTreeInterfaceItem *>(MEM_dupallocN(&item));
item_types::item_copy(*citem, item, 0);
item_types::item_set_unique_identifier(next_uid++, *citem);
item_types::item_copy(*citem, item, 0, [&]() { return this->next_uid++; });
parent->add_item(*citem);
return citem;
@ -1213,8 +1218,7 @@ bNodeTreeInterfaceItem *bNodeTreeInterface::insert_item_copy(const bNodeTreeInte
}
bNodeTreeInterfaceItem *citem = static_cast<bNodeTreeInterfaceItem *>(MEM_dupallocN(&item));
item_types::item_copy(*citem, item, 0);
item_types::item_set_unique_identifier(next_uid++, *citem);
item_types::item_copy(*citem, item, 0, [&]() { return this->next_uid++; });
parent->insert_item(*citem, position);
return citem;

View File

@ -148,6 +148,15 @@ static void BKE_previewimg_free(PreviewImageDeferred **prv)
*prv = nullptr;
}
void BKE_previewimg_runtime_data_clear(PreviewImage *prv)
{
prv->tag = 0;
prv->icon_id = 0;
for (int i = 0; i < NUM_ICON_SIZES; i++) {
prv->gputexture[i] = nullptr;
}
}
void BKE_previewimg_clear_single(PreviewImage *prv, enum eIconSizes size)
{
MEM_SAFE_FREE(prv->rect[size]);
@ -508,7 +517,6 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
if (prv->rect[i]) {
BLO_read_data_address(reader, &prv->rect[i]);
}
prv->gputexture[i] = nullptr;
/* PRV_RENDERING is a runtime only flag currently, but don't mess with it on undo! It gets
* special handling in #memfile_undosys_restart_unfinished_id_previews() then. */
@ -516,6 +524,5 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
prv->flag[i] &= ~PRV_RENDERING;
}
}
prv->icon_id = 0;
prv->tag = 0;
BKE_previewimg_runtime_data_clear(prv);
}

View File

@ -133,6 +133,8 @@ MINLINE void add_v4_v4v4(float r[4], const float a[4], const float b[4]);
MINLINE void add_v3fl_v3fl_v3i(float r[3], const float a[3], const int b[3]);
MINLINE void add_v3_uchar_clamped(uchar r[3], int i);
MINLINE void sub_v2_v2(float r[2], const float a[2]);
MINLINE void sub_v2_v2_db(double r[2], const double a[2]);
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2]);

View File

@ -89,9 +89,9 @@ template<typename T> class OffsetIndices {
return OffsetIndices(offsets_.slice(range.start(), range.one_after_last()));
}
const T *data() const
Span<T> data() const
{
return offsets_.data();
return offsets_;
}
};

View File

@ -458,6 +458,13 @@ MINLINE void add_v4_v4v4(float r[4], const float a[4], const float b[4])
r[3] = a[3] + b[3];
}
MINLINE void add_v3_uchar_clamped(uchar r[3], int i)
{
r[0] = (uchar)clamp_i(r[0] + i, 0, 255);
r[1] = (uchar)clamp_i(r[1] + i, 0, 255);
r[2] = (uchar)clamp_i(r[2] + i, 0, 255);
}
MINLINE void sub_v2_v2(float r[2], const float a[2])
{
r[0] -= a[0];

View File

@ -272,6 +272,7 @@ PreviewImage *BLO_blendhandle_get_preview_for_id(BlendHandle *bh,
if (preview_from_file == nullptr) {
break;
}
BKE_previewimg_runtime_data_clear(preview_from_file);
PreviewImage *result = static_cast<PreviewImage *>(MEM_dupallocN(preview_from_file));
bhead = blo_blendhandle_read_preview_rects(fd, bhead, result, preview_from_file);
@ -334,6 +335,8 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_
prv = static_cast<PreviewImage *>(BLO_library_read_struct(fd, bhead, "PreviewImage"));
if (prv) {
BKE_previewimg_runtime_data_clear(prv);
memcpy(new_prv, prv, sizeof(PreviewImage));
bhead = blo_blendhandle_read_preview_rects(fd, bhead, new_prv, prv);
MEM_freeN(prv);

View File

@ -88,6 +88,12 @@ static void version_bonegroup_migrate_color(Main *bmain)
bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
BLI_assert_msg(GS(arm->id.name) == ID_AR,
"Expected ARMATURE object to have an Armature as data");
/* There is no guarantee that the current state of poses is in sync with the Armature data.
*
* NOTE: No need to handle user refcounting in readfile code. */
BKE_pose_ensure(bmain, ob, arm, false);
PoseSet &pose_set = armature_poses.lookup_or_add_default(arm);
pose_set.add(ob->pose);
}

View File

@ -390,7 +390,7 @@ BLI_INLINE void extract_task_range_run_iter(const MeshRenderData &mr,
stop = mr.tri_len;
break;
case MR_ITER_POLY:
range_data.elems = is_mesh ? mr.faces.data() : (void *)mr.bm->ftable;
range_data.elems = is_mesh ? mr.faces.data().data() : (void *)mr.bm->ftable;
func = is_mesh ? extract_range_iter_face_mesh : extract_range_iter_face_bm;
stop = mr.face_len;
break;

View File

@ -204,14 +204,14 @@ static void accumululate_material_counts_mesh(
for (const int i : range) {
if (!mr.hide_poly[i]) {
const int mat = std::clamp(material_indices[i], 0, last_index);
tri_counts[mat] += ME_FACE_TRI_TOT(faces[i].size());
tri_counts[mat] += bke::mesh::face_triangles_num(faces[i].size());
}
}
}
else {
for (const int i : range) {
const int mat = std::clamp(material_indices[i], 0, last_index);
tri_counts[mat] += ME_FACE_TRI_TOT(faces[i].size());
tri_counts[mat] += bke::mesh::face_triangles_num(faces[i].size());
}
}
});

View File

@ -175,6 +175,8 @@ enum {
UI_BLOCK_SEARCH_ONLY = 1 << 25,
/** Hack for quick setup (splash screen) to draw text centered. */
UI_BLOCK_QUICK_SETUP = 1 << 26,
/** Don't accelerator keys for the items in the block. */
UI_BLOCK_NO_ACCELERATOR_KEYS = 1 << 27,
};
/** #uiPopupBlockHandle.menuretval */
@ -247,6 +249,15 @@ enum {
UI_BUT_OVERRIDDEN = 1u << 31u,
};
enum {
/**
* This is used when `UI_BUT_ACTIVATE_ON_INIT` is used, which is used to activate e.g. a search
* box as soon as a popup opens. Usually, the text in the search box is selected by default.
* However, sometimes this behavior is not desired, so it can be disabled with this flag.
*/
UI_BUT2_ACTIVATE_ON_INIT_NO_SELECT = 1 << 0,
};
/** #uiBut.dragflag */
enum {
/** By default only the left part of a button triggers dragging. A questionable design to make
@ -887,6 +898,7 @@ bool UI_but_active_drop_color(bContext *C);
void UI_but_flag_enable(uiBut *but, int flag);
void UI_but_flag_disable(uiBut *but, int flag);
bool UI_but_flag_is_set(uiBut *but, int flag);
void UI_but_flag2_enable(uiBut *but, int flag);
void UI_but_drawflag_enable(uiBut *but, int flag);
void UI_but_drawflag_disable(uiBut *but, int flag);
@ -2404,7 +2416,7 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C);
void UI_but_func_operator_search(uiBut *but);
void uiTemplateOperatorSearch(uiLayout *layout);
void UI_but_func_menu_search(uiBut *but);
void UI_but_func_menu_search(uiBut *but, const char *single_menu_idname = nullptr);
void uiTemplateMenuSearch(uiLayout *layout);
/**

View File

@ -2001,7 +2001,9 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_x
UI_block_layout_resolve(block, nullptr, nullptr);
}
ui_block_align_calc(block, CTX_wm_region(C));
if ((block->flag & UI_BLOCK_LOOP) && (block->flag & UI_BLOCK_NUMSELECT)) {
if ((block->flag & UI_BLOCK_LOOP) && (block->flag & UI_BLOCK_NUMSELECT) &&
(block->flag & UI_BLOCK_NO_ACCELERATOR_KEYS) == 0)
{
ui_menu_block_set_keyaccels(block); /* could use a different flag to check */
}
@ -4467,9 +4469,8 @@ static void ui_def_but_rna__menu(bContext * /*C*/, uiLayout *layout, void *but_p
-1,
item->description);
}
item_but->flag |= UI_BUT_LIST_ITEM;
if (item->value == current_value) {
item_but->flag |= UI_BUT_ACTIVE_DEFAULT;
item_but->flag |= UI_SELECT_DRAW;
}
}
}
@ -5848,6 +5849,11 @@ void UI_but_flag_enable(uiBut *but, int flag)
but->flag |= flag;
}
void UI_but_flag2_enable(uiBut *but, int flag)
{
but->flag2 |= flag;
}
void UI_but_flag_disable(uiBut *but, int flag)
{
but->flag &= ~flag;

View File

@ -3480,7 +3480,12 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
/* set cursor pos to the end of the text */
but->editstr = data->str;
but->pos = len;
but->selsta = 0;
if (bool(but->flag2 & UI_BUT2_ACTIVATE_ON_INIT_NO_SELECT)) {
but->selsta = len;
}
else {
but->selsta = 0;
}
but->selend = len;
/* Initialize undo history tracking. */
@ -4316,6 +4321,9 @@ static void ui_block_open_begin(bContext *C, uiBut *but, uiHandleButtonData *dat
}
else if (menufunc) {
data->menu = ui_popup_menu_create(C, data->region, but, menufunc, arg);
if (MenuType *mt = UI_but_menutype_get(but)) {
STRNCPY(data->menu->menu_idname, mt->idname);
}
if (but->block->handle) {
data->menu->popup = but->block->handle->popup;
}
@ -9107,6 +9115,13 @@ void ui_but_activate_event(bContext *C, ARegion *region, uiBut *but)
void ui_but_activate_over(bContext *C, ARegion *region, uiBut *but)
{
/* If there is an active button in the currently active region,
* then add UI_SELECT_DRAW to the to-be-activated button. */
ARegion *active_region = CTX_wm_region(C);
if (active_region && ui_region_find_active_but(active_region)) {
but->flag |= UI_SELECT_DRAW;
}
button_activate_init(C, region, but, BUTTON_ACTIVATE_OVER);
}
@ -10269,6 +10284,41 @@ float ui_block_calc_pie_segment(uiBlock *block, const float event_xy[2])
return len;
}
static int ui_handle_menu_letter_press(
bContext *C, ARegion *region, uiPopupBlockHandle *menu, const wmEvent *event, uiBlock *block)
{
/* Start menu search on key press if enabled. */
if (menu->menu_idname[0]) {
MenuType *mt = WM_menutype_find(menu->menu_idname, false);
if (bool(mt->flag & MenuTypeFlag::SearchOnKeyPress)) {
uiAfterFunc *after = ui_afterfunc_new();
wmOperatorType *ot = WM_operatortype_find("WM_OT_search_single_menu", false);
after->optype = ot;
after->opcontext = WM_OP_INVOKE_DEFAULT;
after->opptr = MEM_cnew<PointerRNA>(__func__);
WM_operator_properties_create_ptr(after->opptr, ot);
RNA_string_set(after->opptr, "menu_idname", menu->menu_idname);
RNA_string_set(after->opptr, "initial_query", event->utf8_buf);
menu->menuretval = UI_RETURN_OK;
return WM_UI_HANDLER_BREAK;
}
}
/* Handle accelerator keys that allow "pressing" a menu entry by pressing a single key. */
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (!(but->flag & UI_BUT_DISABLED) && but->menu_key == event->type) {
if (but->type == UI_BTYPE_BUT) {
UI_but_execute(C, region, but);
}
else {
ui_handle_button_activate_by_type(C, region, but);
}
return WM_UI_HANDLER_BREAK;
}
}
return WM_UI_HANDLER_CONTINUE;
}
static int ui_handle_menu_event(bContext *C,
const wmEvent *event,
uiPopupBlockHandle *menu,
@ -10709,20 +10759,7 @@ static int ui_handle_menu_event(bContext *C,
menu, but, level, is_parent_menu, retval)) {
break;
}
for (but = static_cast<uiBut *>(block->buttons.first); but; but = but->next) {
if (!(but->flag & UI_BUT_DISABLED) && but->menu_key == event->type) {
if (but->type == UI_BTYPE_BUT) {
UI_but_execute(C, region, but);
}
else {
ui_handle_button_activate_by_type(C, region, but);
}
break;
}
}
retval = WM_UI_HANDLER_BREAK;
retval = ui_handle_menu_letter_press(C, region, menu, event, block);
}
break;
}

View File

@ -151,6 +151,7 @@ struct uiBut {
/** Pointer back to the layout item holding this button. */
uiLayout *layout = nullptr;
int flag = 0;
int flag2 = 0;
int drawflag = 0;
eButType type = eButType(0);
eButPointerType pointype = UI_BUT_POIN_NONE;
@ -848,6 +849,8 @@ struct uiPopupBlockHandle {
bool is_grab;
int grab_xy_prev[2];
/* #endif */
char menu_idname[64];
};
/* -------------------------------------------------------------------- */

View File

@ -5918,9 +5918,12 @@ void UI_menutype_draw(bContext *C, MenuType *mt, uiLayout *layout)
printf("%s: opening menu \"%s\"\n", __func__, mt->idname);
}
uiBlock *block = uiLayoutGetBlock(layout);
if (bool(mt->flag & MenuTypeFlag::SearchOnKeyPress)) {
UI_block_flag_enable(block, UI_BLOCK_NO_ACCELERATOR_KEYS);
}
if (mt->listener) {
/* Forward the menu type listener to the block we're drawing in. */
uiBlock *block = uiLayoutGetBlock(layout);
uiBlockDynamicListener *listener = static_cast<uiBlockDynamicListener *>(
MEM_mallocN(sizeof(*listener), __func__));
listener->listener_func = mt->listener;

View File

@ -397,6 +397,12 @@ static uiPopupBlockHandle *ui_popup_menu_create(
if (but) {
pup->slideout = ui_block_is_menu(but->block);
pup->but = but;
if (MenuType *mt = UI_but_menutype_get(but)) {
if (bool(mt->flag & MenuTypeFlag::SearchOnKeyPress)) {
ED_workspace_status_text(C, TIP_("Type to search..."));
}
}
}
if (!but) {
@ -608,7 +614,12 @@ static void ui_popup_menu_create_from_menutype(bContext *C,
ui_item_menutype_func(C, layout, mt);
});
STRNCPY(handle->menu_idname, mt->idname);
handle->can_refresh = true;
if (bool(mt->flag & MenuTypeFlag::SearchOnKeyPress)) {
ED_workspace_status_text(C, TIP_("Type to search..."));
}
}
int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports)

View File

@ -575,6 +575,11 @@ uiBlock *ui_popup_block_refresh(bContext *C,
block = handle_create_func(C, handle, arg);
}
/* Don't create accelerator keys if the parent menu does not have them. */
if (but && but->block->flag & UI_BLOCK_NO_ACCELERATOR_KEYS) {
block->flag |= UI_BLOCK_NO_ACCELERATOR_KEYS;
}
/* callbacks _must_ leave this for us, otherwise we can't call UI_block_update_from_old */
BLI_assert(!block->endblock);
@ -815,6 +820,10 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C,
void ui_popup_block_free(bContext *C, uiPopupBlockHandle *handle)
{
/* This disables the status bar text that is set when opening a menu that supports search (see
* #MenuTypeFlag::SearchOnKeyPress). */
ED_workspace_status_text(C, nullptr);
/* If this popup is created from a popover which does NOT have keep-open flag set,
* then close the popover too. We could extend this to other popup types too. */
ARegion *region = handle->popup_create_vars.butregion;

View File

@ -428,8 +428,12 @@ static void menu_items_from_all_operators(bContext *C, MenuSearch_Data *data)
* - Look up predefined editor-menus.
* - Look up key-map items which call menus.
*/
static MenuSearch_Data *menu_items_from_ui_create(
bContext *C, wmWindow *win, ScrArea *area_init, ARegion *region_init, bool include_all_areas)
static MenuSearch_Data *menu_items_from_ui_create(bContext *C,
wmWindow *win,
ScrArea *area_init,
ARegion *region_init,
bool include_all_areas,
const char *single_menu_idname)
{
MemArena *memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
blender::Map<MenuType *, const char *> menu_display_name_map;
@ -591,11 +595,18 @@ static MenuSearch_Data *menu_items_from_ui_create(
region = region_init;
}
/* Populate menus from the editors,
* note that we could create a fake header, draw the header and extract the menus
* from the buttons, however this is quite involved and can be avoided as by convention
* each space-type has a single root-menu that headers use. */
{
if (single_menu_idname) {
if (MenuType *mt = WM_menutype_find(single_menu_idname, false)) {
if (menu_tagged.add(mt)) {
menu_stack.push({mt});
}
}
}
else {
/* Populate menus from the editors,
* note that we could create a fake header, draw the header and extract the menus
* from the buttons, however this is quite involved and can be avoided as by convention
* each space-type has a single root-menu that headers use. */
const char *idname_array[2] = {nullptr};
int idname_array_len = 0;
@ -798,12 +809,14 @@ static MenuSearch_Data *menu_items_from_ui_create(
}
UI_block_free(nullptr, block);
/* Add key-map items as a second pass,
* so all menus are accessed from the header & top-bar before key shortcuts are expanded. */
if (menu_stack.is_empty() && (has_keymap_menu_items == false)) {
has_keymap_menu_items = true;
menu_types_add_from_keymap_items(
C, win, area, region, menu_stack, menu_to_kmi, menu_tagged);
if (single_menu_idname == nullptr) {
/* Add key-map items as a second pass, so all menus are accessed from the header & top-bar
* before key shortcuts are expanded. */
if (menu_stack.is_empty() && (has_keymap_menu_items == false)) {
has_keymap_menu_items = true;
menu_types_add_from_keymap_items(
C, win, area, region, menu_stack, menu_to_kmi, menu_tagged);
}
}
}
}
@ -887,7 +900,7 @@ static MenuSearch_Data *menu_items_from_ui_create(
* - Many operators need options to be set to give useful results, see: #74157.
* - User who really prefer to list all operators can use #WM_OT_search_operator.
*/
if (U.flag & USER_DEVELOPER_UI) {
if ((U.flag & USER_DEVELOPER_UI) && single_menu_idname == nullptr) {
menu_items_from_all_operators(C, data);
}
@ -1112,15 +1125,17 @@ static ARegion *ui_search_menu_create_tooltip(
/** \name Menu Search Template Public API
* \{ */
void UI_but_func_menu_search(uiBut *but)
void UI_but_func_menu_search(uiBut *but, const char *single_menu_idname)
{
bContext *C = (bContext *)but->block->evil_C;
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
/* When run from top-bar scan all areas in the current window. */
const bool include_all_areas = (area && (area->spacetype == SPACE_TOPBAR));
MenuSearch_Data *data = menu_items_from_ui_create(C, win, area, region, include_all_areas);
const bool include_all_areas = (area && (area->spacetype == SPACE_TOPBAR)) &&
!single_menu_idname;
MenuSearch_Data *data = menu_items_from_ui_create(
C, win, area, region, include_all_areas, single_menu_idname);
UI_but_func_search_set(but,
/* Generic callback. */
ui_searchbox_create_menu,

View File

@ -6397,6 +6397,21 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
uiBlock *block = uiLayoutGetBlock(ui_abs);
eUIEmbossType previous_emboss = UI_block_emboss_get(block);
uchar report_icon_color[4];
uchar report_text_color[4];
UI_GetThemeColorType4ubv(
UI_icon_colorid_from_report_type(report->type), SPACE_INFO, report_icon_color);
UI_GetThemeColorType4ubv(
UI_text_colorid_from_report_type(report->type), SPACE_INFO, report_text_color);
report_text_color[3] = 255; /* This theme color is RGB only, so have to set alpha here. */
if (rti->flash_progress <= 1.0) {
/* Flash report briefly according to progress through fade-out duration. */
const int brighten_amount = int(32 * (1.0f - rti->flash_progress));
add_v3_uchar_clamped(report_icon_color, brighten_amount);
}
UI_fontstyle_set(&style->widgetlabel);
int width = BLF_width(style->widgetlabel.uifont_id, report->message, report->len);
width = min_ii(int(rti->widthfac * width), width);
@ -6420,7 +6435,7 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
0,
"");
/* UI_BTYPE_ROUNDBOX's bg color is set in but->col. */
UI_GetThemeColorType4ubv(UI_icon_colorid_from_report_type(report->type), SPACE_INFO, but->col);
copy_v4_v4_uchar(but->col, report_icon_color);
/* Background for the rest of the message. */
but = uiDefBut(block,
@ -6437,9 +6452,8 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
0,
0,
"");
/* Use icon background at low opacity to highlight, but still contrasting with area TH_TEXT. */
UI_GetThemeColorType4ubv(UI_icon_colorid_from_report_type(report->type), SPACE_INFO, but->col);
copy_v3_v3_uchar(but->col, report_icon_color);
but->col[3] = 64;
UI_block_align_end(block);
@ -6456,8 +6470,7 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
UI_UNIT_X,
UI_UNIT_Y,
TIP_("Click to open the info editor"));
UI_GetThemeColorType4ubv(UI_text_colorid_from_report_type(report->type), SPACE_INFO, but->col);
but->col[3] = 255; /* This theme color is RBG only, so have to set alpha here. */
copy_v4_v4_uchar(but->col, report_text_color);
/* The report message. */
but = uiDefButO(block,

View File

@ -154,13 +154,6 @@ static void color_blend_v4_v4v4(uchar r_col[4],
r_col[3] = (faci * col1[3] + facm * col2[3]) / 256;
}
static void color_add_v3_i(uchar cp[3], int tint)
{
cp[0] = clamp_i(cp[0] + tint, 0, 255);
cp[1] = clamp_i(cp[1] + tint, 0, 255);
cp[2] = clamp_i(cp[2] + tint, 0, 255);
}
static void color_ensure_contrast_v3(uchar cp[3], const uchar cp_other[3], int contrast)
{
BLI_assert(contrast > 0);
@ -169,12 +162,12 @@ static void color_ensure_contrast_v3(uchar cp[3], const uchar cp_other[3], int c
const int delta = item_value - inner_value;
if (delta >= 0) {
if (contrast > delta) {
color_add_v3_i(cp, contrast - delta);
add_v3_uchar_clamped(cp, contrast - delta);
}
}
else {
if (contrast > -delta) {
color_add_v3_i(cp, -contrast - delta);
add_v3_uchar_clamped(cp, -contrast - delta);
}
}
}
@ -1269,8 +1262,8 @@ static void widgetbase_draw_ex(uiWidgetBase *wtb,
outline_col[2] = wcol->outline[2];
outline_col[3] = wcol->outline[3];
/* emboss bottom shadow */
if (wtb->draw_emboss) {
/* Emboss shadow if enabled, and inner and outline colors are not fully transparent. */
if ((wtb->draw_emboss) && (wcol->inner[3] != 0.0f || wcol->outline[3] != 0.0f)) {
UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss_col);
}
}
@ -2737,10 +2730,8 @@ static void widget_state_menu_item(uiWidgetType *wt,
/* Regular disabled. */
color_blend_v3_v3(wt->wcol.text, wt->wcol.inner, 0.5f);
}
else if ((state->but_flag & UI_BUT_LIST_ITEM) &&
state->but_flag & (UI_BUT_ACTIVE_DEFAULT | UI_SELECT))
{
/* Currently-selected list item. */
else if (state->but_flag & (UI_BUT_ACTIVE_DEFAULT | UI_SELECT_DRAW)) {
/* Currently-selected item. */
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
copy_v4_v4_uchar(wt->wcol.text, wt->wcol.text_sel);
}

View File

@ -219,6 +219,9 @@ static int modifier_add_asset_exec(bContext *C, wmOperator *op)
id_us_plus(&node_group->id);
MOD_nodes_update_interface(object, nmd);
/* By default, don't show the data-block selector since it's not usually necessary for assets. */
nmd->flag |= NODES_MODIFIER_HIDE_DATABLOCK_SELECTOR;
STRNCPY(nmd->modifier.name, DATA_(node_group->id.name + 2));
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object);

View File

@ -3027,6 +3027,10 @@ static int drop_geometry_nodes_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED;
}
if (!RNA_boolean_get(op->ptr, "show_datablock_in_modifier")) {
nmd->flag |= NODES_MODIFIER_HIDE_DATABLOCK_SELECTOR;
}
nmd->node_group = node_tree;
id_us_plus(&node_tree->id);
MOD_nodes_update_interface(ob, nmd);
@ -3057,6 +3061,11 @@ void OBJECT_OT_drop_geometry_nodes(wmOperatorType *ot)
INT32_MIN,
INT32_MAX);
RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
RNA_def_boolean(ot->srna,
"show_datablock_in_modifier",
true,
"Show the datablock selector in the modifier",
"");
}
/** \} */

View File

@ -1070,12 +1070,9 @@ static void draw_fcurve_curve_keys(
const int2 bounding_indices = get_bounding_bezt_indices(fcu, v2d->cur.xmin, v2d->cur.xmax);
/* This happens if there is only 1 frame in the curve or the view is only showing the
* extrapolation zone of the curve. */
if (bounding_indices[0] == bounding_indices[1]) {
BezTriple *bezt = &fcu->bezt[bounding_indices[0]];
curve_vertices.append({bezt->vec[1][0], bezt->vec[1][1]});
}
/* Always add the first point so the extrapolation line doesn't jump. */
curve_vertices.append(
{fcu->bezt[bounding_indices[0]].vec[1][0], fcu->bezt[bounding_indices[0]].vec[1][1]});
const blender::float2 pixels_per_unit = calculate_pixels_per_unit(v2d);
const int window_width = BLI_rcti_size_x(&v2d->mask);

View File

@ -34,7 +34,6 @@
#include "WM_types.hh"
#include "UI_interface.hh"
#include "UI_resources.hh"
#include "RNA_access.hh"
#include "RNA_define.hh"
@ -574,17 +573,11 @@ void FILE_OT_find_missing_files(wmOperatorType *ot)
#define ERROR_TIMEOUT 10.0f
#define FLASH_TIMEOUT 1.0f
#define COLLAPSE_TIMEOUT 0.25f
#define BRIGHTEN_AMOUNT 0.1f
static int update_reports_display_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
{
wmWindowManager *wm = CTX_wm_manager(C);
ReportList *reports = CTX_wm_reports(C);
Report *report;
ReportTimerInfo *rti;
float target_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float progress = 0.0, flash_progress = 0.0;
float timeout = 0.0, flash_timeout = FLASH_TIMEOUT;
int send_note = 0;
/* escape if not our timer */
if ((reports->reporttimer == nullptr) || (reports->reporttimer != event->customdata) ||
@ -594,12 +587,16 @@ static int update_reports_display_invoke(bContext *C, wmOperator * /*op*/, const
return OPERATOR_PASS_THROUGH;
}
rti = (ReportTimerInfo *)reports->reporttimer->customdata;
wmWindowManager *wm = CTX_wm_manager(C);
ReportTimerInfo *rti = (ReportTimerInfo *)reports->reporttimer->customdata;
const float flash_timeout = FLASH_TIMEOUT;
bool send_notifier = false;
timeout = (report->type & RPT_ERROR_ALL) ? ERROR_TIMEOUT : INFO_TIMEOUT;
const float timeout = (report->type & RPT_ERROR_ALL) ? ERROR_TIMEOUT : INFO_TIMEOUT;
const float time_duration = float(reports->reporttimer->time_duration);
/* clear the report display after timeout */
if (float(reports->reporttimer->time_duration) > timeout) {
if (time_duration > timeout) {
WM_event_timer_remove(wm, nullptr, reports->reporttimer);
reports->reporttimer = nullptr;
@ -608,41 +605,28 @@ static int update_reports_display_invoke(bContext *C, wmOperator * /*op*/, const
return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
}
/* set target color based on report type */
UI_GetThemeColorType3fv(UI_icon_colorid_from_report_type(report->type), SPACE_INFO, target_col);
target_col[3] = 0.65f;
if (rti->widthfac == 0.0f) {
/* initialize color to a brighter shade of the target color */
rti->col[0] = target_col[0] + BRIGHTEN_AMOUNT;
rti->col[1] = target_col[1] + BRIGHTEN_AMOUNT;
rti->col[2] = target_col[2] + BRIGHTEN_AMOUNT;
rti->col[3] = 1.0f;
CLAMP3(rti->col, 0.0, 1.0);
rti->widthfac = 1.0f;
}
progress = powf(float(reports->reporttimer->time_duration) / timeout, 2.0f);
flash_progress = powf(float(reports->reporttimer->time_duration) / flash_timeout, 2.0);
const float progress = powf(time_duration / timeout, 2.0f);
const float flash_progress = powf(time_duration / flash_timeout, 2.0);
/* save us from too many draws */
if (flash_progress <= 1.0f) {
send_note = 1;
/* flash report briefly according to progress through fade-out duration */
interp_v4_v4v4(rti->col, rti->col, target_col, flash_progress);
/* Flash report briefly according to progress through fade-out duration. */
send_notifier = true;
}
rti->flash_progress = flash_progress;
/* collapse report at end of timeout */
if (progress * timeout > timeout - COLLAPSE_TIMEOUT) {
rti->widthfac = (progress * timeout - (timeout - COLLAPSE_TIMEOUT)) / COLLAPSE_TIMEOUT;
rti->widthfac = 1.0f - rti->widthfac;
send_note = 1;
send_notifier = true;
}
if (send_note) {
if (send_notifier) {
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, nullptr);
}

View File

@ -526,7 +526,6 @@ static void node_update_basis_from_declaration(
if (!is_parent_collapsed) {
locy -= NODE_DY;
is_first = false;
need_spacer_after_item = true;
}
SET_FLAG_FROM_TEST(
@ -1758,6 +1757,12 @@ static void node_draw_panels_background(const bNode &node, uiBlock &block)
const nodes::NodeDeclaration &decl = *node.declaration();
const rctf &rct = node.runtime->totr;
float color_panel[4];
UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.2f, color_panel);
/* True if the last panel is open, draw bottom gap as background. */
bool is_last_panel_visible = false;
float last_panel_content_y = 0.0f;
int panel_i = 0;
for (const nodes::ItemDeclarationPtr &item_decl : decl.items) {
@ -1769,25 +1774,21 @@ static void node_draw_panels_background(const bNode &node, uiBlock &block)
}
const bNodePanelState &state = node.panel_states()[panel_i];
const bke::bNodePanelRuntime &runtime = node.runtime->panels[panel_i];
/* Don't draw hidden or collapsed panels. */
if (state.is_collapsed() || state.is_parent_collapsed()) {
const bool is_visible = !(state.is_collapsed() || state.is_parent_collapsed());
is_last_panel_visible = is_visible;
last_panel_content_y = runtime.max_content_y;
if (!is_visible) {
++panel_i;
continue;
}
const bke::bNodePanelRuntime &runtime = node.runtime->panels[panel_i];
const rctf content_rect = {
rct.xmin,
rct.xmax,
runtime.min_content_y,
runtime.max_content_y,
};
UI_block_emboss_set(&block, UI_EMBOSS_NONE);
/* Panel background. */
float color_panel[4];
UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.2f, color_panel);
const rctf content_rect = {rct.xmin, rct.xmax, runtime.min_content_y, runtime.max_content_y};
UI_draw_roundbox_corner_set(UI_CNR_NONE);
UI_draw_roundbox_4fv(&content_rect, true, BASIS_RAD, color_panel);
@ -1795,6 +1796,17 @@ static void node_draw_panels_background(const bNode &node, uiBlock &block)
++panel_i;
}
/* If last item is an open panel, extend the panel background to cover the bottom border. */
if (is_last_panel_visible) {
UI_block_emboss_set(&block, UI_EMBOSS_NONE);
const rctf content_rect = {rct.xmin, rct.xmax, rct.ymin, last_panel_content_y};
UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
UI_draw_roundbox_4fv(&content_rect, true, BASIS_RAD, color_panel);
UI_block_emboss_set(&block, UI_EMBOSS);
}
}
static void node_draw_panels(bNodeTree &ntree, const bNode &node, uiBlock &block)
@ -1857,7 +1869,7 @@ static void node_draw_panels(bNodeTree &ntree, const bNode &node, uiBlock &block
panel_decl->name.c_str(),
int(rct.xmin + NODE_MARGIN_X + 0.4f),
int(runtime.location_y - NODE_DYS),
short(rct.xmax - rct.xmin - 0.35f * U.widget_unit),
short(rct.xmax - rct.xmin - (30.0f * UI_SCALE_FAC)),
short(NODE_DY),
nullptr,
0,

View File

@ -1022,6 +1022,7 @@ static void node_group_make_insert_selected(const bContext &C,
Map<int32_t, int32_t> node_identifier_map;
ntree.ensure_topology_cache();
/* Add all outputs first. */
for (bNode *node : nodes_to_move) {
for (bNodeSocket *output_socket : node->output_sockets()) {
for (bNodeLink *link : output_socket->directly_linked_links()) {
@ -1047,6 +1048,9 @@ static void node_group_make_insert_selected(const bContext &C,
}
}
}
}
/* Now add all inputs. */
for (bNode *node : nodes_to_move) {
for (bNodeSocket *input_socket : node->input_sockets()) {
for (bNodeLink *link : input_socket->directly_linked_links()) {
if (nodeLinkIsHidden(link)) {
@ -1067,9 +1071,6 @@ static void node_group_make_insert_selected(const bContext &C,
if (!info.interface_socket) {
info.interface_socket = add_interface_from_socket(ntree, group, *link->tosock);
}
else {
links_to_remove.add(link);
}
}
}
}

View File

@ -911,6 +911,13 @@ static void view3d_id_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
ID *id = WM_drag_get_local_ID_or_import_from_asset(C, drag, 0);
WM_operator_properties_id_lookup_set_from_id(drop->ptr, id);
RNA_boolean_set(drop->ptr, "show_datablock_in_modifier", (drag->type != WM_DRAG_ASSET));
}
static void view3d_geometry_nodes_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
{
view3d_id_drop_copy(C, drag, drop);
RNA_boolean_set(drop->ptr, "show_datablock_in_modifier", (drag->type != WM_DRAG_ASSET));
}
static void view3d_id_drop_copy_with_type(bContext *C, wmDrag *drag, wmDropBox *drop)
@ -1008,7 +1015,7 @@ static void view3d_dropboxes()
WM_dropbox_add(lb,
"OBJECT_OT_drop_geometry_nodes",
view3d_geometry_nodes_drop_poll,
view3d_id_drop_copy,
view3d_geometry_nodes_drop_copy,
WM_drag_free_imported_drag_ID,
view3d_geometry_nodes_drop_tooltip);
WM_dropbox_add(lb,

View File

@ -34,21 +34,9 @@ static void snap_object_data_mesh_get(const Mesh *me_eval,
bool use_hide,
BVHTreeFromMesh *r_treedata)
{
const Span<float3> vert_positions = me_eval->vert_positions();
const blender::OffsetIndices faces = me_eval->faces();
const Span<int> corner_verts = me_eval->corner_verts();
/* The BVHTree from looptris is always required. */
BKE_bvhtree_from_mesh_get(
r_treedata, me_eval, use_hide ? BVHTREE_FROM_LOOPTRI_NO_HIDDEN : BVHTREE_FROM_LOOPTRI, 4);
BLI_assert(reinterpret_cast<const float3 *>(r_treedata->vert_positions) ==
vert_positions.data());
BLI_assert(r_treedata->corner_verts == corner_verts.data());
BLI_assert(!faces.data() || r_treedata->looptri);
BLI_assert(!r_treedata->tree || r_treedata->looptri);
UNUSED_VARS_NDEBUG(vert_positions, faces, corner_verts);
}
/** \} */

View File

@ -591,8 +591,6 @@ void split_edges(Mesh &mesh,
propagate_vert_attributes(mesh, vert_map);
BKE_mesh_tag_edges_split(&mesh);
BLI_assert(BKE_mesh_is_valid(&mesh));
}
} // namespace blender::geometry

View File

@ -51,6 +51,7 @@ typedef enum ThumbSource {
/**
* Create thumbnail for file and returns new imbuf for thumbnail.
* \param filepath: File path (but not a library path!) to the thumbnail to be created.
*/
struct ImBuf *IMB_thumb_create(const char *filepath,
ThumbSize size,
@ -59,18 +60,24 @@ struct ImBuf *IMB_thumb_create(const char *filepath,
/**
* Read thumbnail for file and returns new imbuf for thumbnail.
* \param file_or_lib_path: File path or library-ID path (e.g. `/a/b.blend/Material/MyMaterial`) to
* the thumbnail to be read.
*/
struct ImBuf *IMB_thumb_read(const char *filepath, ThumbSize size);
struct ImBuf *IMB_thumb_read(const char *file_or_lib_path, ThumbSize size);
/**
* Delete all thumbs for the file.
* \param file_or_lib_path: File path or library-ID path (e.g. `/a/b.blend/Material/MyMaterial`) to
* the thumbnail to be deleted.
*/
void IMB_thumb_delete(const char *filepath, ThumbSize size);
void IMB_thumb_delete(const char *file_or_lib_path, ThumbSize size);
/**
* Create the thumb if necessary and manage failed and old thumbs.
* \param file_or_lib_path: File path or library-ID path (e.g. `/a/b.blend/Material/MyMaterial`) to
* the thumbnail to be created/managed.
*/
struct ImBuf *IMB_thumb_manage(const char *filepath, ThumbSize size, ThumbSource source);
struct ImBuf *IMB_thumb_manage(const char *file_or_lib_path, ThumbSize size, ThumbSource source);
/**
* Create the necessary directories to store the thumbnails.

View File

@ -495,13 +495,13 @@ ImBuf *IMB_thumb_create(const char *filepath, ThumbSize size, ThumbSource source
filepath, uri, thumb_name, false, THUMB_DEFAULT_HASH, nullptr, nullptr, size, source, img);
}
ImBuf *IMB_thumb_read(const char *filepath, ThumbSize size)
ImBuf *IMB_thumb_read(const char *file_or_lib_path, ThumbSize size)
{
char thumb[FILE_MAX];
char uri[URI_MAX];
ImBuf *img = nullptr;
if (!uri_from_filename(filepath, uri)) {
if (!uri_from_filename(file_or_lib_path, uri)) {
return nullptr;
}
if (thumbpath_from_uri(uri, thumb, sizeof(thumb), size)) {
@ -511,16 +511,16 @@ ImBuf *IMB_thumb_read(const char *filepath, ThumbSize size)
return img;
}
void IMB_thumb_delete(const char *filepath, ThumbSize size)
void IMB_thumb_delete(const char *file_or_lib_path, ThumbSize size)
{
char thumb[FILE_MAX];
char uri[URI_MAX];
if (!uri_from_filename(filepath, uri)) {
if (!uri_from_filename(file_or_lib_path, uri)) {
return;
}
if (thumbpath_from_uri(uri, thumb, sizeof(thumb), size)) {
if (BLI_path_ncmp(filepath, thumb, sizeof(thumb)) == 0) {
if (BLI_path_ncmp(file_or_lib_path, thumb, sizeof(thumb)) == 0) {
return;
}
if (BLI_exists(thumb)) {
@ -529,18 +529,16 @@ void IMB_thumb_delete(const char *filepath, ThumbSize size)
}
}
ImBuf *IMB_thumb_manage(const char *filepath, ThumbSize size, ThumbSource source)
ImBuf *IMB_thumb_manage(const char *file_or_lib_path, ThumbSize size, ThumbSource source)
{
char path_buff[FILE_MAX_LIBEXTRA];
/* Will be the actual path to the file, i.e. the same as #filepath or if that points into a
* .blend, the path of the .blend. */
const char *file_path;
const char *path;
char *blen_group = nullptr, *blen_id = nullptr;
path = file_path = filepath;
/* Will be the actual path to the file, i.e. the same as #file_or_lib_path, or if that points
* into a .blend, the path of the .blend. */
const char *file_path = file_or_lib_path;
if (source == THB_SOURCE_BLEND) {
if (BKE_blendfile_library_path_explode(path, path_buff, &blen_group, &blen_id)) {
if (BKE_blendfile_library_path_explode(file_or_lib_path, path_buff, &blen_group, &blen_id)) {
if (blen_group) {
if (!blen_id) {
/* No preview for blen groups */
@ -556,7 +554,7 @@ ImBuf *IMB_thumb_manage(const char *filepath, ThumbSize size, ThumbSource source
return nullptr;
}
char uri[URI_MAX];
if (!uri_from_filename(path, uri)) {
if (!uri_from_filename(file_or_lib_path, uri)) {
return nullptr;
}
char thumb_path[FILE_MAX];
@ -580,8 +578,8 @@ ImBuf *IMB_thumb_manage(const char *filepath, ThumbSize size, ThumbSource source
{
/* The requested path points to a generated thumbnail already (path into the thumbnail cache
* directory). Attempt to load that, there's nothing we can recreate. */
if (BLI_path_ncmp(path, thumb_path, sizeof(thumb_path)) == 0) {
img = IMB_loadiffname(path, IB_rect, nullptr);
if (BLI_path_ncmp(file_or_lib_path, thumb_path, sizeof(thumb_path)) == 0) {
img = IMB_loadiffname(file_or_lib_path, IB_rect, nullptr);
}
else {
img = IMB_loadiffname(thumb_path, IB_rect | IB_metadata, nullptr);
@ -617,9 +615,9 @@ ImBuf *IMB_thumb_manage(const char *filepath, ThumbSize size, ThumbSource source
/* recreate all thumbs */
IMB_freeImBuf(img);
img = nullptr;
IMB_thumb_delete(path, THB_NORMAL);
IMB_thumb_delete(path, THB_LARGE);
IMB_thumb_delete(path, THB_FAIL);
IMB_thumb_delete(file_or_lib_path, THB_NORMAL);
IMB_thumb_delete(file_or_lib_path, THB_LARGE);
IMB_thumb_delete(file_or_lib_path, THB_FAIL);
img = thumb_create_or_fail(
file_path, uri, thumb_name, use_hash, thumb_hash, blen_group, blen_id, size, source);
}

View File

@ -82,7 +82,7 @@ enum {
*
* #MLoopTri's are allocated in an array, where each polygon's #MLoopTri's are stored contiguously,
* the number of triangles for each polygon is guaranteed to be the corner count - 2,
* even for degenerate geometry. See #ME_FACE_TRI_TOT macro.
* even for degenerate geometry. See #bke::mesh::face_triangles_num macro.
*
* It's also possible to perform a reverse lookup (find all #MLoopTri's for any given face).
*
@ -90,7 +90,7 @@ enum {
* // loop over all looptri's for a given polygon: i
* const IndexRange face = faces[i];
* MLoopTri *lt = &looptri[poly_to_tri_count(i, face.start())];
* int j, lt_tot = ME_FACE_TRI_TOT(face.size());
* int j, lt_tot = bke::mesh::face_triangles_num(face.size());
*
* for (j = 0; j < lt_tot; j++, lt++) {
* int vtri[3] = {
@ -321,15 +321,6 @@ enum {
/** \} */
/* -------------------------------------------------------------------- */
/** \name Utility Macros
* \{ */
/** Number of triangles that make up this face once tessellated. */
#define ME_FACE_TRI_TOT(face_loop_num) ((face_loop_num)-2)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Deprecated Structs
* \{ */

View File

@ -2333,9 +2333,19 @@ typedef struct NodesModifierData {
* Directory where baked simulation states are stored. This may be relative to the .blend file.
*/
char *simulation_bake_directory;
/** NodesModifierFlag. */
int8_t flag;
char _pad[7];
NodesModifierRuntimeHandle *runtime;
} NodesModifierData;
typedef enum NodesModifierFlag {
NODES_MODIFIER_HIDE_DATABLOCK_SELECTOR = (1 << 0),
} NodesModifierFlag;
typedef struct MeshToVolumeModifierData {
ModifierData modifier;

View File

@ -159,11 +159,6 @@ typedef struct bNodeTreeInterfacePanel {
*/
bNodeTreeInterfacePanel *find_parent_recursive(const bNodeTreeInterfaceItem &item);
/**
* Create a copy of items in the span and add them to the interface.
* \note This does not generate new identifiers for items, use only for identical copies.
*/
void copy_from(blender::Span<const bNodeTreeInterfaceItem *> items_src, int flag);
/** Remove all items from the panel. */
void clear(bool do_id_user);

View File

@ -105,8 +105,8 @@ typedef struct ReportList {
#
#
typedef struct ReportTimerInfo {
float col[4];
float widthfac;
float flash_progress;
} ReportTimerInfo;
//#ifdef WITH_XR_OPENXR

View File

@ -2493,6 +2493,14 @@ static void rna_def_library(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_flag(prop, PROP_THICK_WRAP);
prop = RNA_def_property(srna, "needs_liboverride_resync", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "tag", LIBRARY_TAG_RESYNC_REQUIRED);
RNA_def_property_ui_text(prop,
"Library Overrides Need resync",
"True if this library contains library overrides that are linked in "
"current blendfile, and that had to be recursively resynced on load "
"(it is recommended to open and re-save that library blendfile then)");
func = RNA_def_function(srna, "reload", "rna_Library_reload");
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func, "Reload this library and all its linked data-blocks");

View File

@ -652,7 +652,7 @@ static void rna_MeshPolygon_flip(ID *id, MIntProperty *poly_offset_p)
{
using namespace blender;
Mesh *me = (Mesh *)id;
const int index = reinterpret_cast<int *>(poly_offset_p) - me->faces().data();
const int index = reinterpret_cast<int *>(poly_offset_p) - me->faces().data().data();
bke::mesh_flip_faces(*me, IndexMask(IndexRange(index, 1)));
BKE_mesh_tessface_clear(me);
BKE_mesh_runtime_clear_geometry(me);

View File

@ -7075,6 +7075,13 @@ static void rna_def_modifier_nodes(BlenderRNA *brna)
prop, "Simulation Bake Directory", "Location on disk where the bake data is stored");
RNA_def_property_update(prop, 0, nullptr);
prop = RNA_def_property(srna, "show_group_selector", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(
prop, nullptr, "flag", NODES_MODIFIER_HIDE_DATABLOCK_SELECTOR);
RNA_def_property_ui_text(prop, "Show Node Group Selector", "");
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, nullptr);
RNA_define_lib_overridable(false);
}

View File

@ -1995,6 +1995,15 @@ static void rna_def_menu(BlenderRNA *brna)
PropertyRNA *parm;
FunctionRNA *func;
static const EnumPropertyItem menu_flag_items[] = {
{int(MenuTypeFlag::SearchOnKeyPress),
"SEARCH_ON_KEY_PRESS",
0,
"Search on Key Press",
"Open a menu search when a key pressed while the menu is open"},
{0, nullptr, 0, nullptr, nullptr},
};
srna = RNA_def_struct(brna, "Menu", nullptr);
RNA_def_struct_ui_text(srna, "Menu", "Editor menu containing buttons");
RNA_def_struct_sdna(srna, "Menu");
@ -2059,6 +2068,12 @@ static void rna_def_menu(BlenderRNA *brna)
RNA_def_property_string_sdna(prop, nullptr, "type->owner_id");
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "type->flag");
RNA_def_property_enum_items(prop, menu_flag_items);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL | PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Options", "Options for this menu type");
RNA_define_verify_sdna(true);
}

View File

@ -1487,16 +1487,18 @@ static void panel_draw(const bContext *C, Panel *panel)
* attribute/value toggle requires a manually built layout anyway. */
uiLayoutSetPropDecorate(layout, false);
uiTemplateID(layout,
C,
ptr,
"node_group",
"node.new_geometry_node_group_assign",
nullptr,
nullptr,
0,
false,
nullptr);
if (!(nmd->flag & NODES_MODIFIER_HIDE_DATABLOCK_SELECTOR)) {
uiTemplateID(layout,
C,
ptr,
"node_group",
"node.new_geometry_node_group_assign",
nullptr,
nullptr,
0,
false,
nullptr);
}
if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) {
PointerRNA bmain_ptr = RNA_main_pointer_create(bmain);

View File

@ -288,6 +288,7 @@ static void modifier_ops_extra_draw(bContext *C, uiLayout *layout, void *md_v)
WM_OP_INVOKE_DEFAULT,
UI_ITEM_NONE,
&op_ptr);
uiItemR(layout, &ptr, "show_group_selector", UI_ITEM_NONE, nullptr, ICON_NONE);
}
}

View File

@ -335,8 +335,6 @@ static Mesh *create_uv_sphere_mesh(const float radius,
mesh->tag_loose_edges_none();
mesh->bounds_set_eager(calculate_bounds_uv_sphere(radius, segments, rings));
BLI_assert(BKE_mesh_is_valid(mesh));
return mesh;
}

View File

@ -797,8 +797,11 @@ void SEQ_retiming_sound_animation_data_set(const Scene *scene, const Sequence *s
}
}
else {
const int range_start = max_ii(0, range.start);
const int range_end = max_ii(0, range.end);
BKE_sound_set_scene_sound_pitch_constant_range(
seq->scene_sound, range.start, range.end, range.speed);
seq->scene_sound, range_start, range_end, range.speed);
}
}
}

View File

@ -1196,7 +1196,7 @@ int WM_operator_confirm_message_ex(bContext *C,
uiPopupMenu *pup = UI_popup_menu_begin(C, title, icon);
uiLayout *layout = UI_popup_menu_layout(pup);
uiItemFullO_ptr(
layout, op->type, message, ICON_NONE, properties, opcontext, UI_ITEM_NONE, nullptr);
layout, op->type, message, ICON_NONE, properties, opcontext, UI_ITEM_O_DEPRESS, nullptr);
UI_popup_menu_end(C, pup);
return OPERATOR_INTERFACE;
@ -1741,27 +1741,30 @@ static void WM_OT_operator_defaults(wmOperatorType *ot)
enum SearchType {
SEARCH_TYPE_OPERATOR = 0,
SEARCH_TYPE_MENU = 1,
SEARCH_TYPE_SINGLE_MENU = 2,
};
struct SearchPopupInit_Data {
SearchType search_type;
int size[2];
std::string single_menu_idname;
};
static char g_search_text[256] = "";
static uiBlock *wm_block_search_menu(bContext *C, ARegion *region, void *userdata)
{
const SearchPopupInit_Data *init_data = static_cast<const SearchPopupInit_Data *>(userdata);
static char search[256] = "";
uiBlock *block = UI_block_begin(C, region, "_popup", UI_EMBOSS);
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
uiBut *but = uiDefSearchBut(block,
search,
g_search_text,
0,
ICON_VIEWZOOM,
sizeof(search),
sizeof(g_search_text),
10,
10,
init_data->size[0],
@ -1776,6 +1779,10 @@ static uiBlock *wm_block_search_menu(bContext *C, ARegion *region, void *userdat
else if (init_data->search_type == SEARCH_TYPE_MENU) {
UI_but_func_menu_search(but);
}
else if (init_data->search_type == SEARCH_TYPE_SINGLE_MENU) {
UI_but_func_menu_search(but, init_data->single_menu_idname.c_str());
UI_but_flag2_enable(but, UI_BUT2_ACTIVATE_ON_INIT_NO_SELECT);
}
else {
BLI_assert_unreachable();
}
@ -1837,16 +1844,33 @@ static int wm_search_menu_invoke(bContext *C, wmOperator *op, const wmEvent *eve
}
}
int search_type;
SearchType search_type;
if (STREQ(op->type->idname, "WM_OT_search_menu")) {
search_type = SEARCH_TYPE_MENU;
}
else if (STREQ(op->type->idname, "WM_OT_search_single_menu")) {
search_type = SEARCH_TYPE_SINGLE_MENU;
}
else {
search_type = SEARCH_TYPE_OPERATOR;
}
static SearchPopupInit_Data data{};
data.search_type = SearchType(search_type);
if (search_type == SEARCH_TYPE_SINGLE_MENU) {
{
char *buffer = RNA_string_get_alloc(op->ptr, "menu_idname", nullptr, 0, nullptr);
data.single_menu_idname = buffer;
MEM_SAFE_FREE(buffer);
}
{
char *buffer = RNA_string_get_alloc(op->ptr, "initial_query", nullptr, 0, nullptr);
STRNCPY(g_search_text, buffer);
MEM_SAFE_FREE(buffer);
}
}
data.search_type = search_type;
data.size[0] = UI_searchbox_size_x() * 2;
data.size[1] = UI_searchbox_size_y();
@ -1877,6 +1901,25 @@ static void WM_OT_search_operator(wmOperatorType *ot)
ot->poll = WM_operator_winactive;
}
static void WM_OT_search_single_menu(wmOperatorType *ot)
{
ot->name = "Search Single Menu";
ot->idname = "WM_OT_search_single_menu";
ot->description = "Pop-up a search for a menu in current context";
ot->invoke = wm_search_menu_invoke;
ot->exec = wm_search_menu_exec;
ot->poll = WM_operator_winactive;
RNA_def_string(ot->srna, "menu_idname", nullptr, 0, "Menu Name", "Menu to search in");
RNA_def_string(ot->srna,
"initial_query",
nullptr,
0,
"Initial Query",
"Query to insert into the search box");
}
static int wm_call_menu_exec(bContext *C, wmOperator *op)
{
char idname[BKE_ST_MAXNAME];
@ -2024,6 +2067,24 @@ static bool wm_operator_winactive_normal(bContext *C)
return true;
}
static bool wm_operator_winactive_not_full(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
bScreen *screen;
if (win == nullptr) {
return false;
}
if (!((screen = WM_window_get_active_screen(win)) && (screen->state != SCREENFULL))) {
return false;
}
if (G.background) {
return false;
}
return true;
}
/* included for script-access */
static void WM_OT_window_close(wmOperatorType *ot)
{
@ -2042,7 +2103,7 @@ static void WM_OT_window_new(wmOperatorType *ot)
ot->description = "Create a new window";
ot->exec = wm_window_new_exec;
ot->poll = wm_operator_winactive_normal;
ot->poll = wm_operator_winactive_not_full;
}
static void WM_OT_window_new_main(wmOperatorType *ot)
@ -3833,6 +3894,7 @@ void wm_operatortypes_register()
WM_operatortype_append(WM_OT_splash_about);
WM_operatortype_append(WM_OT_search_menu);
WM_operatortype_append(WM_OT_search_operator);
WM_operatortype_append(WM_OT_search_single_menu);
WM_operatortype_append(WM_OT_call_menu);
WM_operatortype_append(WM_OT_call_menu_pie);
WM_operatortype_append(WM_OT_call_panel);

View File

@ -79,6 +79,7 @@ SOURCE_EXT = (
"hh",
"m",
"mm",
"metal",
"msl",
"glsl",
"osl",