1 # SPDX-FileCopyrightText: 2012-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
6 "name": "Extra Objects",
7 "author": "Multiple Authors",
10 "location": "View3D > Add > Curve > Extra Objects",
11 "description": "Add extra curve object types",
13 "doc_url": "{BLENDER_MANUAL_URL}/addons/add_curve/extra_objects.html",
14 "category": "Add Curve",
19 importlib
.reload(add_curve_aceous_galore
)
20 importlib
.reload(add_curve_spirals
)
21 importlib
.reload(add_curve_torus_knots
)
22 importlib
.reload(add_surface_plane_cone
)
23 importlib
.reload(add_curve_curly
)
24 importlib
.reload(beveltaper_curve
)
25 importlib
.reload(add_curve_celtic_links
)
26 importlib
.reload(add_curve_braid
)
27 importlib
.reload(add_curve_simple
)
28 importlib
.reload(add_curve_spirofit_bouncespline
)
31 from . import add_curve_aceous_galore
32 from . import add_curve_spirals
33 from . import add_curve_torus_knots
34 from . import add_surface_plane_cone
35 from . import add_curve_curly
36 from . import beveltaper_curve
37 from . import add_curve_celtic_links
38 from . import add_curve_braid
39 from . import add_curve_simple
40 from . import add_curve_spirofit_bouncespline
43 from bpy
.types
import (
47 from bpy
.props
import (
53 def convert_old_presets(data_path
, msg_data_path
, old_preset_subdir
,
54 new_preset_subdir
, fixdic
={}, ext
=".py"):
59 def convert_presets(self
, context
):
60 if not getattr(self
, data_path
, False):
64 target_path
= os
.path
.join("presets", old_preset_subdir
)
65 target_path
= bpy
.utils
.user_resource('SCRIPTS', path
=target_path
)
67 # created an anytype op to run against preset
68 op
= type('', (), {})()
70 files
= [f
for f
in os
.listdir(target_path
) if f
.endswith(ext
)]
72 print("No old presets in %s" % target_path
)
73 setattr(self
, msg_data_path
, "No old presets")
76 new_target_path
= os
.path
.join("presets", new_preset_subdir
)
77 new_target_path
= bpy
.utils
.user_resource('SCRIPTS', path
=new_target_path
, create
=True)
79 file = open(os
.path
.join(target_path
, f
))
81 if line
.startswith("op."):
84 for key
, items
in fixdic
.items():
85 if hasattr(op
, key
) and isinstance(getattr(op
, key
), int):
86 setattr(op
, key
, items
[getattr(op
, key
)])
88 new_file_path
= os
.path
.join(new_target_path
, f
)
89 if os
.path
.isfile(new_file_path
):
91 print("Preset %s already exists, passing..." % f
)
93 file_preset
= open(new_file_path
, 'w')
94 file_preset
.write("import bpy\n")
95 file_preset
.write("op = bpy.context.active_operator\n")
97 for prop
, value
in vars(op
).items():
98 if isinstance(value
, str):
99 file_preset
.write("op.%s = '%s'\n" % (prop
, str(value
)))
101 file_preset
.write("op.%s = %s\n" % (prop
, str(value
)))
103 print("Writing new preset to %s" % new_file_path
)
105 setattr(self
, msg_data_path
, "Converted %d old presets" % len(files
))
108 return convert_presets
113 class CurveExtraObjectsAddonPreferences(AddonPreferences
):
117 "spiral_type": ['ARCH', 'ARCH', 'LOG', 'SPHERE', 'TORUS'],
118 "curve_type": ['POLY', 'NURBS'],
119 "spiral_direction": ['COUNTER_CLOCKWISE', 'CLOCKWISE']
121 update_spiral_presets_msg
: StringProperty(
122 default
="Nothing to do"
124 update_spiral_presets
: BoolProperty(
125 name
="Update Old Presets",
126 description
="Update presets to reflect data changes",
128 update
=convert_old_presets(
129 "update_spiral_presets", # this props name
130 "update_spiral_presets_msg", # message prop
131 "operator/curve.spirals",
132 "curve_extras/curve.spirals",
136 show_menu_list
: BoolProperty(
138 description
="Show/Hide the Add Menu items",
142 def draw(self
, context
):
145 box
.label(text
="Spirals:")
147 if self
.update_spiral_presets
:
148 box
.label(text
=self
.update_spiral_presets_msg
, icon
="FILE_TICK")
150 box
.prop(self
, "update_spiral_presets")
152 icon_1
= "TRIA_RIGHT" if not self
.show_menu_list
else "TRIA_DOWN"
154 box
.prop(self
, "show_menu_list", emboss
=False, icon
=icon_1
)
156 if self
.show_menu_list
:
157 box
.label(text
="Items located in the Add Menu > Curve (default shortcut Ctrl + A):",
159 box
.label(text
="2D Objects:", icon
="LAYER_ACTIVE")
160 box
.label(text
="Angle, Arc, Circle, Distance, Ellipse, Line, Point, Polygon,",
162 box
.label(text
="Polygon ab, Rectangle, Rhomb, Sector, Segment, Trapezoid",
164 box
.label(text
="Curve Profiles:", icon
="LAYER_ACTIVE")
165 box
.label(text
="Arc, Arrow, Cogwheel, Cycloid, Flower, Helix (3D),",
167 box
.label(text
="Noise (3D), Nsided, Profile, Rectangle, Splat, Star",
169 box
.label(text
="Curve Spirals:", icon
="LAYER_ACTIVE")
170 box
.label(text
="Archemedian, Logarithmic, Spheric, Torus",
172 box
.label(text
="Knots:", icon
="LAYER_ACTIVE")
173 box
.label(text
="Torus Knots Plus, Celtic Links, Braid Knot",
175 box
.label(text
="SpiroFit, Bounce Spline, Catenary", icon
="LAYER_USED")
176 box
.label(text
="Curly Curve", icon
="LAYER_ACTIVE")
177 box
.label(text
="Bevel/Taper:", icon
="LAYER_ACTIVE")
178 box
.label(text
="Add Curve as Bevel, Add Curve as Taper",
180 box
.label(text
="Simple Curve:", icon
="LAYER_ACTIVE")
181 box
.label(text
="Available if the Active Object is a Curve was created with 2D Objects",
184 box
.label(text
="Items located in the Add Menu > Surface (default shortcut Ctrl + A):",
186 box
.label(text
="Wedge, Cone, Star, Plane",
190 class INFO_MT_curve_knots_add(Menu
):
191 # Define the "Extras" menu
192 bl_idname
= "INFO_MT_curve_knots_add"
195 def draw(self
, context
):
197 layout
.operator_context
= 'INVOKE_REGION_WIN'
199 layout
.operator("curve.torus_knot_plus", text
="Torus Knot Plus")
200 layout
.operator("curve.celtic_links", text
="Celtic Links")
201 layout
.operator("curve.add_braid", text
="Braid Knot")
202 layout
.operator("object.add_spirofit_spline", icon
="FORCE_MAGNETIC")
203 layout
.operator("object.add_bounce_spline", icon
="FORCE_HARMONIC")
204 layout
.operator("object.add_catenary_curve", icon
="FORCE_CURVE")
207 # Define "Extras" menus
208 def menu_func(self
, context
):
211 layout
.operator_menu_enum("curve.curveaceous_galore", "ProfileType", icon
='CURVE_DATA')
212 layout
.operator_menu_enum("curve.spirals", "spiral_type", icon
='FORCE_VORTEX')
214 layout
.operator("curve.curlycurve", text
="Curly Curve", icon
='GP_ONLY_SELECTED')
215 if context
.mode
!= 'OBJECT':
216 # fix in D2142 will allow to work in EDIT_CURVE
219 layout
.menu(INFO_MT_curve_knots_add
.bl_idname
, text
="Knots", icon
='CURVE_DATA')
221 layout
.operator("curve.bevelcurve")
222 layout
.operator("curve.tapercurve")
223 layout
.operator("curve.simple")
225 def menu_surface(self
, context
):
226 self
.layout
.separator()
227 if context
.mode
== 'EDIT_SURFACE':
228 self
.layout
.operator("curve.smooth_x_times", text
="Special Smooth", icon
="MOD_CURVE")
229 elif context
.mode
== 'OBJECT':
230 self
.layout
.operator("object.add_surface_wedge", text
="Wedge", icon
="SURFACE_DATA")
231 self
.layout
.operator("object.add_surface_cone", text
="Cone", icon
="SURFACE_DATA")
232 self
.layout
.operator("object.add_surface_star", text
="Star", icon
="SURFACE_DATA")
233 self
.layout
.operator("object.add_surface_plane", text
="Plane", icon
="SURFACE_DATA")
237 CurveExtraObjectsAddonPreferences
,
238 INFO_MT_curve_knots_add
242 from bpy
.utils
import register_class
246 add_curve_simple
.register()
247 add_curve_spirals
.register()
248 add_curve_aceous_galore
.register()
249 add_curve_torus_knots
.register()
250 add_curve_braid
.register()
251 add_curve_celtic_links
.register()
252 add_curve_curly
.register()
253 add_curve_spirofit_bouncespline
.register()
254 add_surface_plane_cone
.register()
255 beveltaper_curve
.register()
257 # Add "Extras" menu to the "Add Curve" menu
258 bpy
.types
.VIEW3D_MT_curve_add
.append(menu_func
)
259 # Add "Extras" menu to the "Add Surface" menu
260 bpy
.types
.VIEW3D_MT_surface_add
.append(menu_surface
)
264 # Remove "Extras" menu from the "Add Curve" menu.
265 bpy
.types
.VIEW3D_MT_curve_add
.remove(menu_func
)
266 # Remove "Extras" menu from the "Add Surface" menu.
267 bpy
.types
.VIEW3D_MT_surface_add
.remove(menu_surface
)
269 add_surface_plane_cone
.unregister()
270 add_curve_spirofit_bouncespline
.unregister()
271 add_curve_curly
.unregister()
272 add_curve_celtic_links
.unregister()
273 add_curve_braid
.unregister()
274 add_curve_torus_knots
.unregister()
275 add_curve_aceous_galore
.unregister()
276 add_curve_spirals
.unregister()
277 add_curve_simple
.unregister()
278 beveltaper_curve
.unregister()
280 from bpy
.utils
import unregister_class
281 for cls
in reversed(classes
):
282 unregister_class(cls
)
284 if __name__
== "__main__":