diff --git a/scripts/addons/cam/__init__.py b/scripts/addons/cam/__init__.py index c90b10709..6aaa453e2 100644 --- a/scripts/addons/cam/__init__.py +++ b/scripts/addons/cam/__init__.py @@ -22,7 +22,7 @@ from bpy_extras.object_utils import object_data_add # Relative Imports - from 'cam' module -from . import basrelief +from .basrelief import DoBasRelief, ProblemAreas from .cam_operation import camOperation from .chain import ( camChain, @@ -109,6 +109,9 @@ classes = [ + # .basrelief + DoBasRelief, + ProblemAreas, # .chain opReference, camChain, @@ -188,7 +191,7 @@ def register() -> None: bpy.utils.register_class(cls) ui_register() - basrelief.register() + # .cam_operation - last to allow dependencies to register before it bpy.utils.register_class(camOperation) @@ -253,7 +256,7 @@ def unregister() -> None: bpy.utils.unregister_class(cls) ui_unregister() - basrelief.unregister() + bpy.utils.unregister_class(camOperation) scene = bpy.types.Scene diff --git a/scripts/addons/cam/basrelief.py b/scripts/addons/cam/basrelief.py index d9f5c43d8..1ade8e590 100644 --- a/scripts/addons/cam/basrelief.py +++ b/scripts/addons/cam/basrelief.py @@ -11,14 +11,6 @@ import numpy import bpy -from bpy.props import ( - BoolProperty, - EnumProperty, - FloatProperty, - IntProperty, - PointerProperty, - StringProperty, -) # //////////////////////////////////////////////////////////////////// @@ -832,7 +824,7 @@ def imagetonumpy(i): x = 0 y = 0 count = 0 - na = numpy.array((0.1), dtype=float64) + na = numpy.array((0.1), dtype=numpy.float64) size = width * height na.resize(size * 4) @@ -1401,347 +1393,6 @@ def filterwindow(x, y, cx=0, cy=0): # , curve=None): # numpytoimage(target,br.output_image_name) -class BasReliefsettings(bpy.types.PropertyGroup): - use_image_source: BoolProperty( - name="Use Image Source", - description="", - default=False, - ) - source_image_name: StringProperty( - name="Image Source", - description="image source", - ) - view_layer_name: StringProperty( - name="View Layer Source", - description="Make a bas-relief from whatever is on this view layer", - ) - bit_diameter: FloatProperty( - name="Diameter of Ball End in mm", - description="Diameter of bit which will be used for carving", - min=0.01, - max=50.0, - default=3.175, - precision=PRECISION, - ) - pass_per_radius: IntProperty( - name="Passes per Radius", - description="Amount of passes per radius\n(more passes, " "more mesh precision)", - default=2, - min=1, - max=10, - ) - widthmm: IntProperty( - name="Desired Width in mm", - default=200, - min=5, - max=4000, - ) - heightmm: IntProperty( - name="Desired Height in mm", - default=150, - min=5, - max=4000, - ) - thicknessmm: IntProperty( - name="Thickness in mm", - default=15, - min=5, - max=100, - ) - - justifyx: EnumProperty( - name="X", - items=[("1", "Left", "", 0), ("-0.5", "Centered", "", 1), ("-1", "Right", "", 2)], - default="-1", - ) - justifyy: EnumProperty( - name="Y", - items=[ - ("1", "Bottom", "", 0), - ("-0.5", "Centered", "", 2), - ("-1", "Top", "", 1), - ], - default="-1", - ) - justifyz: EnumProperty( - name="Z", - items=[ - ("-1", "Below 0", "", 0), - ("-0.5", "Centered", "", 2), - ("1", "Above 0", "", 1), - ], - default="-1", - ) - - depth_exponent: FloatProperty( - name="Depth Exponent", - description="Initial depth map is taken to this power. Higher = " "sharper relief", - min=0.5, - max=10.0, - default=1.0, - precision=PRECISION, - ) - - silhouette_threshold: FloatProperty( - name="Silhouette Threshold", - description="Silhouette threshold", - min=0.000001, - max=1.0, - default=0.003, - precision=PRECISION, - ) - recover_silhouettes: BoolProperty( - name="Recover Silhouettes", - description="", - default=True, - ) - silhouette_scale: FloatProperty( - name="Silhouette Scale", - description="Silhouette scale", - min=0.000001, - max=5.0, - default=0.3, - precision=PRECISION, - ) - silhouette_exponent: IntProperty( - name="Silhouette Square Exponent", - description="If lower, true depth distances between objects will be " - "more visibe in the relief", - default=3, - min=0, - max=5, - ) - attenuation: FloatProperty( - name="Gradient Attenuation", - description="Gradient attenuation", - min=0.000001, - max=100.0, - default=1.0, - precision=PRECISION, - ) - min_gridsize: IntProperty( - name="Minimum Grid Size", - default=16, - min=2, - max=512, - ) - smooth_iterations: IntProperty( - name="Smooth Iterations", - default=1, - min=1, - max=64, - ) - vcycle_iterations: IntProperty( - name="V-Cycle Iterations", - description="Set higher for planar constraint", - default=2, - min=1, - max=128, - ) - linbcg_iterations: IntProperty( - name="LINBCG Iterations", - description="Set lower for flatter relief, and when using " "planar constraint", - default=5, - min=1, - max=64, - ) - use_planar: BoolProperty( - name="Use Planar Constraint", - description="", - default=False, - ) - gradient_scaling_mask_use: BoolProperty( - name="Scale Gradients with Mask", - description="", - default=False, - ) - decimate_ratio: FloatProperty( - name="Decimate Ratio", - description="Simplify the mesh using the Decimate modifier. " - "The lower the value the more simplyfied", - min=0.01, - max=1.0, - default=0.1, - precision=PRECISION, - ) - - gradient_scaling_mask_name: StringProperty( - name="Scaling Mask Name", - description="Mask name", - ) - scale_down_before_use: BoolProperty( - name="Scale Down Image Before Processing", - description="", - default=False, - ) - scale_down_before: FloatProperty( - name="Image Scale", - description="Image scale", - min=0.025, - max=1.0, - default=0.5, - precision=PRECISION, - ) - detail_enhancement_use: BoolProperty( - name="Enhance Details", - description="Enhance details by frequency analysis", - default=False, - ) - # detail_enhancement_freq=FloatProperty(name="frequency limit", description="Image scale", min=0.025, max=1.0, default=.5, precision=PRECISION) - detail_enhancement_amount: FloatProperty( - name="Amount", - description="Image scale", - min=0.025, - max=1.0, - default=0.5, - precision=PRECISION, - ) - - advanced: BoolProperty( - name="Advanced Options", - description="Show advanced options", - default=True, - ) - - -class BASRELIEF_Panel(bpy.types.Panel): - """Bas Relief Panel""" - - bl_label = "[ Bas Relief ]" - bl_idname = "WORLD_PT_BASRELIEF" - bl_options = {"DEFAULT_CLOSED"} - bl_space_type = "PROPERTIES" - bl_region_type = "WINDOW" - bl_context = "render" - COMPAT_ENGINES = {"FABEX_RENDER"} - - # def draw_header(self, context): - # self.layout.menu("CAM_CUTTER_MT_presets", text="CAM Cutter") - @classmethod - def poll(cls, context): - """Check if the current render engine is compatible. - - This class method checks whether the render engine specified in the - provided context is included in the list of compatible engines. It - accesses the render settings from the context and verifies if the engine - is part of the predefined compatible engines. - - Args: - context (Context): The context containing the scene and render settings. - - Returns: - bool: True if the render engine is compatible, False otherwise. - """ - - rd = context.scene.render - return rd.engine in cls.COMPAT_ENGINES - - def draw(self, context): - """Draw the user interface for the bas relief settings. - - This method constructs the layout for the bas relief settings in the - Blender user interface. It includes various properties and options that - allow users to configure the bas relief calculations, such as selecting - images, adjusting parameters, and setting justification options. The - layout is dynamically updated based on user selections, providing a - comprehensive interface for manipulating bas relief settings. - - Args: - context (bpy.context): The context in which the UI is being drawn. - - Returns: - None: This method does not return any value; it modifies the layout - directly. - """ - - layout = self.layout - layout.use_property_split = True - layout.use_property_decorate = False - - # print(dir(layout)) - s = bpy.context.scene - - br = s.basreliefsettings - - # if br: - # cutter preset - - box = layout.box() - col = box.column(align=True) - col.label(text="Source") - if br.use_image_source: - col.prop_search(br, "source_image_name", bpy.data, "images") - else: - col.prop_search(br, "view_layer_name", bpy.context.scene, "view_layers") - col.prop(br, "use_image_source") - col.prop(br, "depth_exponent") - col.prop(br, "advanced") - - box = layout.box() - col = box.column(align=True) - col.label(text="Parameters") - col.prop(br, "bit_diameter", text="Ball End Diameter (mm)") - col.prop(br, "pass_per_radius") - col.prop(br, "widthmm", text="Desired Width (mm)") - col.prop(br, "heightmm", text="Desired Height (mm)") - col.prop(br, "thicknessmm", text="Thickness (mm)") - - box = layout.box() - col = box.column(align=True) - col.label(text="Justification") - col.prop(br, "justifyx") - col.prop(br, "justifyy") - col.prop(br, "justifyz") - - box = layout.box() - col = box.column(align=True) - col.label(text="Silhouette") - col.prop(br, "silhouette_threshold", text="Threshold") - col.prop(br, "recover_silhouettes") - if br.recover_silhouettes: - col.prop(br, "silhouette_scale", text="Scale") - if br.advanced: - col.prop(br, "silhouette_exponent", text="Square Exponent") - # layout.template_curve_mapping(br,'curva') - # layout.prop(br,'attenuation') - - box = layout.box() - col = box.column(align=True) - col.label(text="Iterations") - if br.advanced: - col.prop(br, "smooth_iterations", text="Smooth") - col.prop(br, "vcycle_iterations", text="V-Cycle") - col.prop(br, "linbcg_iterations", text="LINBCG") - - if br.advanced: - layout.prop(br, "min_gridsize") - layout.prop(br, "decimate_ratio") - layout.prop(br, "use_planar") - - layout.prop(br, "gradient_scaling_mask_use") - if br.advanced: - if br.gradient_scaling_mask_use: - layout.prop_search(br, "gradient_scaling_mask_name", bpy.data, "images") - layout.prop(br, "detail_enhancement_use") - if br.detail_enhancement_use: - # layout.prop(br,'detail_enhancement_freq') - layout.prop(br, "detail_enhancement_amount") - # print(dir(layout)) - # layout.prop(s.view_settings.curve_mapping,"curves") - # layout.label('Frequency scaling:') - # s.view_settings.curve_mapping.clip_max_y=2 - - # layout.template_curve_mapping(s.view_settings, "curve_mapping") - - # layout.prop(br,'scale_down_before_use') - # if br.scale_down_before_use: - # layout.prop(br,'scale_down_before') - box = layout.box() - col = box.column() - col.scale_y = 1.2 - col.operator("scene.calculate_bas_relief", text="Calculate Relief", icon="RNDCURVE") - - class ReliefError(Exception): pass @@ -1832,56 +1483,3 @@ def execute(self, context): br = s.basreliefsettings problemAreas(br) return {"FINISHED"} - - -def get_panels(): - """Retrieve a tuple of panel settings and related components. - - This function returns a tuple containing various components related to - Bas Relief settings. The components include BasReliefsettings, - BASRELIEF_Panel, DoBasRelief, and ProblemAreas, which are likely used in - the context of a graphical user interface or a specific application - domain. - - Returns: - tuple: A tuple containing the BasReliefsettings, BASRELIEF_Panel, - DoBasRelief, and ProblemAreas components. - """ - - return (BasReliefsettings, BASRELIEF_Panel, DoBasRelief, ProblemAreas) - - -def register(): - """Register the necessary classes and properties for the add-on. - - This function registers all the panels defined in the add-on by - iterating through the list of panels returned by the `get_panels()` - function. It also adds a new property, `basreliefsettings`, to the - `Scene` type, which is a pointer property that references the - `BasReliefsettings` class. This setup is essential for the proper - functioning of the add-on, allowing users to access and modify the - settings related to bas relief. - """ - - for p in get_panels(): - bpy.utils.register_class(p) - s = bpy.types.Scene - s.basreliefsettings = PointerProperty( - type=BasReliefsettings, - ) - - -def unregister(): - """Unregister all panels and remove basreliefsettings from the Scene type. - - This function iterates through all registered panels and unregisters - each one using Blender's utility functions. Additionally, it removes the - basreliefsettings attribute from the Scene type, ensuring that any - settings related to bas relief are no longer accessible in the current - Blender session. - """ - - for p in get_panels(): - bpy.utils.unregister_class(p) - s = bpy.types.Scene - del s.basreliefsettings diff --git a/scripts/addons/cam/engine.py b/scripts/addons/cam/engine.py index 0e0bc0a51..75da28253 100644 --- a/scripts/addons/cam/engine.py +++ b/scripts/addons/cam/engine.py @@ -35,6 +35,20 @@ class FABEX_ENGINE(RenderEngine): bl_label = "Fabex CNC/CAM" bl_use_eevee_viewport = True + # view3d = [a.spaces[0] for a in context.screen.areas if a.type == "VIEW_3D"][0] + + # shading = view3d.shading + # shading.color_type = "OBJECT" + # shading.show_shadows = True + # shading.show_cavity = True + # shading.cavity_type = "BOTH" + # shading.cavity_ridge_factor = 2.5 + # shading.cavity_valley_factor = 2.5 + # shading.curvature_ridge_factor = 2 + # shading.curvature_valley_factor = 2 + # shading.use_dof = True + # shading.show_object_outline = True + def get_panels(): """Retrieve a list of panels for the Blender UI. diff --git a/scripts/addons/cam/ops.py b/scripts/addons/cam/ops.py index ff02768c7..4a9900157 100644 --- a/scripts/addons/cam/ops.py +++ b/scripts/addons/cam/ops.py @@ -1093,8 +1093,9 @@ def execute(self, context): context: The context in which the operation is executed. """ # Open Sidebar to show Operation Settings - view3d = [a for a in context.screen.areas if a.type == "VIEW_3D"][0] - view3d.spaces[0].show_region_ui = True + if context.scene.interface.operation_location == "SIDEBAR": + view3d = [a for a in context.screen.areas if a.type == "VIEW_3D"][0] + view3d.spaces[0].show_region_ui = True s = bpy.context.scene fixUnits() @@ -1118,11 +1119,6 @@ def execute(self, context): if s.objects.get("CAM_machine") is None: addMachineAreaObject() - # ui = [r for r in view3d.regions if r.type == "UI"][0] - # ui.active_panel_category = "CNC" - # view3d.regions[5].active_panel_category = "CNC" - # view3d.tag_redraw() - return {"FINISHED"} @@ -1235,6 +1231,10 @@ def execute(self, context): scene = context.scene try: if len(scene.cam_operations) == 0: + # # Close Sidebar + # view3d = [a for a in context.screen.areas if a.type == "VIEW_3D"][0] + # if view3d.regions[5].active_panel_category == "CNC": + # view3d.spaces[0].show_region_ui = False return {"CANCELLED"} active_op = scene.cam_operations[scene.cam_active_operation] active_op_object = bpy.data.objects[active_op.name] diff --git a/scripts/addons/cam/preferences.py b/scripts/addons/cam/preferences.py index 1c87c0ab7..4dc5d6b14 100644 --- a/scripts/addons/cam/preferences.py +++ b/scripts/addons/cam/preferences.py @@ -3,6 +3,7 @@ Class to store all Addon preferences. """ +import bpy from bpy.props import ( BoolProperty, EnumProperty, @@ -13,7 +14,6 @@ AddonPreferences, ) -# from .version import __version__ as cam_version from .utils import opencamlib_version @@ -29,6 +29,7 @@ class CamAddonPreferences(AddonPreferences): experimental: BoolProperty( name="Show Experimental Features", + description="Use these features when you want to help development of Fabex", default=False, ) @@ -44,6 +45,177 @@ class CamAddonPreferences(AddonPreferences): default="3", ) + default_shading: EnumProperty( + name="Viewport Shading in New File", + description="Choose viewport shading preset", + items=[ + ("DEFAULT", "Default", "Standard viewport shading"), + ("DELUXE", "Deluxe", "Cavity, Curvature, Depth of Field, Shadows & Object Colors"), + ("CLEAN_DEFAULT", "Clean Default", "Standard viewport shading with no overlays"), + ("CLEAN_DELUXE", "Clean Deluxe", "Deluxe shading with no overlays"), + ("PREVIEW", "Preview", "HDRI Lighting Preview"), + ], + default="DEFAULT", + ) + + default_layout: EnumProperty( + name="Panel Layout", + description="Presets for all panel locations", + items=[ + ( + "CLASSIC", + "Classic", + "Properties Area holds most panels, Tools holds the rest", + ), + ( + "MODERN", + "Modern", + "Properties holds Main panels, Sidebar holds Operation panels, Tools holds Tools", + ), + ( + "USER", + "User", + "Define your own locations for panels", + ), + ], + default="MODERN", + ) + + default_main_location: EnumProperty( + name="Main Panels", + description="Location for Chains, Operations, Material, Machine, Pack, Slice Panels", + items=[ + ( + "PROPERTIES", + "Properties", + "Default panel location is the Render tab of the Properties Area", + ), + ( + "SIDEBAR", + "Sidebar (N-Panel)", + "Common location for addon UI, press N to show/hide", + ), + ( + "TOOLS", + "Tools (T-Panel)", + "Blender's Tool area, press T to show/hide", + ), + ], + default="PROPERTIES", + ) + + default_operation_location: EnumProperty( + name="Operation Panels", + description="Location for Setup, Area, Cutter, Feedrate, Optimisation, Movement, G-code", + items=[ + ( + "PROPERTIES", + "Properties", + "Default panel location is the Render tab of the Properties Area", + ), + ( + "SIDEBAR", + "Sidebar (N-Panel)", + "Common location for addon UI, press N to show/hide", + ), + ( + "TOOLS", + "Tools (T-Panel)", + "Blender's Tool area, press T to show/hide", + ), + ], + default="SIDEBAR", + ) + + default_tools_location: EnumProperty( + name="Tools Panels", + description="Location for Curve Tools, Curve Creators, Info", + items=[ + ( + "PROPERTIES", + "Properties", + "Default panel location is the Render tab of the Properties Area", + ), + ( + "SIDEBAR", + "Sidebar (N-Panel)", + "Common location for addon UI, press N to show/hide", + ), + ( + "TOOLS", + "Tools (T-Panel)", + "Blender's Tool area, press T to show/hide", + ), + ], + default="TOOLS", + ) + + user_main_location: EnumProperty( + name="Main Panels", + items=[ + ( + "PROPERTIES", + "Properties", + "Default panel location is the Render tab of the Properties Area", + ), + ( + "SIDEBAR", + "Sidebar (N-Panel)", + "Common location for addon UI, press N to show/hide", + ), + ( + "TOOLS", + "Tools (T-Panel)", + "Blender's Tool area, press T to show/hide", + ), + ], + default="PROPERTIES", + ) + + user_operation_location: EnumProperty( + name="Operation Panels", + items=[ + ( + "PROPERTIES", + "Properties", + "Default panel location is the Render tab of the Properties Area", + ), + ( + "SIDEBAR", + "Sidebar (N-Panel)", + "Common location for addon UI, press N to show/hide", + ), + ( + "TOOLS", + "Tools (T-Panel)", + "Blender's Tool area, press T to show/hide", + ), + ], + default="SIDEBAR", + ) + + user_tools_location: EnumProperty( + name="Tools Panels", + items=[ + ( + "PROPERTIES", + "Properties", + "Default panel location is the Render tab of the Properties Area", + ), + ( + "SIDEBAR", + "Sidebar (N-Panel)", + "Common location for addon UI, press N to show/hide", + ), + ( + "TOOLS", + "Tools (T-Panel)", + "Blender's Tool area, press T to show/hide", + ), + ], + default="TOOLS", + ) + default_machine_preset: StringProperty( name="Machine Preset in New File", description="So that machine preset choice persists between files", @@ -52,18 +224,28 @@ class CamAddonPreferences(AddonPreferences): def draw(self, context): layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + box = layout.box() col = box.column(align=True) - # # Fabex Version - # col.label(text=f'Fabex v{".".join([str(x) for x in cam_version])}') + col.label(text="User Layout Preset", icon="DESKTOP") + col.label(text="Panel Locations") + col.prop(context.scene.interface, "main_location", text="Main") + col.prop(context.scene.interface, "operation_location", text="Operation") + col.prop(context.scene.interface, "tools_location", text="Tools") + box = layout.box() + col = box.column(align=True) + col.label(text="Library", icon="ASSET_MANAGER") # OpenCAMLib Version - if int(context.scene.interface.level) >= 1: - ocl_version = opencamlib_version() - if ocl_version is None: - col.label(text="OpenCAMLib is not Installed") - else: - col.label(text=f"OpenCAMLib v{ocl_version}") - - layout.label(text="Use Experimental Features when you want to help development of Fabex:") - layout.prop(self, "experimental") + ocl_version = opencamlib_version() + if ocl_version is None: + col.label(text="OpenCAMLib is not Installed") + else: + col.label(text=f"OpenCAMLib v{ocl_version}") + + box = layout.box() + col = box.column(align=True) + col.label(text="Experimental", icon="EXPERIMENTAL") + col.prop(self, "experimental") diff --git a/scripts/addons/cam/preset_managers.py b/scripts/addons/cam/preset_managers.py index 2a1bdb4fd..02781532e 100644 --- a/scripts/addons/cam/preset_managers.py +++ b/scripts/addons/cam/preset_managers.py @@ -18,6 +18,13 @@ class CAM_CUTTER_MT_presets(Menu): draw = Menu.draw_preset +class CAM_OPERATION_MT_presets(Menu): + bl_label = "Operation Presets" + preset_subdir = "cam_operations" + preset_operator = "script.execute_preset" + draw = Menu.draw_preset + + class CAM_MACHINE_MT_presets(Menu): bl_label = "Machine Presets" preset_subdir = "cam_machines" @@ -57,13 +64,6 @@ class AddPresetCamCutter(AddPresetBase, Operator): preset_subdir = "cam_cutters" -class CAM_OPERATION_MT_presets(Menu): - bl_label = "Operation Presets" - preset_subdir = "cam_operations" - preset_operator = "script.execute_preset" - draw = Menu.draw_preset - - class AddPresetCamOperation(AddPresetBase, Operator): """Add an Operation Preset""" diff --git a/scripts/addons/cam/ui/__init__.py b/scripts/addons/cam/ui/__init__.py index fbd7d9be4..90e7b1373 100644 --- a/scripts/addons/cam/ui/__init__.py +++ b/scripts/addons/cam/ui/__init__.py @@ -4,6 +4,7 @@ """ import bpy +from bpy.props import PointerProperty from .menus.import_gcode import TOPBAR_MT_import_gcode from .menus.curve_creators import VIEW3D_MT_tools_add, VIEW3D_MT_tools_create @@ -15,12 +16,13 @@ CAM_UL_chains, CAM_UL_operations, ) +from .panels.basrelief import BasReliefsettings, BASRELIEF_Panel from .panels.blank import CAM_BLANK_Panel from .panels.cutter import CAM_CUTTER_Panel from .panels.feedrate import CAM_FEEDRATE_Panel from .panels.gcode import CAM_GCODE_Panel from .panels.info import CAM_INFO_Panel, CAM_INFO_Properties -from .panels.interface import CAM_INTERFACE_Properties +from .panels.interface import CAM_INTERFACE_Properties, draw_interface from .panels.machine import CAM_MACHINE_Panel from .panels.material import ( CAM_MATERIAL_Panel, @@ -77,6 +79,8 @@ CAM_PACK_Panel, CAM_Popup_Panel, CAM_SLICE_Panel, + BasReliefsettings, + BASRELIEF_Panel, VIEW3D_PT_tools_curvetools, VIEW3D_PT_tools_create, WM_OT_gcode_import, @@ -88,17 +92,6 @@ ] -def draw_engine_extras(self, context): - layout = self.layout - layout.use_property_split = True - layout.use_property_decorate = False - - if context.engine == "FABEX_RENDER": - - col = layout.column() - col.prop(context.scene.interface, "level") - - def progress_bar(self, context): progress = context.window_manager.progress percent = int(progress * 100) @@ -108,7 +101,7 @@ def progress_bar(self, context): row.scale_x = 2 row.progress( factor=progress, - text=f"Processing...{percent}% (Esc to Cancel)", + text=f"Processing...{percent}%", ) @@ -116,14 +109,19 @@ def register(): for cls in classes: bpy.utils.register_class(cls) - bpy.types.VIEW3D_HT_header.prepend(progress_bar) + bpy.types.VIEW3D_HT_header.append(progress_bar) bpy.types.TOPBAR_MT_file_import.append(TOPBAR_MT_import_gcode.draw) bpy.types.VIEW3D_MT_curve_add.append(VIEW3D_MT_tools_add.draw) bpy.types.VIEW3D_MT_editor_menus.append(Fabex_Menu.draw) - bpy.types.RENDER_PT_context.append(draw_engine_extras) + bpy.types.RENDER_PT_context.append(draw_interface) bpy.types.WindowManager.progress = bpy.props.FloatProperty(default=0) + scene = bpy.types.Scene + scene.basreliefsettings = PointerProperty( + type=BasReliefsettings, + ) + def unregister(): for cls in classes: @@ -133,4 +131,7 @@ def unregister(): bpy.types.TOPBAR_MT_file_import.remove(TOPBAR_MT_import_gcode.draw) bpy.types.VIEW3D_MT_curve_add.remove(VIEW3D_MT_tools_add.draw) bpy.types.VIEW3D_MT_editor_menus.remove(Fabex_Menu.draw) - bpy.types.RENDER_PT_context.remove(draw_engine_extras) + bpy.types.RENDER_PT_context.remove(draw_interface) + + scene = bpy.types.Scene + del scene.basreliefsettings diff --git a/scripts/addons/cam/ui/legacy_ui.py b/scripts/addons/cam/ui/legacy_ui.py index 9ed7d9dbd..bf97176c6 100644 --- a/scripts/addons/cam/ui/legacy_ui.py +++ b/scripts/addons/cam/ui/legacy_ui.py @@ -36,44 +36,72 @@ class VIEW3D_PT_tools_curvetools(Panel): bl_space_type = "VIEW_3D" bl_region_type = "TOOLS" bl_context = "objectmode" - bl_label = "Curve CAM Tools" - bl_order = 0 + bl_label = "[ Curve Tools ]" + # bl_options = {"HIDE_HEADER"} def draw(self, context): + # if not context.scene.render.engine == "FABEX_RENDER": + # return + # else: layout = self.layout - layout.operator("object.curve_boolean") - layout.operator("object.convex_hull") - layout.operator("object.curve_intarsion") - layout.operator("object.curve_overcuts") - layout.operator("object.curve_overcuts_b") - layout.operator("object.silhouete") - layout.operator("object.silhouete_offset") - layout.operator("object.curve_remove_doubles") - layout.operator("object.mesh_get_pockets") + layout.scale_y = 1.2 + # header, panel = layout.panel("curve_tools") + # header.label(text="Curve Tools", icon="CURVE_DATA") + # if panel: + col = layout.column() + col.operator("object.curve_boolean", icon="MOD_BOOLEAN") + col.operator("object.convex_hull", icon="MOD_SOLIDIFY") + col.operator("object.curve_intarsion", icon="OUTLINER_DATA_META") + column = col.column(align=True) + column.operator("object.curve_overcuts", icon="CON_SIZELIKE") + column.operator("object.curve_overcuts_b", icon="CON_SIZELIKE") + column = col.column(align=True) + column.operator("object.silhouete", icon="USER", text="Object Silhouette") + column.operator("object.silhouete_offset", icon="COMMUNITY", text="Silhouette Offset") + col.operator( + "object.curve_remove_doubles", icon="FORCE_CHARGE", text="Remove Curve Doubles" + ) + col.operator("object.mesh_get_pockets", icon="HOLDOUT_ON", text="Get Pocket Surfaces") + + column = col.column(align=True) + column.operator( + "object.cam_pack_objects", icon="STICKY_UVS_LOC", text="Pack Curves on Sheet" + ) + column.operator("object.cam_slice_objects", icon="ALIGN_FLUSH", text="Slice Model to Sheet") + + col.operator("scene.calculate_bas_relief", icon="RNDCURVE", text="Bas Relief") class VIEW3D_PT_tools_create(Panel): bl_space_type = "VIEW_3D" bl_region_type = "TOOLS" bl_context = "objectmode" - bl_label = "Curve CAM Creators" - bl_option = "DEFAULT_CLOSED" - bl_order = 1 + bl_label = "[ Curve Creators ]" + # bl_option = "DEFAULT_CLOSED" + # bl_options = {"HIDE_HEADER"} def draw(self, context): + # if not context.scene.render.engine == "FABEX_RENDER": + # return + # else: layout = self.layout - layout.operator("object.curve_plate") - layout.operator("object.curve_drawer") - layout.operator("object.curve_mortise") - layout.operator("object.curve_interlock") - layout.operator("object.curve_puzzle") - layout.operator("object.sine") - layout.operator("object.lissajous") - layout.operator("object.hypotrochoid") - layout.operator("object.customcurve") - layout.operator("object.curve_hatch") - layout.operator("object.curve_gear") - layout.operator("object.curve_flat_cone") + layout.scale_y = 1.2 + # header, panel = layout.panel("curve_tools") + # header.label(text="Curve Creators", icon="FCURVE") + # if panel: + col = layout.column(align=True) + col.operator("object.curve_plate", icon="META_PLANE") + col.operator("object.curve_drawer", icon="CON_SAMEVOL") + col.operator("object.curve_mortise", icon="CHECKBOX_DEHLT") + col.operator("object.curve_interlock", icon="REMOVE") + col.operator("object.curve_puzzle", icon="HAND") + col.operator("object.sine", icon="FORCE_HARMONIC") + col.operator("object.lissajous", icon="VIEW_ORTHO") + col.operator("object.hypotrochoid", icon="SHADING_WIRE") + col.operator("object.customcurve", icon="IPO_BOUNCE") + col.operator("object.curve_hatch", icon="OUTLINER_DATA_LIGHTPROBE") + col.operator("object.curve_gear", icon="PREFERENCES") + col.operator("object.curve_flat_cone", icon="MESH_CONE") class WM_OT_gcode_import(Operator, ImportHelper): diff --git a/scripts/addons/cam/ui/panels/basrelief.py b/scripts/addons/cam/ui/panels/basrelief.py new file mode 100644 index 000000000..abb1f82a2 --- /dev/null +++ b/scripts/addons/cam/ui/panels/basrelief.py @@ -0,0 +1,358 @@ +"""Fabex 'basrelief.py' + +'Bas Relief' properties and panel in Properties > Render +""" + +import bpy +from bpy.types import PropertyGroup, Panel +from bpy.props import ( + BoolProperty, + EnumProperty, + FloatProperty, + IntProperty, + PointerProperty, + StringProperty, +) + +from ...constants import PRECISION + + +class BasReliefsettings(PropertyGroup): + use_image_source: BoolProperty( + name="Use Image Source", + description="", + default=False, + ) + source_image_name: StringProperty( + name="Image Source", + description="image source", + ) + view_layer_name: StringProperty( + name="View Layer Source", + description="Make a bas-relief from whatever is on this view layer", + ) + bit_diameter: FloatProperty( + name="Diameter of Ball End in mm", + description="Diameter of bit which will be used for carving", + min=0.01, + max=50.0, + default=3.175, + precision=PRECISION, + ) + pass_per_radius: IntProperty( + name="Passes per Radius", + description="Amount of passes per radius\n(more passes, " "more mesh precision)", + default=2, + min=1, + max=10, + ) + widthmm: IntProperty( + name="Desired Width in mm", + default=200, + min=5, + max=4000, + ) + heightmm: IntProperty( + name="Desired Height in mm", + default=150, + min=5, + max=4000, + ) + thicknessmm: IntProperty( + name="Thickness in mm", + default=15, + min=5, + max=100, + ) + + justifyx: EnumProperty( + name="X", + items=[("1", "Left", "", 0), ("-0.5", "Centered", "", 1), ("-1", "Right", "", 2)], + default="-1", + ) + justifyy: EnumProperty( + name="Y", + items=[ + ("1", "Bottom", "", 0), + ("-0.5", "Centered", "", 2), + ("-1", "Top", "", 1), + ], + default="-1", + ) + justifyz: EnumProperty( + name="Z", + items=[ + ("-1", "Below 0", "", 0), + ("-0.5", "Centered", "", 2), + ("1", "Above 0", "", 1), + ], + default="-1", + ) + + depth_exponent: FloatProperty( + name="Depth Exponent", + description="Initial depth map is taken to this power. Higher = " "sharper relief", + min=0.5, + max=10.0, + default=1.0, + precision=PRECISION, + ) + + silhouette_threshold: FloatProperty( + name="Silhouette Threshold", + description="Silhouette threshold", + min=0.000001, + max=1.0, + default=0.003, + precision=PRECISION, + ) + recover_silhouettes: BoolProperty( + name="Recover Silhouettes", + description="", + default=True, + ) + silhouette_scale: FloatProperty( + name="Silhouette Scale", + description="Silhouette scale", + min=0.000001, + max=5.0, + default=0.3, + precision=PRECISION, + ) + silhouette_exponent: IntProperty( + name="Silhouette Square Exponent", + description="If lower, true depth distances between objects will be " + "more visibe in the relief", + default=3, + min=0, + max=5, + ) + attenuation: FloatProperty( + name="Gradient Attenuation", + description="Gradient attenuation", + min=0.000001, + max=100.0, + default=1.0, + precision=PRECISION, + ) + min_gridsize: IntProperty( + name="Minimum Grid Size", + default=16, + min=2, + max=512, + ) + smooth_iterations: IntProperty( + name="Smooth Iterations", + default=1, + min=1, + max=64, + ) + vcycle_iterations: IntProperty( + name="V-Cycle Iterations", + description="Set higher for planar constraint", + default=2, + min=1, + max=128, + ) + linbcg_iterations: IntProperty( + name="LINBCG Iterations", + description="Set lower for flatter relief, and when using " "planar constraint", + default=5, + min=1, + max=64, + ) + use_planar: BoolProperty( + name="Use Planar Constraint", + description="", + default=False, + ) + gradient_scaling_mask_use: BoolProperty( + name="Scale Gradients with Mask", + description="", + default=False, + ) + decimate_ratio: FloatProperty( + name="Decimate Ratio", + description="Simplify the mesh using the Decimate modifier. " + "The lower the value the more simplyfied", + min=0.01, + max=1.0, + default=0.1, + precision=PRECISION, + ) + + gradient_scaling_mask_name: StringProperty( + name="Scaling Mask Name", + description="Mask name", + ) + scale_down_before_use: BoolProperty( + name="Scale Down Image Before Processing", + description="", + default=False, + ) + scale_down_before: FloatProperty( + name="Image Scale", + description="Image scale", + min=0.025, + max=1.0, + default=0.5, + precision=PRECISION, + ) + detail_enhancement_use: BoolProperty( + name="Enhance Details", + description="Enhance details by frequency analysis", + default=False, + ) + # detail_enhancement_freq=FloatProperty(name="frequency limit", description="Image scale", min=0.025, max=1.0, default=.5, precision=PRECISION) + detail_enhancement_amount: FloatProperty( + name="Amount", + description="Image scale", + min=0.025, + max=1.0, + default=0.5, + precision=PRECISION, + ) + + advanced: BoolProperty( + name="Advanced Options", + description="Show advanced options", + default=True, + ) + + +class BASRELIEF_Panel(Panel): + """Bas Relief Panel""" + + bl_label = "[ Bas Relief ]" + bl_idname = "WORLD_PT_BASRELIEF" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "render" + COMPAT_ENGINES = {"FABEX_RENDER"} + + # def draw_header(self, context): + # self.layout.menu("CAM_CUTTER_MT_presets", text="CAM Cutter") + @classmethod + def poll(cls, context): + """Check if the current render engine is compatible. + + This class method checks whether the render engine specified in the + provided context is included in the list of compatible engines. It + accesses the render settings from the context and verifies if the engine + is part of the predefined compatible engines. + + Args: + context (Context): The context containing the scene and render settings. + + Returns: + bool: True if the render engine is compatible, False otherwise. + """ + + rd = context.scene.render + return rd.engine in cls.COMPAT_ENGINES + + def draw(self, context): + """Draw the user interface for the bas relief settings. + + This method constructs the layout for the bas relief settings in the + Blender user interface. It includes various properties and options that + allow users to configure the bas relief calculations, such as selecting + images, adjusting parameters, and setting justification options. The + layout is dynamically updated based on user selections, providing a + comprehensive interface for manipulating bas relief settings. + + Args: + context (bpy.context): The context in which the UI is being drawn. + + Returns: + None: This method does not return any value; it modifies the layout + directly. + """ + + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + # print(dir(layout)) + scene = context.scene + + br = scene.basreliefsettings + + # if br: + # cutter preset + + box = layout.box() + col = box.column(align=True) + col.label(text="Source") + if br.use_image_source: + col.prop_search(br, "source_image_name", bpy.data, "images") + else: + col.prop_search(br, "view_layer_name", context.scene, "view_layers") + col.prop(br, "use_image_source") + col.prop(br, "depth_exponent") + col.prop(br, "advanced") + + box = layout.box() + col = box.column(align=True) + col.label(text="Parameters") + col.prop(br, "bit_diameter", text="Ball End Diameter (mm)") + col.prop(br, "pass_per_radius") + col.prop(br, "widthmm", text="Desired Width (mm)") + col.prop(br, "heightmm", text="Desired Height (mm)") + col.prop(br, "thicknessmm", text="Thickness (mm)") + + box = layout.box() + col = box.column(align=True) + col.label(text="Justification") + col.prop(br, "justifyx") + col.prop(br, "justifyy") + col.prop(br, "justifyz") + + box = layout.box() + col = box.column(align=True) + col.label(text="Silhouette") + col.prop(br, "silhouette_threshold", text="Threshold") + col.prop(br, "recover_silhouettes") + if br.recover_silhouettes: + col.prop(br, "silhouette_scale", text="Scale") + if br.advanced: + col.prop(br, "silhouette_exponent", text="Square Exponent") + # layout.template_curve_mapping(br,'curva') + # layout.prop(br,'attenuation') + + box = layout.box() + col = box.column(align=True) + col.label(text="Iterations") + if br.advanced: + col.prop(br, "smooth_iterations", text="Smooth") + col.prop(br, "vcycle_iterations", text="V-Cycle") + col.prop(br, "linbcg_iterations", text="LINBCG") + + if br.advanced: + layout.prop(br, "min_gridsize") + layout.prop(br, "decimate_ratio") + layout.prop(br, "use_planar") + + layout.prop(br, "gradient_scaling_mask_use") + if br.advanced: + if br.gradient_scaling_mask_use: + layout.prop_search(br, "gradient_scaling_mask_name", bpy.data, "images") + layout.prop(br, "detail_enhancement_use") + if br.detail_enhancement_use: + # layout.prop(br,'detail_enhancement_freq') + layout.prop(br, "detail_enhancement_amount") + # print(dir(layout)) + # layout.prop(s.view_settings.curve_mapping,"curves") + # layout.label('Frequency scaling:') + # s.view_settings.curve_mapping.clip_max_y=2 + + # layout.template_curve_mapping(s.view_settings, "curve_mapping") + + # layout.prop(br,'scale_down_before_use') + # if br.scale_down_before_use: + # layout.prop(br,'scale_down_before') + box = layout.box() + col = box.column() + col.scale_y = 1.2 + col.operator("scene.calculate_bas_relief", text="Calculate Relief", icon="RNDCURVE") diff --git a/scripts/addons/cam/ui/panels/blank.py b/scripts/addons/cam/ui/panels/blank.py index b4a6a7572..af002e0f2 100644 --- a/scripts/addons/cam/ui/panels/blank.py +++ b/scripts/addons/cam/ui/panels/blank.py @@ -10,6 +10,7 @@ class CAM_BLANK_Panel(Panel): """CAM Blank Panel""" + bl_idname = "CAM_PT_blank" bl_label = "" bl_space_type = "VIEW_3D" bl_region_type = "UI" diff --git a/scripts/addons/cam/ui/panels/info.py b/scripts/addons/cam/ui/panels/info.py index 08486a387..e684695d5 100644 --- a/scripts/addons/cam/ui/panels/info.py +++ b/scripts/addons/cam/ui/panels/info.py @@ -62,7 +62,6 @@ class CAM_INFO_Panel(CAMButtonsPanel, Panel): bl_region_type = "TOOLS" # bl_category = "CNC" bl_options = {"HIDE_HEADER"} - bl_order = 3 bl_label = "Info & Warnings" bl_idname = "WORLD_PT_CAM_INFO" @@ -83,7 +82,7 @@ def draw(self, context): percent = int(context.window_manager.progress * 100) col.progress( factor=context.window_manager.progress, - text=f"Processing...{percent}% (Esc to Cancel)", + text=f"Processing...{percent}%", ) if self.op is None: return @@ -93,7 +92,7 @@ def draw(self, context): box = main.box() col = box.column(align=True) col.alert = True - col.label(text="Warning!", icon="ERROR") + col.label(text="!!! Warning !!!", icon="ERROR") for line in self.op.info.warnings.rstrip("\n").split("\n"): if len(line) > 0: col.label(text=line, icon="ERROR") @@ -113,28 +112,25 @@ def draw(self, context): box = main.box() col = box.column(align=True) - col.label(text=f"Operation Duration: {time_estimate}", icon="TIME") + col.label(text="Estimates") + col.label(text=f"Time: {time_estimate}", icon="TIME") # Operation Chipload if not self.op.info.chipload > 0: - return - - chipload = f"Chipload: {strInUnits(self.op.info.chipload, 4)}/tooth" - col.label(text=chipload) + pass + else: + chipload = f"Chipload: {strInUnits(self.op.info.chipload, 4)}/tooth" + col.label(text=chipload) # Operation Money Cost if self.level >= 1: if not int(self.op.info.duration * 60) > 0: return - row = main.row() - row.label(text="Hourly Rate") - row.prop(bpy.context.scene.cam_machine, "hourly_rate", text="") - if float(bpy.context.scene.cam_machine.hourly_rate) < 0.01: return cost_per_second = bpy.context.scene.cam_machine.hourly_rate / 3600 total_cost = self.op.info.duration * 60 * cost_per_second - op_cost = f"Operation Cost: ${total_cost:.2f} (${cost_per_second:.2f}/s)" - main.label(text=op_cost) + op_cost = f"Cost: ${total_cost:.2f} (${cost_per_second:.2f}/s)" + col.label(text=op_cost, icon="TAG") diff --git a/scripts/addons/cam/ui/panels/interface.py b/scripts/addons/cam/ui/panels/interface.py index 8dcc60bc5..b7c0f77ff 100644 --- a/scripts/addons/cam/ui/panels/interface.py +++ b/scripts/addons/cam/ui/panels/interface.py @@ -7,6 +7,23 @@ from bpy.props import EnumProperty from bpy.types import PropertyGroup +from .area import CAM_AREA_Panel +from .basrelief import BASRELIEF_Panel +from .chains import CAM_CHAINS_Panel +from .cutter import CAM_CUTTER_Panel +from .feedrate import CAM_FEEDRATE_Panel +from .gcode import CAM_GCODE_Panel +from .info import CAM_INFO_Panel +from .machine import CAM_MACHINE_Panel +from .material import CAM_MATERIAL_Panel +from .movement import CAM_MOVEMENT_Panel +from .op_properties import CAM_OPERATION_PROPERTIES_Panel +from .operations import CAM_OPERATIONS_Panel +from .optimisation import CAM_OPTIMISATION_Panel +from .pack import CAM_PACK_Panel +from .slice import CAM_SLICE_Panel +from ..legacy_ui import VIEW3D_PT_tools_curvetools, VIEW3D_PT_tools_create + def update_interface(self, context): # set default for new files @@ -15,16 +32,388 @@ def update_interface(self, context): bpy.ops.wm.save_userpref() +def update_shading(self, context): + view3d = [a.spaces[0] for a in context.screen.areas if a.type == "VIEW_3D"][0] + shading = view3d.shading + overlay = view3d.overlay + + if context.scene.interface.shading == "DEFAULT": + shading.type = "SOLID" + shading.color_type = "MATERIAL" + shading.show_shadows = False + shading.show_cavity = False + shading.use_dof = False + overlay.show_overlays = True + overlay.show_floor = True + overlay.show_axis_x = True + overlay.show_axis_y = True + + elif context.scene.interface.shading == "DELUXE": + shading.type = "SOLID" + shading.color_type = "OBJECT" + shading.show_shadows = True + shading.show_cavity = True + shading.cavity_type = "BOTH" + shading.use_dof = True + overlay.show_overlays = True + overlay.show_floor = True + overlay.show_axis_x = True + overlay.show_axis_y = True + + elif context.scene.interface.shading == "CLEAN_DEFAULT": + shading.type = "SOLID" + shading.color_type = "MATERIAL" + shading.show_shadows = False + shading.show_cavity = False + shading.use_dof = False + overlay.show_overlays = True + overlay.show_floor = False + overlay.show_axis_x = False + overlay.show_axis_y = False + + elif context.scene.interface.shading == "CLEAN_DELUXE": + shading.type = "SOLID" + shading.color_type = "OBJECT" + shading.show_shadows = True + shading.show_cavity = True + shading.cavity_type = "BOTH" + shading.use_dof = True + overlay.show_overlays = True + overlay.show_floor = False + overlay.show_axis_x = False + overlay.show_axis_y = False + + elif context.scene.interface.shading == "PREVIEW": + shading.type = "MATERIAL" + shading.studio_light = "interior.exr" + overlay.show_overlays = False + + addon_prefs = context.preferences.addons["bl_ext.user_default.fabex"].preferences + addon_prefs.default_shading = context.scene.interface.shading + bpy.ops.wm.save_userpref() + + +def update_layout(self, context): + # Layout preset dicts to fill out panel bl_ attributes + properties = { + "space": "PROPERTIES", + "region": "WINDOW", + "context": "render", + "category": "", + } + + sidebar = { + "space": "VIEW_3D", + "region": "UI", + "context": "", + "category": "CNC", + } + + tools = { + "space": "VIEW_3D", + "region": "TOOLS", + "context": "objectmode", + "category": "", + } + + # Unregister all permanent panels + try: + unregister_classes = [ + bpy.types.WORLD_PT_CAM_OPERATION_AREA, + bpy.types.WORLD_PT_CAM_CHAINS, + bpy.types.WORLD_PT_CAM_CUTTER, + bpy.types.WORLD_PT_CAM_FEEDRATE, + bpy.types.WORLD_PT_CAM_GCODE, + bpy.types.WORLD_PT_CAM_INFO, + bpy.types.WORLD_PT_CAM_MACHINE, + bpy.types.WORLD_PT_CAM_MATERIAL, + bpy.types.WORLD_PT_CAM_MOVEMENT, + bpy.types.WORLD_PT_CAM_OPERATION, + bpy.types.WORLD_PT_CAM_OPERATIONS, + bpy.types.WORLD_PT_CAM_OPTIMISATION, + bpy.types.WORLD_PT_CAM_PACK, + bpy.types.WORLD_PT_CAM_SLICE, + bpy.types.WORLD_PT_BASRELIEF, + bpy.types.VIEW3D_PT_tools_curvetools, + bpy.types.VIEW3D_PT_tools_create, + ] + + for cls in unregister_classes: + bpy.utils.unregister_class(cls) + + except AttributeError: + pass + + main_classes = [ + CAM_CHAINS_Panel, + CAM_OPERATIONS_Panel, + CAM_MATERIAL_Panel, + CAM_MACHINE_Panel, + CAM_PACK_Panel, + CAM_SLICE_Panel, + BASRELIEF_Panel, + ] + operation_classes = [ + CAM_OPERATION_PROPERTIES_Panel, + CAM_AREA_Panel, + CAM_CUTTER_Panel, + CAM_FEEDRATE_Panel, + CAM_GCODE_Panel, + CAM_MOVEMENT_Panel, + CAM_OPTIMISATION_Panel, + ] + tools_classes = [ + VIEW3D_PT_tools_curvetools, + VIEW3D_PT_tools_create, + CAM_INFO_Panel, + ] + + # Create 3 empty lists to hold the classes we want to assign to each area + properties_area_classes = [] + sidebar_area_classes = [] + tools_area_classes = [] + + addon_prefs = context.preferences.addons["bl_ext.user_default.fabex"].preferences + + panel_layout = context.scene.interface.layout + + main_location = context.scene.interface.main_location + operation_location = context.scene.interface.operation_location + tools_location = context.scene.interface.tools_location + + if panel_layout == "CLASSIC": + main_location = "PROPERTIES" + operation_location = "PROPERTIES" + tools_location = "TOOLS" + + elif panel_layout == "MODERN": + main_location = "PROPERTIES" + operation_location = "SIDEBAR" + tools_location = "TOOLS" + + elif panel_layout == "USER": + main_location = addon_prefs.user_main_location + operation_location = addon_prefs.user_operation_location + tools_location = addon_prefs.user_tools_location + + # Assign Panels to their location + # Main Panels + if main_location == "PROPERTIES": + for cls in main_classes: + properties_area_classes.append(cls) + elif main_location == "SIDEBAR": + for cls in main_classes: + sidebar_area_classes.append(cls) + elif main_location == "TOOLS": + for cls in main_classes: + tools_area_classes.append(cls) + + # Operation Panels + if operation_location == "PROPERTIES": + for cls in operation_classes: + properties_area_classes.append(cls) + elif operation_location == "SIDEBAR": + for cls in operation_classes: + sidebar_area_classes.append(cls) + elif operation_location == "TOOLS": + for cls in operation_classes: + tools_area_classes.append(cls) + + # Tools Panels + if tools_location == "PROPERTIES": + for cls in tools_classes: + properties_area_classes.append(cls) + elif tools_location == "SIDEBAR": + for cls in tools_classes: + sidebar_area_classes.append(cls) + elif tools_location == "TOOLS": + for cls in tools_classes: + tools_area_classes.append(cls) + + # Re-register the panels in their new areas + # Properties Area + for cls in properties_area_classes: + cls.bl_space_type = properties["space"] + cls.bl_region_type = properties["region"] + cls.bl_context = properties["context"] + cls.bl_category = properties["category"] + bpy.utils.register_class(cls) + + # Sidebar (N-Panel) Area + for cls in sidebar_area_classes: + cls.bl_space_type = sidebar["space"] + cls.bl_region_type = sidebar["region"] + cls.bl_context = sidebar["context"] + cls.bl_category = sidebar["category"] + bpy.utils.register_class(cls) + + # Tools (T-Panel) Area + for cls in tools_area_classes: + cls.bl_space_type = tools["space"] + cls.bl_region_type = tools["region"] + cls.bl_context = tools["context"] + cls.bl_category = tools["category"] + bpy.utils.register_class(cls) + + # Update Preferences with current settings and save + addon_prefs.default_layout = panel_layout + + addon_prefs.default_main_location = main_location + addon_prefs.default_operation_location = operation_location + addon_prefs.default_tools_location = tools_location + + bpy.ops.wm.save_userpref() + + +def update_user_layout(self, context): + # Update the settings for the User layout preset + main_location = context.scene.interface.main_location + operation_location = context.scene.interface.operation_location + tools_location = context.scene.interface.tools_location + + addon_prefs = context.preferences.addons["bl_ext.user_default.fabex"].preferences + addon_prefs.user_main_location = main_location + addon_prefs.user_operation_location = operation_location + addon_prefs.user_tools_location = tools_location + + bpy.ops.wm.save_userpref() + + +# update_layout(self, context) + + class CAM_INTERFACE_Properties(PropertyGroup): level: EnumProperty( name="Interface", description="Choose visible options", items=[ - ("0", "Basic", "Only show essential options"), - ("1", "Advanced", "Show advanced options"), - ("2", "Complete", "Show all options"), - ("3", "Experimental", "Show experimental options"), + ("0", "Basic", "Only show essential options", "", 0), + ("1", "Advanced", "Show advanced options", "", 1), + ("2", "Complete", "Show all options", "", 2), + ("3", "Experimental", "Show experimental options", "EXPERIMENTAL", 3), ], default="0", update=update_interface, ) + + shading: EnumProperty( + name="Shading", + description="Choose viewport shading preset", + items=[ + ("DEFAULT", "Default", "Standard viewport shading"), + ("DELUXE", "Deluxe", "Cavity, Curvature, Depth of Field, Shadows & Object Colors"), + ("CLEAN_DEFAULT", "Clean Default", "Standard viewport shading with no overlays"), + ("CLEAN_DELUXE", "Clean Deluxe", "Deluxe shading with no overlays"), + ("PREVIEW", "Preview", "HDRI Lighting Preview"), + ], + default="DEFAULT", + update=update_shading, + ) + + layout: EnumProperty( + name="Layout", + description="Presets for all panel locations", + items=[ + ( + "CLASSIC", + "Classic", + "Properties Area holds most panels, Tools holds the rest", + ), + ( + "MODERN", + "Modern", + "Properties holds Main panels, Sidebar holds Operation panels, Tools holds Tools", + ), + ( + "USER", + "User", + "Define your own locations for panels", + ), + ], + default="MODERN", + update=update_layout, + ) + + main_location: EnumProperty( + name="Main Panels", + description="Location for Chains, Operations, Material, Machine, Pack, Slice Panels", + items=[ + ( + "PROPERTIES", + "Properties", + "Default panel location is the Render tab of the Properties Area", + ), + ( + "SIDEBAR", + "Sidebar (N-Panel)", + "Common location for addon UI, press N to show/hide", + ), + ( + "TOOLS", + "Tools (T-Panel)", + "Blender's Tool area, press T to show/hide", + ), + ], + default="PROPERTIES", + update=update_user_layout, + ) + + operation_location: EnumProperty( + name="Operation Panels", + description="Location for Setup, Area, Cutter, Feedrate, Optimisation, Movement, G-code", + items=[ + ( + "PROPERTIES", + "Properties", + "Default panel location is the Render tab of the Properties Area", + ), + ( + "SIDEBAR", + "Sidebar (N-Panel)", + "Common location for addon UI, press N to show/hide", + ), + ( + "TOOLS", + "Tools (T-Panel)", + "Blender's Tool area, press T to show/hide", + ), + ], + default="SIDEBAR", + update=update_user_layout, + ) + + tools_location: EnumProperty( + name="Tools Panels", + description="Location for Curve Tools, Curve Creators, Info", + items=[ + ( + "PROPERTIES", + "Properties", + "Default panel location is the Render tab of the Properties Area", + ), + ( + "SIDEBAR", + "Sidebar (N-Panel)", + "Common location for addon UI, press N to show/hide", + ), + ( + "TOOLS", + "Tools (T-Panel)", + "Blender's Tool area, press T to show/hide", + ), + ], + default="TOOLS", + update=update_user_layout, + ) + + +def draw_interface(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + if context.engine == "FABEX_RENDER": + col = layout.column() + col.prop(context.scene.interface, "level") + col.prop(context.scene.interface, "layout") + col.prop(context.scene.interface, "shading") diff --git a/scripts/addons/cam/utils.py b/scripts/addons/cam/utils.py index 3e8ffecca..1a9d0942a 100644 --- a/scripts/addons/cam/utils.py +++ b/scripts/addons/cam/utils.py @@ -435,7 +435,7 @@ def getBounds(o): or o.max.z - o.min.z > m.working_area.z ): o.info.warnings += "Operation Exceeds Your Machine Limits\n" - bpy.ops.cam.popup("INVOKE_DEFAULT") + bpy.ops.cam.popup("INVOKE_DEFAULT") def getBoundsMultiple(operations): @@ -2139,6 +2139,22 @@ def addMachineAreaObject(): # else: # bpy.context.scene.objects.active = None + # Update Viewport Shading for better previews + + # view3d = [a.spaces[0] for a in bpy.context.screen.areas if a.type == "VIEW_3D"][0] + + # shading = view3d.shading + # shading.color_type = "OBJECT" + # shading.show_shadows = True + # shading.show_cavity = True + # shading.cavity_type = "BOTH" + # shading.cavity_ridge_factor = 2.5 + # shading.cavity_valley_factor = 2.5 + # shading.curvature_ridge_factor = 2 + # shading.curvature_valley_factor = 2 + # shading.use_dof = True + # shading.show_object_outline = True + def addMaterialAreaObject(): """Add a material area object to the current Blender scene. @@ -3038,7 +3054,7 @@ def getStrategyList(scene, context): "CIRCLES", "Circles", "Circles path", - "MESH_CIRCLE", + "ONIONSKIN_ON", 7, ), ( @@ -3210,14 +3226,23 @@ def check_operations_on_load(context): except KeyError: bpy.ops.extensions.package_install(repo_index=0, pkg_id=module) - s = bpy.context.scene - for o in s.cam_operations: + scene = bpy.context.scene + for o in scene.cam_operations: if o.computing: o.computing = False # set interface level to previously used level for a new file if not bpy.data.filepath: _IS_LOADING_DEFAULTS = True - s.interface.level = addon_prefs.default_interface_level + + scene.interface.level = addon_prefs.default_interface_level + scene.interface.shading = addon_prefs.default_shading + + scene.interface.layout = addon_prefs.default_layout + + scene.interface.main_location = addon_prefs.default_main_location + scene.interface.operation_location = addon_prefs.default_operation_location + scene.interface.tools_location = addon_prefs.default_tools_location + machine_preset = addon_prefs.machine_preset = addon_prefs.default_machine_preset if len(machine_preset) > 0: print("Loading Preset:", machine_preset) diff --git a/scripts/addons/cam/version.py b/scripts/addons/cam/version.py index 87573e1d2..4ccc678fd 100644 --- a/scripts/addons/cam/version.py +++ b/scripts/addons/cam/version.py @@ -1 +1 @@ -__version__=(1,0,54) \ No newline at end of file +__version__ = (1, 0, 54)