Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/modifiers/intern/MOD_ui_common.c')
-rw-r--r--source/blender/modifiers/intern/MOD_ui_common.c426
1 files changed, 426 insertions, 0 deletions
diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c
new file mode 100644
index 00000000000..973afe5fef6
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_ui_common.c
@@ -0,0 +1,426 @@
+/* This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include <string.h>
+
+#include "BLI_listbase.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_context.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_screen.h"
+
+#include "DNA_object_force_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "ED_object.h"
+
+#include "BLT_translation.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "MOD_modifiertypes.h"
+#include "MOD_ui_common.h" /* Self include */
+
+static Object *get_modifier_object(const bContext *C)
+{
+ SpaceProperties *sbuts = CTX_wm_space_properties(C);
+ if (sbuts != NULL && (sbuts->pinid != NULL) && GS(sbuts->pinid->name) == ID_OB) {
+ return (Object *)sbuts->pinid;
+ }
+ else {
+ return CTX_data_active_object(C);
+ }
+}
+
+/**
+ * Poll function so these modifier panels don't show for other object types with modifiers (only
+ * grease pencil currently).
+ */
+static bool modifier_ui_poll(const bContext *C, PanelType *UNUSED(pt))
+{
+ Object *ob = get_modifier_object(C);
+
+ return (ob != NULL) && (ob->type != OB_GPENCIL);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Panel Drag and Drop, Expansion Saving
+ * \{ */
+
+/**
+ * Move a modifier to the index it's moved to after a drag and drop.
+ */
+static void modifier_reorder(bContext *C, Panel *panel, int new_index)
+{
+ Object *ob = get_modifier_object(C);
+
+ ModifierData *md = BLI_findlink(&ob->modifiers, panel->runtime.list_index);
+ PointerRNA props_ptr;
+ wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_modifier_move_to_index", false);
+ WM_operator_properties_create_ptr(&props_ptr, ot);
+ RNA_string_set(&props_ptr, "modifier", md->name);
+ RNA_int_set(&props_ptr, "index", new_index);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
+ WM_operator_properties_free(&props_ptr);
+}
+
+static short get_modifier_expand_flag(const bContext *C, Panel *panel)
+{
+ Object *ob = get_modifier_object(C);
+ ModifierData *md = BLI_findlink(&ob->modifiers, panel->runtime.list_index);
+ return md->ui_expand_flag;
+}
+
+static void set_modifier_expand_flag(const bContext *C, Panel *panel, short expand_flag)
+{
+ Object *ob = get_modifier_object(C);
+ ModifierData *md = BLI_findlink(&ob->modifiers, panel->runtime.list_index);
+ md->ui_expand_flag = expand_flag;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Modifier Panel Layouts
+ * \{ */
+
+/**
+ * Draw modifier error message.
+ */
+void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
+{
+ ModifierData *md = ptr->data;
+ if (md->error) {
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiItemL(row, IFACE_(md->error), ICON_ERROR);
+ }
+}
+
+/**
+ * Gets RNA pointers for the active object and the panel's modifier data. Also locks
+ * the layout if the modifer is from a linked object, and sets the context pointer.
+ */
+#define ERROR_LIBDATA_MESSAGE TIP_("External library data")
+void modifier_panel_get_property_pointers(const bContext *C,
+ Panel *panel,
+ PointerRNA *r_ob_ptr,
+ PointerRNA *r_md_ptr)
+{
+ Object *ob = get_modifier_object(C);
+
+ ModifierData *md = BLI_findlink(&ob->modifiers, panel->runtime.list_index);
+
+ RNA_pointer_create(&ob->id, &RNA_Modifier, md, r_md_ptr);
+
+ if (r_ob_ptr != NULL) {
+ RNA_pointer_create(&ob->id, &RNA_Object, ob, r_ob_ptr);
+ }
+
+ uiBlock *block = uiLayoutGetBlock(panel->layout);
+ UI_block_lock_set(
+ block, BKE_object_obdata_is_libdata(ob) || ID_IS_LINKED(ob), ERROR_LIBDATA_MESSAGE);
+
+ uiLayoutSetContextPointer(panel->layout, "modifier", r_md_ptr);
+}
+
+/**
+ * Helper function for modifier layouts to draw vertex group settings.
+ */
+void modifier_vgroup_ui(uiLayout *layout,
+ PointerRNA *ptr,
+ PointerRNA *ob_ptr,
+ const char *vgroup_prop,
+ const char *invert_vgroup_prop,
+ const char *text)
+{
+ bool has_vertex_group = RNA_string_length(ptr, vgroup_prop) != 0;
+
+ uiLayout *row = uiLayoutRow(layout, true);
+ uiItemPointerR(row, ptr, vgroup_prop, ob_ptr, "vertex_groups", text, ICON_NONE);
+ if (invert_vgroup_prop != NULL) {
+ uiLayout *sub = uiLayoutRow(row, true);
+ uiLayoutSetActive(sub, has_vertex_group);
+ uiLayoutSetPropDecorate(sub, false);
+ uiItemR(sub, ptr, invert_vgroup_prop, 0, "", ICON_ARROW_LEFTRIGHT);
+ }
+ if (uiLayoutGetPropDecorate(layout)) {
+ uiItemL(row, "", ICON_BLANK1);
+ }
+}
+
+/**
+ * Check whether Modifier is a simulation or not. Used for switching to the
+ * physics/particles context tab.
+ */
+static int modifier_is_simulation(ModifierData *md)
+{
+ /* Physic Tab */
+ if (ELEM(md->type,
+ eModifierType_Cloth,
+ eModifierType_Collision,
+ eModifierType_Fluidsim,
+ eModifierType_Fluid,
+ eModifierType_Softbody,
+ eModifierType_Surface,
+ eModifierType_DynamicPaint)) {
+ return 1;
+ }
+ /* Particle Tab */
+ else if (md->type == eModifierType_ParticleSystem) {
+ return 2;
+ }
+ else {
+ return 0;
+ }
+}
+
+static bool modifier_can_delete(ModifierData *md)
+{
+ /* fluid particle modifier can't be deleted here */
+ if (md->type == eModifierType_ParticleSystem) {
+ short particle_type = ((ParticleSystemModifierData *)md)->psys->part->type;
+ if (ELEM(particle_type,
+ PART_FLUID,
+ PART_FLUID_FLIP,
+ PART_FLUID_FOAM,
+ PART_FLUID_SPRAY,
+ PART_FLUID_BUBBLE,
+ PART_FLUID_TRACER,
+ PART_FLUID_SPRAYFOAM,
+ PART_FLUID_SPRAYBUBBLE,
+ PART_FLUID_FOAMBUBBLE,
+ PART_FLUID_SPRAYFOAMBUBBLE)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void modifier_ops_extra_draw(bContext *UNUSED(C), uiLayout *layout, void *md_v)
+{
+ ModifierData *md = (ModifierData *)md_v;
+
+ uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
+
+ uiItemEnumO(layout,
+ "OBJECT_OT_modifier_apply",
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"),
+ 0,
+ "apply_as",
+ MODIFIER_APPLY_DATA);
+
+ if (BKE_modifier_is_same_topology(md) && !BKE_modifier_is_non_geometrical(md)) {
+ uiItemEnumO(layout,
+ "OBJECT_OT_modifier_apply",
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply As Shapekey"),
+ ICON_SHAPEKEY_DATA,
+ "apply_as",
+ MODIFIER_APPLY_SHAPE);
+ }
+
+ if (!ELEM(md->type,
+ eModifierType_Fluidsim,
+ eModifierType_Softbody,
+ eModifierType_ParticleSystem,
+ eModifierType_Cloth,
+ eModifierType_Fluid)) {
+ uiItemO(layout,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Duplicate"),
+ ICON_DUPLICATE,
+ "OBJECT_OT_modifier_copy");
+ }
+
+ if (modifier_can_delete(md) && !modifier_is_simulation(md)) {
+ uiItemO(layout,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete"),
+ ICON_X,
+ "OBJECT_OT_modifier_remove");
+ }
+}
+
+static void modifier_panel_header(const bContext *C, Panel *panel)
+{
+ uiLayout *row, *sub;
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ptr;
+ Object *ob = get_modifier_object(C);
+
+ /* Don't use #modifier_panel_get_property_pointers, we don't want to lock the header. */
+ ModifierData *md = BLI_findlink(&ob->modifiers, panel->runtime.list_index);
+ RNA_pointer_create(&ob->id, &RNA_Modifier, md, &ptr);
+ uiLayoutSetContextPointer(panel->layout, "modifier", &ptr);
+
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+ Scene *scene = CTX_data_scene(C);
+ int index = panel->runtime.list_index;
+ bool narrow_panel = (panel->sizex < UI_UNIT_X * 8 && panel->sizex != 0);
+
+ /* Modifier Icon. */
+ row = uiLayoutRow(layout, false);
+ if (mti->isDisabled && mti->isDisabled(scene, md, 0)) {
+ uiLayoutSetRedAlert(row, true);
+ }
+ uiItemL(row, "", RNA_struct_ui_icon(ptr.type));
+
+ /* Modifier Name. */
+ if (!narrow_panel) {
+ uiItemR(layout, &ptr, "name", 0, "", ICON_NONE);
+ }
+
+ /* Switch context buttons. */
+ if (modifier_is_simulation(md) == 1) {
+ uiItemStringO(
+ layout, "", ICON_PROPERTIES, "WM_OT_properties_context_change", "context", "PHYSICS");
+ }
+ else if (modifier_is_simulation(md) == 2) {
+ uiItemStringO(
+ layout, "", ICON_PROPERTIES, "WM_OT_properties_context_change", "context", "PARTICLES");
+ }
+
+ /* Mode switching buttons. */
+ row = uiLayoutRow(layout, true);
+ if (ob->type == OB_MESH) {
+ int last_cage_index;
+ int cage_index = BKE_modifiers_get_cage_index(scene, ob, &last_cage_index, 0);
+ if (BKE_modifier_supports_cage(scene, md) && (index <= last_cage_index)) {
+ sub = uiLayoutRow(row, true);
+ if (index < cage_index || !BKE_modifier_couldbe_cage(scene, md)) {
+ uiLayoutSetActive(sub, false);
+ }
+ uiItemR(sub, &ptr, "show_on_cage", 0, "", ICON_NONE);
+ }
+ } /* Tessellation point for curve-typed objects. */
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ if (mti->type != eModifierTypeType_Constructive) {
+ /* Constructive modifiers tessellates curve before applying. */
+ uiItemR(layout, &ptr, "use_apply_on_spline", 0, "", ICON_NONE);
+ }
+ }
+ /* Collision and Surface are always enabled, hide buttons. */
+ if (((md->type != eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) &&
+ (md->type != eModifierType_Surface)) {
+ if (mti->flags & eModifierTypeFlag_SupportsEditmode) {
+ sub = uiLayoutRow(row, true);
+ uiLayoutSetActive(sub, (md->mode & eModifierMode_Realtime));
+ uiItemR(sub, &ptr, "show_in_editmode", 0, "", ICON_NONE);
+ }
+ uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE);
+ uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE);
+ }
+
+ row = uiLayoutRow(layout, false);
+ uiItemMenuF(row, "", ICON_DOWNARROW_HLT, modifier_ops_extra_draw, md);
+
+ /* Some padding at the end, so the buttons aren't too close to the drag button. */
+ uiItemS(layout);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Modifier Registration Helpers
+ * \{ */
+
+/**
+ * Create a panel in the context's region
+ */
+PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
+{
+ /* Get the name for the modifier's panel. */
+ char panel_idname[BKE_ST_MAXNAME];
+ BKE_modifier_type_panel_id(type, panel_idname);
+
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
+
+ strcpy(panel_type->idname, panel_idname);
+ strcpy(panel_type->label, "");
+ strcpy(panel_type->context, "modifier");
+ strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+
+ panel_type->draw_header = modifier_panel_header;
+ panel_type->draw = draw;
+ panel_type->poll = modifier_ui_poll;
+
+ /* Give the panel the special flag that says it was built here and corresponds to a
+ * modifer rather than a PanelType. */
+ panel_type->flag = PNL_LAYOUT_HEADER_EXPAND | PNL_DRAW_BOX | PNL_INSTANCED;
+ panel_type->reorder = modifier_reorder;
+ panel_type->get_list_data_expand_flag = get_modifier_expand_flag;
+ panel_type->set_list_data_expand_flag = set_modifier_expand_flag;
+
+ BLI_addtail(&region_type->paneltypes, panel_type);
+
+ return panel_type;
+}
+
+/**
+ * Add a shild panel to the parent.
+ *
+ * \note To create the panel type's idname, it appends the \a name argument to the \a parent's
+ * idname.
+ */
+PanelType *modifier_subpanel_register(ARegionType *region_type,
+ const char *name,
+ const char *label,
+ PanelDrawFn draw_header,
+ PanelDrawFn draw,
+ PanelType *parent)
+{
+ /* Create the subpanel's ID name. */
+ char panel_idname[BKE_ST_MAXNAME];
+ strcpy(panel_idname, parent->idname);
+ strcat(panel_idname, "_");
+ strcat(panel_idname, name);
+
+ PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname);
+
+ strcpy(panel_type->idname, panel_idname);
+ strcpy(panel_type->label, label);
+ strcpy(panel_type->context, "modifier");
+ strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+
+ panel_type->draw_header = draw_header;
+ panel_type->draw = draw;
+ panel_type->poll = modifier_ui_poll;
+ panel_type->flag = (PNL_DEFAULT_CLOSED | PNL_DRAW_BOX);
+
+ BLI_assert(parent != NULL);
+ strcpy(panel_type->parent_id, parent->idname);
+ panel_type->parent = parent;
+ BLI_addtail(&parent->children, BLI_genericNodeN(panel_type));
+ BLI_addtail(&region_type->paneltypes, panel_type);
+
+ return panel_type;
+}
+
+/** \} */