Skip to content
Snippets Groups Projects
utility_gui.py 13.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • # SPDX-License-Identifier: GPL-2.0-or-later
    
    
    import bpy
    from bpy.types import Operator, Panel
    from bpy.props import (StringProperty,
                           EnumProperty,
                           FloatProperty,
                           BoolProperty)
    
    from io_mesh_atomic.utility_panel import choose_objects
    from io_mesh_atomic.utility_panel import custom_datafile
    from io_mesh_atomic.utility_panel import custom_datafile_change_atom_props
    from io_mesh_atomic.utility_panel import separate_atoms
    from io_mesh_atomic.utility_panel import distance
    
    
    # -----------------------------------------------------------------------------
    #                                                                           GUI
    
    # The panel.
    class PANEL_PT_prepare(Panel):
        bl_label       = "Atomic Blender Utilities"
        bl_space_type  = "VIEW_3D"
        bl_region_type = "UI"
        bl_options     = {'DEFAULT_CLOSED'}
    
        bl_category = "Create"
    
        bl_idname = "ATOMIC_PT_utilities"
    
    
    
        # This thing here just guarantees that the panel is NOT opened when the
    
        # check box in the addon preferences is not activated! See __init__.py
        @classmethod
        def poll(cls, context):
            pref = context.preferences
            return pref.addons[__package__].preferences.bool_utility
    
        def draw(self, context):
            layout = self.layout
            scn    = context.scene.atom_blend
    
            box = layout.box()
            col = box.column(align=True)
            col.label(text="Custom data file")
            col.prop(scn, "datafile")
            col.operator("atom_blend.datafile_apply")
    
            box = layout.box()
            col = box.column(align=True)
            col.label(text="Measure distances")
            col.operator("atom_blend.button_distance")
            col.prop(scn, "distance")
    
            box = layout.box()
            col = box.column(align=True)
            col.label(text="Change atom size")
            col.label(text="1. Type of radii")
            col.prop(scn, "radius_type")
            col2 = col.column()
            col2.active = (scn.radius_type == '3')
            col2.prop(scn, "radius_type_ionic")
            col = box.column(align=True)
            col.label(text="2. Radii in pm")
            col.prop(scn, "radius_pm_name")
            col.prop(scn, "radius_pm")
            col = box.column(align=True)
            col.label(text="3. Radii by scale")
            col.prop(scn, "radius_all")
            row = col.row()
            row.operator("atom_blend.radius_all_smaller")
            row.operator("atom_blend.radius_all_bigger")
    
            box = layout.box()
            col = box.column(align=True)
            col.label(text="Change stick size")
            col.prop(scn, "sticks_all")
            row = col.row()
            row.operator("atom_blend.sticks_all_smaller")
            row.operator("atom_blend.sticks_all_bigger")
    
            box = layout.box()
            col = box.column(align=True)
            col.label(text="Change atom shape")
            col2 = col.column()
            col2.active = (scn.replace_objs_special == '0')
            col2.prop(scn, "replace_objs")
            col2.prop(scn, "replace_objs_material")
            col.prop(scn, "replace_objs_special")
            col.operator("atom_blend.replace_atom")
            col.label(text="Default values")
            col.operator("atom_blend.default_atoms")
    
            box = layout.box()
            col = box.column(align=True)
            col.label(text="Separate atoms")
            col3 = col.column()
            col3.active = (bpy.context.mode == 'EDIT_MESH')
            col3.operator("atom_blend.separate_atom")
    
    
    # The properties of buttons etc. in the panel.
    class PanelProperties(bpy.types.PropertyGroup):
    
        def Callback_radius_type(self, context):
            scn = bpy.context.scene.atom_blend
            choose_objects("ATOM_RADIUS_TYPE",
                           None,
                           None,
                           scn.radius_type,
                           scn.radius_type_ionic,
                           None)
        def Callback_radius_pm(self, context):
            scn = bpy.context.scene.atom_blend
            choose_objects("ATOM_RADIUS_PM",
                           None,
                           [scn.radius_pm_name,
                           scn.radius_pm],
                           None,
                           None,
                           None)
    
        datafile: StringProperty(
            name = "", description="Path to your custom data file",
            maxlen = 256, default = "", subtype='FILE_PATH')
        XYZ_file: StringProperty(
            name = "Path to file", default="",
            description = "Path of the XYZ file")
        number_atoms: StringProperty(name="",
            default="Number", description = "This output shows "
            "the number of atoms which have been loaded")
        distance: StringProperty(
            name="", default="Distance (A)",
            description="Distance of 2 objects in Angstrom")
        replace_objs: EnumProperty(
            name="Shape",
    
            description="Choose a different atom shape",
    
            items=(('0',"Unchanged", "Do not change the shape"),
                   ('1a',"Sphere (Mesh)", "Replace with a sphere (Mesh)"),
                   ('1b',"Sphere (NURBS)", "Replace with a sphere (NURBS)"),
                   ('2',"Cube", "Replace with a cube"),
                   ('3',"Plane", "Replace with a plane"),
                   ('4a',"Circle (Mesh)", "Replace with a circle (Mesh)"),
                   ('4b',"Circle (NURBS)", "Replace with a circle (NURBS)"),
                   ('5a',"Icosphere 1", "Replace with a icosphere, subd=1"),
                   ('5b',"Icosphere 2", "Replace with a icosphere, subd=2"),
                   ('5c',"Icosphere 3", "Replace with a icosphere, subd=3"),
                   ('5d',"Icosphere 4", "Replace with a icosphere, subd=4"),
                   ('5e',"Icosphere 5", "Replace with a icosphere, subd=5"),
                   ('6a',"Cylinder (Mesh)", "Replace with a cylinder (Mesh)"),
                   ('6b',"Cylinder (NURBS)", "Replace with a cylinder (NURBS)"),
                   ('7',"Cone", "Replace with a cone"),
                   ('8a',"Torus (Mesh)", "Replace with a torus (Mesh)"),
                   ('8b',"Torus (NURBS)", "Replace with a torus (NURBS)")),
                   default='0',)
        replace_objs_material: EnumProperty(
            name="Material",
    
            description="Choose a different material",
    
            items=(('0',"Unchanged", "Leave the material unchanged"),
                   ('1',"Normal", "Use normal material (no transparency and reflection)"),
                   ('2',"Transparent", "Use transparent material"),
                   ('3',"Reflecting", "Use reflecting material"),
                   ('4',"Transparent + reflecting", "Use transparent and reflecting material")),
                   default='0',)
        replace_objs_special: EnumProperty(
            name="Special",
    
            description="Choose a special atom shape",
    
            items=(('0',"None", "Use no special shape."),
                   ('1',"F2+ center", "Replace with a F2+ center"),
                   ('2',"F+ center", "Replace with a F+ center"),
                   ('3',"F0 center", "Replace with a F0 center")),
                   default='0',)
        radius_type: EnumProperty(
            name="Type",
            description="Which type of atom radii?",
            items=(('0',"predefined", "Use pre-defined radii"),
                   ('1',"atomic", "Use atomic radii"),
                   ('2',"van der Waals","Use van der Waals radii"),
                   ('3',"ionic radii", "Use ionic radii")),
                   default='0',update=Callback_radius_type)
        radius_type_ionic: EnumProperty(
            name="Charge",
    
            description="Charge state of the ions if existing",
    
            items=(('0',"-4", "Charge state -4"),
                   ('1',"-3", "Charge state -3"),
                   ('2',"-2", "Charge state -2"),
                   ('3',"-1", "Charge state -1"),
                   ('4'," 0", "Charge state  0: nothing is done"),
                   ('5',"+1", "Charge state +1"),
                   ('6',"+2", "Charge state +2"),
                   ('7',"+3", "Charge state +3"),
                   ('8',"+4", "Charge state +4"),
                   ('9',"+5", "Charge state +5"),
                   ('10',"+6", "Charge state +6"),
                   ('11',"+7", "Charge state +7")),
                   default='4',update=Callback_radius_type)
        radius_pm_name: StringProperty(
            name="", default="Atom name",
            description="Put in the name of the atom (e.g. Hydrogen)")
        radius_pm: FloatProperty(
            name="", default=100.0, min=0.0,
            description="Put in the radius of the atom (in pm)",
            update=Callback_radius_pm)
        radius_all: FloatProperty(
            name="Scale", default = 1.05, min=1.0, max=5.0,
            description="Put in the scale factor")
        sticks_all: FloatProperty(
            name="Scale", default = 1.05, min=1.0, max=5.0,
            description="Put in the scale factor")
    
    
    # Button loading a custom data file
    class DatafileApply(Operator):
        bl_idname = "atom_blend.datafile_apply"
        bl_label = "Apply"
        bl_description = "Use color and radii values stored in the custom file"
    
        def execute(self, context):
            scn = bpy.context.scene.atom_blend
    
            if scn.datafile == "":
                return {'FINISHED'}
    
            custom_datafile(scn.datafile)
            custom_datafile_change_atom_props()
    
            return {'FINISHED'}
    
    
    # Button for separating single atoms from a dupliverts structure
    class DefaultAtom(Operator):
        bl_idname = "atom_blend.default_atoms"
        bl_label = "Default"
    
        bl_description = ("Use default shapes and colors for atoms")
    
    
        # Are we in the OBJECT mode?
        @classmethod
        def poll(self, context):
            if bpy.context.mode == 'OBJECT':
                return True
            else:
                return False
    
        def execute(self, context):
            scn = bpy.context.scene.atom_blend
            choose_objects("ATOM_DEFAULT_OBJ",
                           None,
                           None,
                           None,
                           None,
                           None)
            return {'FINISHED'}
    
    
    # Button for separating single atoms from a dupliverts structure
    class ReplaceAtom(Operator):
        bl_idname = "atom_blend.replace_atom"
        bl_label = "Replace"
    
        bl_description = ("Replace selected atoms with atoms of different shape")
    
    
        # Are we in the OBJECT mode?
        @classmethod
        def poll(self, context):
            if bpy.context.mode == 'OBJECT':
                return True
            else:
                return False
    
        def execute(self, context):
            scn = bpy.context.scene.atom_blend
            choose_objects("ATOM_REPLACE_OBJ",
                           None,
                           None,
                           None,
                           None,
                           None)
            return {'FINISHED'}
    
    
    # Button for separating single atoms from a dupliverts structure
    class SeparateAtom(Operator):
        bl_idname = "atom_blend.separate_atom"
        bl_label = "Separate"
        bl_description = ("Separate selected atoms in a dupliverts structure. "
                          "You have to be in the 'Edit Mode'")
    
        # Are we in the EDIT mode?
        @classmethod
        def poll(self, context):
            if bpy.context.mode == 'EDIT_MESH':
                return True
            else:
                return False
    
        def execute(self, context):
            scn = bpy.context.scene.atom_blend
    
            separate_atoms(scn)
    
            return {'FINISHED'}
    
    
    # Button for measuring the distance of active objects
    class DistanceButton(Operator):
        bl_idname = "atom_blend.button_distance"
        bl_label = "Measure ..."
    
        bl_description = "Measure the distance between two atoms (objects)"
    
    
        def execute(self, context):
            scn  = bpy.context.scene.atom_blend
            dist = distance()
    
            # Put the distance into the string of the output field.
            scn.distance = dist
            return {'FINISHED'}
    
    
    # Button for increasing the radii of all selected atoms
    class RadiusAllBiggerButton(Operator):
        bl_idname = "atom_blend.radius_all_bigger"
        bl_label = "Bigger ..."
        bl_description = "Increase the radii of selected atoms"
    
        def execute(self, context):
            scn = bpy.context.scene.atom_blend
            choose_objects("ATOM_RADIUS_ALL",
                           scn.radius_all,
                           None,
                           None,
                           None,
                           None)
            return {'FINISHED'}
    
    
    # Button for decreasing the radii of all selected atoms
    class RadiusAllSmallerButton(Operator):
        bl_idname = "atom_blend.radius_all_smaller"
        bl_label = "Smaller ..."
        bl_description = "Decrease the radii of selected atoms"
    
        def execute(self, context):
            scn = bpy.context.scene.atom_blend
            choose_objects("ATOM_RADIUS_ALL",
                           1.0/scn.radius_all,
                           None,
                           None,
                           None,
                           None)
            return {'FINISHED'}
    
    
    # Button for increasing the radii of all selected sticks
    class SticksAllBiggerButton(Operator):
        bl_idname = "atom_blend.sticks_all_bigger"
        bl_label = "Bigger ..."
        bl_description = "Increase the radii of selected sticks"
    
        def execute(self, context):
            scn = bpy.context.scene.atom_blend
            choose_objects("STICKS_RADIUS_ALL",
                           None,
                           None,
                           None,
                           None,
                           scn.sticks_all)
            return {'FINISHED'}
    
    
    # Button for decreasing the radii of all selected sticks
    class SticksAllSmallerButton(Operator):
        bl_idname = "atom_blend.sticks_all_smaller"
        bl_label = "Smaller ..."
        bl_description = "Decrease the radii of selected sticks"
    
        def execute(self, context):
            scn = bpy.context.scene.atom_blend
            choose_objects("STICKS_RADIUS_ALL",
                           None,
                           None,
                           None,
                           None,
                           1.0/scn.sticks_all)
            return {'FINISHED'}