class EPOCHListItem(bpy.types.PropertyGroup): """ Group of properties representing an item in the list """ name: prop.StringProperty( name="Name", description="A name for this item", default="Untitled") id: prop.StringProperty( name="id", description="A description for this item", default="Empty") min_y: prop.FloatProperty( name="code for icon", description="", default=0.0) max_y: prop.FloatProperty( name="code for icon", description="", default=0.0) height: prop.FloatProperty( name="height of epoch row", description="", default=0.0) epoch_color: prop.StringProperty( name="color of epoch row", description="", default="Empty") use_toggle: BoolProperty(name="", default=True) is_locked: BoolProperty(name="", default=True) is_selected: BoolProperty(name="", default=False) epoch_soloing: BoolProperty(name="", default=False) rm_models: BoolProperty(name="", default=False) reconstruction_on: BoolProperty(name="", default=False) unique_id: StringProperty(default="") epoch_RGB_color: FloatVectorProperty( name="epoch_color", subtype="COLOR", size=3, min=0.0, max=1.0, default=(0.5, 0.5, 0.5) ) wire_color: FloatVectorProperty( name="wire", subtype='COLOR', default=(0.2, 0.2, 0.2), min=0.0, max=1.0, description="wire color of the group" )
class TemplateAttributeDefault(types.PropertyGroup): @property def hash(self): return str(hash(getattr(self, self.value_name))) @property def value_name(self): return "value_{}".format(self.type.lower()) @property def value(self): return getattr(self, self.value_name) @value.setter def value(self, value): setattr(self, self.value_name, value) name = props.StringProperty( description="Name of template attribute default value") type = props.EnumProperty( description="Data type of template attribute default value", items=TYPE_ENUMS) value_int = props.IntProperty() value_float = props.FloatProperty() value_string = props.StringProperty() value_bool = props.BoolProperty()
class Mafia4ds_GlobalMeshProperties(types.PropertyGroup): Type: props.EnumProperty( name="Type", items=[ ("0x01", "Visual", ""), #("0x05", "Sector", ""), ("0x06", "Dummy", ""), #("0x07", "Target", ""), #("0x0a", "Joint", "") ]) VisualType: props.EnumProperty( name="Visual Type", items=[ ("0x00", "Mesh", ""), #("0x02", "SingleMesh", ""), #("0x03", "SingleMorph", ""), #("0x04", "Billboard", ""), #("0x05", "Morph", ""), #("0x06", "Glow", ""), #("0x08", "Mirror", "") ]) Parameters: props.StringProperty(name="Parameters", default="") RenderFlags: props.IntProperty(name="Render Flags", default=0x2a00) CullingFlags: props.IntProperty(name="Culling Flags", default=0x09) InstanceIdx: props.IntProperty(name="Instance Idx", default=0) LodRatio: props.FloatProperty(name="Lod Ratio", default=0.0)
def resizeAll(context): size = p.FloatProperty(name="Units", default=1) dimensions = mathutils.Vector((self.size, self.size, self.size)) for probe in all_active_lightprobes(): probe.dimensions = dimensions
class NODE_OT_SynchroniseTextBlocks(types.Operator): bl_idname = "hive.synchronise_text_blocks" bl_label = "Reload From Text Block" node_id = props.IntProperty() mouse_x = props.FloatProperty() mouse_y = props.FloatProperty() @classmethod def poll(cls, context): return True def execute(self, context): node_tree = context.space_data.edit_tree blend_manager.reload_node_tree_from_source(node_tree) return {'FINISHED'}
class NODE_OT_GrabHiveNode(types.Operator): bl_idname = "hive.grab_hive_node" bl_label = "Grab Hive Node" node_id = props.IntProperty() mouse_x = props.FloatProperty() mouse_y = props.FloatProperty() @classmethod def poll(cls, context): return True def invoke(self, context, event): context.window_manager.modal_handler_add(self) return {'RUNNING_MODAL'} def modal(self, context, event): node_tree = context.space_data.edit_tree gui_node_manager = blend_manager.get_gui_manager_for_node_tree( node_tree) node_manager = gui_node_manager.node_manager # Get nodes node = gui_node_manager.gui_node_id_to_node[self.node_id] if event.type == 'MOUSEMOVE': mouse_x, mouse_y = context.space_data.cursor_location position = mouse_x / LOCATION_DIVISOR, mouse_y / LOCATION_DIVISOR node_manager.reposition_node(node, position) elif event.type in ('LEFTMOUSE', 'RETURN'): return {'FINISHED'} elif event.type == 'RIGHTMOUSE': node_manager.reposition_node(node, (0, 0)) return {'FINISHED'} elif event.type == 'ESC': return {'CANCELLED'} return {'RUNNING_MODAL'}
class ParameterGroup(types.PropertyGroup): name = props.StringProperty(name="Name") data_type = props.EnumProperty(items=enum_data_types) value_str = props.StringProperty() value_int = props.IntProperty() value_bool = props.BoolProperty() value_float = props.FloatProperty() @property def value(self): return getattr(self, "value_{}".format(self.data_type)) @value.setter def value(self, value): setattr(self, "value_{}".format(self.data_type), value)
class ResizeAllOperator(bpy.types.Operator): bl_idname = "object.resize_all_lightprobes" bl_label = "Resize Light Probes" bl_options = {"REGISTER", "UNDO"} size = p.FloatProperty(name="Units", default=1) def invoke(self, context, event): return self.execute(context) def execute(self, context): dimensions = mathutils.Vector((self.size, self.size, self.size)) for probe in all_active_lightprobes(): probe.dimensions = dimensions return {"FINISHED"}
class EMListItem(bpy.types.PropertyGroup): """ Group of properties representing an item in the list """ name: prop.StringProperty( name="Name", description="A name for this item", default="Untitled") description: prop.StringProperty( name="Description", description="A description for this item", default="Empty") icon: prop.StringProperty( name="code for icon", description="", default="RESTRICT_INSTANCED_ON") url: prop.StringProperty( name="url", description="An url behind this item", default="Empty") shape: prop.StringProperty( name="shape", description="The shape of this item", default="Empty") y_pos: prop.FloatProperty( name="y_pos", description="The y_pos of this item", default=0.0) epoch: prop.StringProperty( name="code for epoch", description="", default="Empty") id_node: prop.StringProperty( name="id node", description="", default="Empty")
class _PieMenu(ExecuteString): # {idname: index, ...} _last_item_index = {} idname = props.StringProperty(name="ID Name", get=prop_idname_get, set=prop_idname_set) active = props.BoolProperty(name="Active", description="Activate or deactivate menu", default=True) show_expanded = props.BoolProperty() poll_string = props.StringProperty( name="Poll", description="e.g.\nreturn context.mode == 'EDIT_MESH'", ) init_string = props.StringProperty(name="Init", ) label = props.StringProperty( name="Label", description="Menu title", ) draw_type = props.EnumProperty(name="Draw Type", items=[('SIMPLE', "Simple", ""), ('BOX', "Box", ""), ('CIRCLE', "Circle", "")], default='BOX', get=prop_draw_type_get, set=prop_draw_type_set) icon_scale = props.FloatProperty( name="Icon Scale", default=1.0, min=1.0, max=10.0, ) icon_expand = props.FloatProperty( name="Icon Expand", default=0.0, min=-1.0, max=1.0, ) radius = props.IntProperty(name="Radius", description="Pie menu size in pixels", min=0, default=0, get=prop_radius_get, set=prop_radius_set) quick_action = props.EnumProperty( name="Quick Action", items=[('NONE', "None", ""), ('LAST', "Last", ""), ('FIXED', "Fixed", "")], default='NONE', ) quick_action_index = props.IntProperty( name="Quick Action Index", description="", min=0, max=16, default=0, ) highlight = props.EnumProperty( name="Highlight", items=[('NONE', "None", ""), ('LAST', "Last", ""), ('FIXED', "Fixed", "")], default='NONE', ) highlight_index = props.IntProperty( name="Highlight Index", description="", min=0, max=16, default=0, ) translate = props.BoolProperty( name="Translate", default=True, ) items_num = props.EnumProperty( name="Number of Items", items=[('4', "4", ""), ('8', "8", ""), ('16', "16", "")], default='8', ) # menu_items = props.CollectionProperty( # name="Items", type=PieMenuItem) menu_items = [] # ↑継承で上書きする場合に問題が発生する item_order = props.EnumProperty( name="Item Order", items=[ ('CW', "Clockwise", "[0, 1, 2, 3, 4, 5, 6, 7]"), ('CW6', "Clockwise 6", "[4, 5, 6, 7, 0, 1, 2, 3] Start from six o'clock"), ('OFFICIAL', "Official", "[3, 5, 1, 7, 2, 6, 0, 4]"), ('MODIFIED', "Modified", "[3, 7, 1, 5, 2, 4, 0, 6]"), ], default='OFFICIAL', ) next = props.StringProperty( name="Next Menu", description="Shortcut: wheel down", ) prev = props.StringProperty( name="Previous Menu", description="Shortcut: wheel up", ) # 上書き radius_ = props.IntProperty() quick_action_index_ = props.IntProperty() highlight_index_ = props.IntProperty() # 描画時に使用 active_index = props.IntProperty(default=-1) active_item_index = props.IntProperty(default=-1) # -1: None is_valid_click = props.BoolProperty(default=True) co = props.FloatVectorProperty(subtype='XYZ', size=2) current_items_type = props.StringProperty( ) # "", "shift", "ctrl", "alt", "oskey" @property def item_boundary_angles(self): return self["item_boundary_angles"] @item_boundary_angles.setter def item_boundary_angles(self, value): self["item_boundary_angles"] = value @property def current_items(self): mod = self.current_items_type items = [] for item in self.menu_items: if item.active: if mod == "shift" and item.shift.active: items.append(item.shift) elif mod == "ctrl" and item.ctrl.active: items.append(item.ctrl) else: items.append(item) ls = [] for i in self["current_items_indices"]: if i == -1: ls.append(None) else: item = items[i] if item.type == 'SPACER': ls.append(None) else: ls.append(item) return ls def poll(self, context, event=None): if self.poll_string: return bool(self.exec_string("poll_string", context, event)) else: return True def init(self, context): if self.init_string: self.exec_string("init_string", context, None) @staticmethod def calc_item_indices(item_order, num): def sort_cw(): for n in (4, 8, 16): if num <= n: return list(range(num)) + [-1] * (n - num) def sort_cw6(): indices = sort_cw() n = int(len(indices) / 2) indices = indices[n:] + indices[:n] return indices def sort_official_modified(modified=False): if modified: if num <= 4: order = [3, 1, 2, 0] elif num <= 8: order = [3, 7, 1, 5, 2, 4, 0, 6] else: # if num <= 16: order = [ 3, 15, 7, 11, 1, 9, 5, 13, 2, 12, 4, 8, 0, 10, 6, 14 ] else: if num <= 4: order = [3, 1, 2, 0] elif num <= 8: order = [3, 5, 1, 7, 2, 6, 0, 4] else: # if num <= 16: order = [ 3, 15, 5, 11, 1, 9, 7, 13, 2, 12, 6, 8, 0, 10, 4, 14 ] indices = list(range(num)) + [-1] * (len(order) - num) return [indices[i] for i in order] if num > 16: raise ValueError() if item_order == 'CW': indices = sort_cw() elif item_order == 'CW6': indices = sort_cw6() elif item_order == 'OFFICIAL': indices = sort_official_modified() else: # elif self.item_order == 'MODIFIED': indices = sort_official_modified(True) return indices def update_current_items(self, context, op): mod = op.last_modifier() self.current_items_type = mod items = [] for item in self.menu_items: if item.active: if mod == "shift" and item.shift.active: items.append(item.shift) elif mod == "ctrl" and item.ctrl.active: items.append(item.ctrl) else: items.append(item) items = items[:16] num = len(items) indices = self.calc_item_indices(self.item_order, num) self["current_items_indices"] = indices # quick_action_index, highlight_index if num <= 4: n = 4 elif num <= 8: n = 8 else: # if num <= 16: n = 16 indices_ = self.calc_item_indices(self.item_order, n) for attr in ["quick_action_index", "highlight_index"]: index = getattr(self, attr) if 0 <= index < num: setattr(self, attr + "_", indices_.index(index)) # poll() for i in indices: if i != -1: item = items[i] item.enabled = item.poll(context) # calc boundaries num = len(indices) pie_angle = math.pi * 2 / num item_boundary_angles = [[0.0, 0.0] for i in range(num)] current_items = self.current_items for i, item in enumerate(current_items): if not item: continue angle = math.pi * 0.5 - pie_angle * i if angle < -1e-5: angle += math.pi * 2 # CCW side for k in range(1, num + 1): if current_items[i - k]: ang = angle + pie_angle * k * 0.5 item_boundary_angles[i][0] = ang break # CW side for k in range(1, num + 1): if current_items[(i + k) % num]: ang = angle - pie_angle * k * 0.5 item_boundary_angles[i][1] = ang break self.item_boundary_angles = item_boundary_angles def correct_radius(self): """Item同士が重ならないようにMenu半径を大きくする。 値は redius_ に格納する """ addon_prefs = pie_menu.addon_preferences radius = self.get("radius", addon_prefs.menu_radius) current_items = self.current_items if len(current_items) == 0: return pie_angle = math.pi * 2 / len(current_items) widget_unit = vawm.widget_unit() if self.draw_type == 'SIMPLE': n = len(current_items) / 4 r = widget_unit * (n - 0.5) + addon_prefs.item_min_space * n self.radius_ = max(r, radius) else: icon_box_size = widget_unit * self.icon_scale if self.draw_type == 'CIRCLE': # >>> (r + icon_size / 2) * math.sin(pie_angle / 2) = \ # (icon_size + item_min_space) / 2 r = (icon_box_size + addon_prefs.item_min_space) / 2 / \ math.sin(pie_angle / 2) - icon_box_size / 2 self.radius_ = max(r, radius) else: # 'BOX' # >>> (r + icon_size / 2) * math.sin(pie_angle) = \ # icon_size + item_min_space r = (icon_box_size + addon_prefs.item_min_space) / \ math.sin(pie_angle) - icon_box_size / 2 self.radius_ = max(r, radius) def calc_active(self, mco): """:rtype: (int, int)""" addon_prefs = pie_menu.addon_preferences current_items = self.current_items if not current_items: return -1, -1 vec = mco - self.co if vec.length < addon_prefs.menu_radius_center: active_index = -1 else: idx = 0 for i, item in enumerate(current_items): if not item: continue idx = i a1, a2 = self.item_boundary_angles[i] a1 += 1e-4 a2 -= 1e-4 v1 = (math.cos(a1), math.sin(a1)) v2 = (math.cos(a2), math.sin(a2)) if cross2d(v2, vec) >= 0 and cross2d(vec, v1) >= 0: active_index = i break else: active_index = idx active_item_index = -1 if active_index == -1: if self.quick_action == 'LAST': last_item_index = self.get_last_item_index() if 0 <= last_item_index < len(current_items): item = current_items[last_item_index] if item: active_item_index = last_item_index elif self.quick_action == 'FIXED': if 0 <= self.quick_action_index_ < len(current_items): item = current_items[self.quick_action_index_] if item: active_item_index = self.quick_action_index_ else: item = current_items[active_index] if item: active_item_index = active_index return active_index, active_item_index def update_active(self, mco, mco_press): """active_indexとactive_itemを更新。 """ self.active_index, self.active_item_index = self.calc_active(mco) if mco_press is not None: i, _ = self.calc_active(mco_press) self.is_valid_click = i == self.active_index else: self.is_valid_click = True def get_last_item_index(self): return self._last_item_index.get(self.idname, -1) def set_last_item_index(self, index): self._last_item_index[self.idname] = index def clear_last_item_idnex(self): if self.idname in self._last_item_index: del self._last_item_index[self.idname] def draw_ui(self, context, layout): if self.show_expanded: main_layout = layout.box().column() else: main_layout = layout.column() main_layout.context_pointer_set("pie_menu", self) row = main_layout.row() icon = 'TRIA_DOWN' if self.show_expanded else 'TRIA_RIGHT' sub = row.row() sub.alignment = 'LEFT' sub.prop(self, "show_expanded", text="", icon=icon, emboss=False) sub.prop(self, "active", text="") sub = row.row() if not self.active: sub.active = False sub.prop(self, "label", text="") sub2 = sub.row() """:type: bpy.types.UILayout""" if not self.idname: sub2.alert = True sub2.prop(self, "name", text="ID Name") sub = row.row(align=True) sub.alignment = 'RIGHT' sub1 = sub.row(align=True) op = sub1.operator(ops.WM_OT_pie_menu_menu_copy.bl_idname, text="", icon='COPYDOWN') sub2 = sub.row(align=True) op = sub2.operator(ops.WM_OT_pie_menu_menu_paste.bl_idname, text="", icon='PASTEDOWN') sub1 = sub.row(align=True) op = sub1.operator(ops.WM_OT_pie_menu_menu_move.bl_idname, text="", icon='TRIA_UP') op.direction = -1 sub2 = sub.row(align=True) op = sub2.operator(ops.WM_OT_pie_menu_menu_move.bl_idname, text="", icon='TRIA_DOWN') op.direction = 1 sub.operator(ops.WM_OT_pie_menu_menu_remove.bl_idname, text="", icon='X') if not self.show_expanded: return column = main_layout.column() row = column.row() split = row.split() sp_column1 = split.column() sp_column2 = split.column() draw_property(sp_column1, self, "draw_type", unset=True, context_attr="pie_menu") draw_property(sp_column1, self, "icon_scale") draw_property(sp_column1, self, "icon_expand") draw_property(sp_column1, self, "radius", unset=True, context_attr="pie_menu") draw_property(sp_column1, self, "translate") draw_property(sp_column1, self, "item_order") sp_column2.label("Quick Action:") draw_property(sp_column2, self, "quick_action", text="", context_attr="pie_menu") sub = sp_column2.row() if self.quick_action != 'FIXED': sub.active = False draw_property(sub, self, "quick_action_index", context_attr="pie_menu") sp_column2.label("Highlight:") draw_property(sp_column2, self, "highlight", text="", context_attr="pie_menu") sub = sp_column2.row() if self.highlight != 'FIXED': sub.active = False draw_property(sub, self, "highlight_index", context_attr="pie_menu") draw_separator(column) draw_property(column, self, "poll_string", "Poll Function", paste=True, context_attr="pie_menu") draw_property(column, self, "init_string", "Init Function", paste=True, context_attr="pie_menu") draw_separator(column) column = main_layout.column() for i, item in enumerate(self.menu_items): col = column.column() item.draw_ui(context, col, self, i) row = column.row() row.alignment = 'LEFT' op = row.operator(ops.WM_OT_pie_menu_item_add.bl_idname, text="Add Item", icon='ZOOMIN')