Cleanup: strip trailing space
[blender-addons.git] / space_view3d_pie_menus / pie_align_menu.py
blobf289bc8372475df7d5eaa792f332dd857d557a5c
1 # SPDX-FileCopyrightText: 2016-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 bl_info = {
6 "name": "Hotkey: 'Alt X'",
7 "description": "V/E/F Align tools",
8 "author": "pitiwazou, meta-androcto",
9 "version": (0, 1, 2),
10 "blender": (2, 80, 0),
11 "location": "Mesh Edit Mode",
12 "warning": "",
13 "doc_url": "",
14 "category": "Edit Align Pie"
17 import bpy
18 from bpy.types import (
19 Menu,
20 Operator,
22 from bpy.props import EnumProperty
25 # Pie Align - Alt + X
26 class PIE_MT_Align(Menu):
27 bl_idname = "PIE_MT_align"
28 bl_label = "Pie Align"
30 def draw(self, context):
31 layout = self.layout
32 pie = layout.menu_pie()
33 # 4 - LEFT
34 box = pie.split().box().column()
36 row = box.row(align=True)
37 row.label(text="X")
38 align_1 = row.operator("alignxyz.all", text="Neg")
39 align_1.axis = '0'
40 align_1.side = 'NEGATIVE'
42 row = box.row(align=True)
43 row.label(text="Y")
44 align_3 = row.operator("alignxyz.all", text="Neg")
45 align_3.axis = '1'
46 align_3.side = 'NEGATIVE'
48 row = box.row(align=True)
49 row.label(text="Z")
50 align_5 = row.operator("alignxyz.all", text="Neg")
51 align_5.axis = '2'
52 align_5.side = 'NEGATIVE'
53 # 6 - RIGHT
54 box = pie.split().box().column()
56 row = box.row(align=True)
57 row.label(text="X")
58 align_2 = row.operator("alignxyz.all", text="Pos")
59 align_2.axis = '0'
60 align_2.side = 'POSITIVE'
62 row = box.row(align=True)
63 row.label(text="Y")
64 align_4 = row.operator("alignxyz.all", text="Pos")
65 align_4.axis = '1'
66 align_4.side = 'POSITIVE'
68 row = box.row(align=True)
69 row.label(text="Z")
70 align_6 = row.operator("alignxyz.all", text="Pos")
71 align_6.axis = '2'
72 align_6.side = 'POSITIVE'
73 # 2 - BOTTOM
74 pie.operator("align.2xyz", text="Align To Y-0").axis = '1'
75 # 8 - TOP
76 pie.operator("align.selected2xyz", text="Align Y").axis = 'Y'
77 # 7 - TOP - LEFT
78 pie.operator("align.selected2xyz", text="Align X").axis = 'X'
79 # 9 - TOP - RIGHT
80 pie.operator("align.selected2xyz", text="Align Z").axis = 'Z'
81 # 1 - BOTTOM - LEFT
82 pie.operator("align.2xyz", text="Align To X-0").axis = '0'
83 # 3 - BOTTOM - RIGHT
84 pie.operator("align.2xyz", text="Align To Z-0").axis = '2'
87 # Align to X, Y, Z
88 class PIE_OT_AlignSelectedXYZ(Operator):
89 bl_idname = "align.selected2xyz"
90 bl_label = "Align to X, Y, Z"
91 bl_description = "Align Selected Along the chosen axis"
92 bl_options = {'REGISTER', 'UNDO'}
94 axis: EnumProperty(
95 name="Axis",
96 items=(
97 ('X', "X", "X Axis"),
98 ('Y', "Y", "Y Axis"),
99 ('Z', "Z", "Z Axis"),
101 description="Choose an axis for alignment",
102 default='X'
105 @classmethod
106 def poll(cls, context):
107 obj = context.active_object
108 return obj and obj.type == "MESH"
110 def execute(self, context):
111 values = {
112 'X': [(0, 1, 1), (True, False, False)],
113 'Y': [(1, 0, 1), (False, True, False)],
114 'Z': [(1, 1, 0), (False, False, True)],
116 chosen_value = values[self.axis][0]
117 constraint_value = values[self.axis][1]
118 bpy.ops.transform.resize(
119 value=chosen_value,
120 constraint_axis=constraint_value,
121 orient_type='GLOBAL',
122 mirror=False,
123 use_proportional_edit=False,
125 return {'FINISHED'}
128 # ################# #
129 # Align To 0 #
130 # ################# #
132 class PIE_OT_AlignToXYZ0(Operator):
133 bl_idname = "align.2xyz"
134 bl_label = "Align To X, Y or Z = 0"
135 bl_description = "Align Active Object To a chosen X, Y or Z equals 0 Location"
136 bl_options = {'REGISTER', 'UNDO'}
138 axis: EnumProperty(
139 name="Axis",
140 items=(
141 ('0', "X", "X Axis"),
142 ('1', "Y", "Y Axis"),
143 ('2', "Z", "Z Axis"),
145 description="Choose an axis for alignment",
146 default='0'
149 @classmethod
150 def poll(cls, context):
151 obj = context.active_object
152 return obj and obj.type == "MESH"
154 def execute(self, context):
155 bpy.ops.object.mode_set(mode='OBJECT')
156 align = int(self.axis)
157 for vert in bpy.context.object.data.vertices:
158 if vert.select:
159 vert.co[align] = 0
160 bpy.ops.object.editmode_toggle()
162 return {'FINISHED'}
165 # Align X Left
166 class PIE_OT_AlignXYZAll(Operator):
167 bl_idname = "alignxyz.all"
168 bl_label = "Align to Front/Back Axis"
169 bl_description = "Align to a Front or Back along the chosen Axis"
170 bl_options = {'REGISTER', 'UNDO'}
172 axis: EnumProperty(
173 name="Axis",
174 items=(
175 ('0', "X", "X Axis"),
176 ('1', "Y", "Y Axis"),
177 ('2', "Z", "Z Axis"),
179 description="Choose an axis for alignment",
180 default='0'
182 side: EnumProperty(
183 name="Side",
184 items=[
185 ('POSITIVE', "Front", "Align on the positive chosen axis"),
186 ('NEGATIVE', "Back", "Align acriss the negative chosen axis"),
188 description="Choose a side for alignment",
189 default='POSITIVE'
192 @classmethod
193 def poll(cls, context):
194 obj = context.active_object
195 return obj and obj.type == "MESH"
197 def execute(self, context):
199 bpy.ops.object.mode_set(mode='OBJECT')
200 count = 0
201 axe = int(self.axis)
202 for vert in bpy.context.object.data.vertices:
203 if vert.select:
204 if count == 0:
205 maxv = vert.co[axe]
206 count += 1
207 continue
208 count += 1
209 if self.side == 'POSITIVE':
210 if vert.co[axe] > maxv:
211 maxv = vert.co[axe]
212 else:
213 if vert.co[axe] < maxv:
214 maxv = vert.co[axe]
216 bpy.ops.object.mode_set(mode='OBJECT')
218 for vert in bpy.context.object.data.vertices:
219 if vert.select:
220 vert.co[axe] = maxv
221 bpy.ops.object.mode_set(mode='EDIT')
223 return {'FINISHED'}
226 classes = (
227 PIE_MT_Align,
228 PIE_OT_AlignSelectedXYZ,
229 PIE_OT_AlignToXYZ0,
230 PIE_OT_AlignXYZAll,
233 addon_keymaps = []
236 def register():
237 for cls in classes:
238 bpy.utils.register_class(cls)
240 wm = bpy.context.window_manager
241 if wm.keyconfigs.addon:
242 # Align
243 km = wm.keyconfigs.addon.keymaps.new(name='Mesh')
244 kmi = km.keymap_items.new('wm.call_menu_pie', 'X', 'PRESS', alt=True)
245 kmi.properties.name = "PIE_MT_align"
246 addon_keymaps.append((km, kmi))
249 def unregister():
250 for cls in classes:
251 bpy.utils.unregister_class(cls)
253 wm = bpy.context.window_manager
254 kc = wm.keyconfigs.addon
255 if kc:
256 for km, kmi in addon_keymaps:
257 km.keymap_items.remove(kmi)
258 addon_keymaps.clear()
261 if __name__ == "__main__":
262 register()