예제 #1
0
    def execute(self, context):
        if self.bones:
            bones = eval(self.bones)
        else:
            bones = Get.selected_pose_bones(context)

        if not bones:
            return {'CANCELLED'}

        wgts = readWidgets()
        if self.widget:
            widget = wgts[self.widget]
        else:
            widget = wgts[context.scene.widget_list]

        for bone in bones:
            if bone.id_data.proxy:
                continue
            slide = list(self.slide)
            rotate = list(self.rotate)
            if self.mirror:
                mirror = findMirrorObject(bone)
                if mirror and mirror in bones and bone.name.endswith(
                    ('L', 'l')):
                    slide[0] *= -1
                    rotate[1] *= -1
                    rotate[2] *= -1

            createWidget(
                context,
                bone,
                widget,
                self.relative_size,
                self.global_size,
                [*self.scale],
                slide,
                rotate,
                get_collection(context),
            )

        utils.update(context)

        pr = utils.prefs(__addon__).bone_widgets
        # pr = prefs.prefs().bone_widgets
        if pr.keep_settings:
            pr.slide = self.slide
            pr.rotate = self.rotate
            pr.relative_size = self.relative_size
            pr.global_size = self.global_size
            pr.scale = self.scale
            pr.mirror = self.mirror

        # Create new object then delete it.
        # When creating multiple widgets, if the last one tries to enter edit
        # mode before a particular update occurs, Blender will crash.
        # If the last object created (I.E. this empty) is not the widget,
        # Blender can enter edit mode without crash
        Get.objects(context, link=True).unlink(New.object(context))

        return {'FINISHED'}
예제 #2
0
    def execute(self, context):
        prefs = utils.prefs().inputs

        old = prefs.use_zoom_to_mouse
        prefs.use_zoom_to_mouse = True

        prefs2 = utils.prefs().inputs

        old2 = prefs2.use_mouse_depth_navigate
        prefs2.use_mouse_depth_navigate = True

        bpy.ops.view3d.dolly('INVOKE_DEFAULT')
        prefs.use_zoom_to_mouse = old
        prefs2.use_mouse_depth_navigate = old2

        return {'FINISHED'}
예제 #3
0
    def draw(self, context):
        layout = self.layout
        src = context.src
        mp = context.mp
        mpath = src.motion_path

        layout.prop(mp, 'show_frame_numbers')  # , text="Frame Numbers")
        layout.prop(mp, 'show_keyframe_highlight')  # , text="Keyframes")
        if mp.show_keyframe_highlight:
            if Is.posebone(src):
                layout.prop(mp,
                            'show_keyframe_action_all',
                            text="+ Non-Grouped Keyframes")
            layout.prop(mp, 'show_keyframe_numbers', text="Keyframe Numbers")

        layout.separator()
        if Is.posebone(src):
            layout.label(text=src.name, icon='BONE_DATA')
        else:
            layout.label(text=src.name, icon='OBJECT_DATA')
        if mpath:
            layout.prop(mpath, 'lines')  # , text="Lines")
            layout.prop(mpath, 'use_custom_color')  # , text="Custom Color")
        else:
            op = 'zpy.update_motion_paths'
            layout.label(text="Add Motion Paths")
            layout.operator(op, text="At Heads").use_tails = False
            layout.operator(op, text="At Tails").use_tails = True

        layout.separator()
        mot = utils.prefs(__package__).motion
        layout.prop(mot, 'frame_before')
        layout.prop(mot, 'frame_after')
예제 #4
0
    def invoke(self, context, event):
        addon_prefs = utils.prefs(__package__).change_frame
        scene = context.scene
        space_data = context.space_data

        # hide viewport helpers
        if (context.area.type == 'VIEW_3D'):
            self.previousManipulator = space_data.show_gizmo
            # space_data.show_gizmo = False

            if (self.renderOnly):
                self.previousOnlyRender = space_data.overlay.show_overlays
                space_data.overlay.show_overlays = False

        # start modal
        if (addon_prefs.boolSmoothDrag):
            self.frameOffset = scene.frame_current_final
        else:
            self.frameOffset = scene.frame_current

        self.mouseOffset = event.mouse_x
        self.startButton = event.type

        # cursor
        context.window.cursor_set("SCROLL_X")

        self.text = []
        bpy.types.STATUSBAR_HT_header.prepend(self.draw_status)
        context.window_manager.modal_handler_add(self)

        found = False

        # auto sensitivity
        if (self.autoSensitivity):

            ratio = (1024 / context.area.width)
            self.sensitivity = (ratio / 10)

            # finding end of frame range
            if (scene.use_preview_range):
                endFrame = scene.frame_preview_end
            else:
                endFrame = scene.frame_end

            self.sensitivity *= (endFrame / 100)

            found = True

        # default
        if (not found):
            self.sensitivity = self.defaultSensitivity / 100

        if context.screen.is_animation_playing:
            bpy.ops.screen.animation_cancel(restore_frame=False)

        return {'RUNNING_MODAL'}
    def invoke(self, context, event):
        if event.alt:
            for action in bpy.data.actions:
                # bases = a.base_interpolations.
                for fc in action.fcurves:
                    for key in fc.keyframe_points:
                        key.interpolation = self.type
        utils.prefs().edit.keyframe_new_interpolation_type = self.type

        return {'FINISHED'}
예제 #6
0
    def execute(self, context):
        prefs = utils.prefs().inputs

        old = prefs.use_mouse_depth_navigate
        prefs.use_mouse_depth_navigate = True

        bpy.ops.view3d.rotate('INVOKE_DEFAULT')
        prefs.use_mouse_depth_navigate = old

        return {'FINISHED'}
예제 #7
0
파일: panels.py 프로젝트: Irmitya/zpy__mods
    def draw(self, context):
        layout = self.layout

        layout.operator('bonewidget.symmetrize_shape', icon='MOD_MIRROR')
        layout.operator('bonewidget.match_bone_transforms', icon='GROUP_BONE')

        layout.operator('bonewidget.add_widgets', icon='ADD', text="Add Widgets")
        layout.operator('bonewidget.remove_widgets', icon='REMOVE', text="Remove Widgets")

        pr = utils.prefs(__addon__).bone_widgets
        layout.prop(pr, 'keep_settings')
예제 #8
0
def toggle_auto_save(scn, context=None):
    if not scn:
        # Prevent error on startup
        scn = bpy.context.scene

    prefs = utils.prefs().filepaths

    if (prefs.use_auto_save_temporary_files != scn.use_auto_save):
        prefs.use_auto_save_temporary_files = scn.use_auto_save

    if bpy.data.filepath.startswith(ignored):
        prefs.use_auto_save_temporary_files = False
예제 #9
0
파일: panels.py 프로젝트: Irmitya/zpy__mods
    def draw(self, context):
        layout = self.layout

        row = layout.row(align=True)
        if len(bpy.types.Scene.widget_list[1]['items']) < 6:
            row.prop(context.scene, 'widget_list', expand=True)
        else:
            row.prop(context.scene, 'widget_list', expand=False, text="")

        row = layout.row(align=True)
        row.menu('BONEWIDGET_MT_bw_specials', icon='DOWNARROW_HLT', text="")
        create = row.operator('bonewidget.create_widget', icon='OBJECT_DATAMODE')

        if context.mode == "POSE":
            row.operator('bonewidget.edit_widget', icon='OUTLINER_DATA_MESH')
            row.operator('bonewidget.remove_widget', text="", icon='X')
        else:
            row.operator('bonewidget.return_to_armature', icon='LOOP_BACK', text='To bone')

        if bpy.ops.bonewidget.create_widget.poll():
            pr = utils.prefs(__addon__).bone_widgets

            row = layout.row()
            row.label(text="Slide:", icon='ORIENTATION_GLOBAL')
            row.prop(pr, 'mirror')
            layout.row().prop(pr, 'slide', text="")
            create.slide = pr.slide

            layout.label(text="Rotation:", icon='ORIENTATION_LOCAL')
            layout.row().prop(pr, 'rotate', text="")
            create.rotate = pr.rotate

            row = layout.row()
            row.label(text="Scale", icon='ORIENTATION_VIEW')
            row.prop(pr, 'relative_size')
            layout.prop(pr, 'global_size', expand=False)
            layout.row().prop(pr, 'scale', text="")
            create.relative_size = pr.relative_size
            create.global_size = pr.global_size
            create.scale = pr.scale
예제 #10
0
    def draw(self, context):
        layout = self.layout.column(align=True)

        camera = context.object.data
        prefs = utils.prefs(__package__)

        # col = layout.row(align=True)
        # display_camera = prefs.get("Toggle Camera props")
        # if display_camera:
        #     draw_camera(context, col.row(), obj)
        # col = col.row()
        # col.emboss = 'PULLDOWN_MENU'
        # prefs.prop(
        #     col, "Toggle Camera props", icon='CAMERA_DATA',
        # )

        # dof_obj = camera.dof.focus_object
        args = dict(text="", toggle=False)
        cdtt = prefs.camera_dof_target_type

        if not camera.dof.focus_object:
            layout.operator(
                PROPS_OT_toggle_camera.bl_idname,
                text=("Value", "Target")[cdtt],
                icon=('EMPTY_AXIS', 'OBJECT_DATA')[cdtt],
            )

        # row = layout.grid_flow(row_major=False, columns=0, even_columns=False, even_rows=False, align=True)
        row = layout.row(align=True)
        if cdtt or camera.dof.focus_object:
            row.prop(camera.dof, 'focus_object', icon='OBJECT_ORIGIN', **args)
        else:
            row.prop(camera, 'show_limits', icon='OBJECT_ORIGIN', **args)
            row.prop(camera.dof, 'focus_distance', icon='NONE', **args)

        layout.prop(camera.dof, 'aperture_fstop', icon='NONE', **args)

        row = layout.row(align=True)
        row.prop(camera, 'display_size', icon='NONE', **args)
    def execute(self, context):
        scn = context.scene
        active = Get.active(context)
        selected = Get.selected(context)
        is_pose = bool(context.mode == 'POSE')

        if not is_pose:
            self.use_tails = False
        mode = ('HEADS', 'TAILS')[self.use_tails]

        # Use the line thickness of the active item, across the selection
        if getattr(active, 'motion_path', None):
            line = active.motion_path.line_thickness
        else:
            line = 1

        colors = dict()
        types = dict()
        for src in Get.selected(context):
            mp = src.motion_path
            if not mp:
                continue

            if mp.use_custom_color:
                colors[src] = mp.color

            if Is.posebone(src):
                display = src.id_data.pose.animation_visualization.motion_path
            else:
                display = src.animation_visualization.motion_path

            types[src] = display.type

        # Get the frame range to bake motion paths in
        motion = utils.prefs(__package__).motion

        if self.use_start_end:
            start = self.start_frame
            end = self.end_frame
        elif (motion.use_relative_range) or (scn.use_preview_range):
            start = scn.frame_preview_start
            end = scn.frame_preview_end
            fc = scn.frame_current
            fb = motion.frame_before
            fa = motion.frame_after

            if not (scn.use_preview_range) or (abs(end - start) > 100 >
                                               (fb + fa)):
                # If the preview range is too high, just default to nearby
                start = fc - fb
                end = fc + fa
        else:
            # if (active):
            # # Use the active object's motion path's in_range distance
            # if (Is.posebone(active)):
            #     mp = active.id_data.pose.animation_visualization.motion_path
            # else:
            #     mp = active.animation_visualization.motion_path
            # fb = mp.frame_before
            # fa = mp.frame_after
            # if (fb < 25): fb = 25
            # if (fa < 25): fa = 25

            # start = scn.frame_current - fb
            # end = scn.frame_current + fa
            start = scn.frame_start
            end = scn.frame_end
            fc = scn.frame_current
            if 150 < abs(end - start):
                start = fc - 50
                end = fc + 50

        # Create the motion paths
        args = dict(start_frame=start, end_frame=end + 1)
        if is_pose:
            op = bpy.ops.pose
            args['bake_location'] = mode

            # Operator only runs on active rig, so repeat for all in pose mode
            obs = {b.id_data for b in selected}

            for ob in obs:
                Set.active(context, ob)
                op.paths_clear(only_selected=True)
                op.paths_calculate(**args)
            else:
                Set.active(context, active)
        else:
            op = bpy.ops.object
            op.paths_clear(only_selected=True)
            op.paths_calculate(**args)

        for src in selected:
            mp = src.motion_path
            if not mp: continue

            mp.line_thickness = line
            color = colors.get(src)
            if color:
                mp.color = color

            if Is.posebone(src):
                display = src.id_data.pose.animation_visualization.motion_path
            else:
                display = src.animation_visualization.motion_path
            display.type = types.get(src, 'CURRENT_FRAME')

        # Set to use the frame hider instead of ever displaying all points
        # if is_pose:
        #     src.id_data.pose.animation_visualization. \
        #         motion_path.type = 'CURRENT_FRAME'
        # else:
        #     src.animation_visualization. \
        #         motion_path.type = 'CURRENT_FRAME'
        # scn.frame_set(scn.frame_current)

        return {'FINISHED'}
예제 #12
0
    def execute(self, context):
        prefs = utils.prefs(__package__)
        prefs.camera_dof_target_type = not prefs.camera_dof_target_type

        return {'INTERFACE'}
예제 #13
0
def manual(context, src, path, **kargs):
    "Insert a keyframe manually. Sub is for sub targets, like constraints"
    # kargs:
    # sub=None, index=-1, frame=None, value=None,
    # group=None, insert_key=None, action=None, context=None

    insert_key = kargs.get('insert_key', None)
    sub = kargs.get('sub', None)
    index = kargs.get('index', -1)
    frame = kargs.get('frame', None)
    value = kargs.get('value', None)
    group = kargs.get('group', None)
    action = kargs.get('action', None)
    results = kargs.get('results', list())
    options = kargs.get('options', set())
    delete = kargs.get('delete', False)

    keyframe_type = kargs.get('type',
                              context.scene.tool_settings.keyframe_type)

    if not keyframe.poll_insert(context, insert_key, src=src):
        return results

    # if frame is None:
    #     frame = context.scene.frame_current
    # if group is None:
    #     group = keyframe.group_name(src)
    # src.keyframe_insert(path, index=index, frame=frame, group=group)
    # return

    if group is None:
        group = keyframe.group_name(src)

    obj = src.id_data
    anim = obj.animation_data_create()
    if action is None:
        key_in_action = True
        action = anim.action
        if action is None:
            action = anim.action = bpy.data.actions.new("Action")
    else:
        # When using a specified action, don't insert
        # keyframes later to determine the property's value
        key_in_action = False

    if frame is None:
        frame = context.scene.frame_current_final

    strip = Get.active_strip(anim) if anim.use_tweak_mode else None

    if strip:
        if not (strip.frame_start <= frame <= strip.frame_end):
            # frame outside of the strip's bounds
            key_in_action = False

        tweak_frame = Get.frame_to_strip(context, anim, frame=frame)
    else:
        tweak_frame = frame

    if Is.posebone(src) and not path.startswith('pose.bones'):
        keypath = utils.string('pose.bones[\"', src.name, '\"]',
                               '' if path.startswith('[') else '.', path)
    elif not Is.object(src) and hasattr(src, 'path_from_id'):
        keypath = src.path_from_id(path)
    else:
        keypath = path

    # Find the value(s) to insert keyframes for
    if hasattr(sub, path):
        base = getattr(sub, path)
    elif hasattr(src, path):
        base = getattr(src, path)
    else:
        base = eval(f'{obj!r}.{keypath}')

    if value is None:
        prop = base
    else:
        if Is.iterable(base) and not Is.iterable(value):
            prop = [value for i in base]
        elif not Is.iterable(base) and Is.iterable(value):
            prop = value[(index, 0)[index == -1]]
        else:
            prop = value

    if (not Is.iterable(prop)):
        if index != -1:
            index = -1
        if (not Is.iterable(prop)):
            props = [(index, prop)]
        else:
            props = [(index, prop[index])]
    elif (index == -1):
        props = list(enumerate(prop))
    else:
        props = [(index, prop[index])]

    def save_quats():
        quats = [0, 0, 0, 0]
        for index in range(4):
            fc = Get.fcurve(action, keypath, index=index)
            if fc:
                quats[index] = len(fc.keyframe_points)
        return quats

    def restore_quats(skip):
        nonlocal quats
        for index in range(4):
            if index == skip:
                continue
            fc = Get.fcurve(action, keypath, index=index)
            if fc and len(fc.keyframe_points) > quats[index]:
                for key in fc.keyframe_points:
                    if key.co.x == tweak_frame:
                        fc.keyframe_points.remove(key)
                        break
                else:
                    # Shouldn't happen but backup in case fail to find key
                    key_args = dict(index=index, frame=frame, group=group)
                    if sub is None:
                        src.keyframe_delete(path, **key_args)
                    else:
                        sub.keyframe_delete(path, **key_args)

    if path.endswith('rotation_quaternion') and (
        (strip and strip.blend_type == 'COMBINE') or
        (not strip and anim.action_blend_type == 'COMBINE')):
        # Combine forces keyframe insertion on all 4 channels, so reset them
        quats = save_quats()
    else:
        quats = None

    # Create curve(s) (if needed) and keyframe(s)
    for (i, v) in props:
        fc = Get.fcurve(action, keypath, i)
        new_fc = not bool(fc)
        if new_fc:
            fc = New.fcurve(action, keypath, index=i, group=group)

        if fc.lock:
            # Internal ops don't allow keyframing locked channels, so :p
            results.append((fc, None))
            continue

        if delete:
            results.append((fc, src.keyframe_delete(path, frame=frame)))
            continue

        count = len(fc.keyframe_points)

        if (value is None) and key_in_action:
            key_args = dict(index=i, frame=frame, group=group, options=options)
            if sub is None:
                src.keyframe_insert(path, **key_args)
            else:
                sub.keyframe_insert(path, **key_args)
            v = fc.evaluate(tweak_frame)

        key = fc.keyframe_points.insert(tweak_frame, v, options={'FAST'})
        # options=set({'REPLACE', 'NEEDED', 'FAST'})
        # src.keyframe_insert(path, index=i, frame=frame, group=group)

        if quats:
            restore_quats(skip=i)
            quats[i] = len(fc.keyframe_points)
            # Update key count for current index, to not remove it later

        # Update keyframe to use default preferences values

        edit = utils.prefs().edit

        key.handle_left_type = key.handle_right_type = \
            edit.keyframe_new_handle_type
        if new_fc:
            # When inserting keyframes, only change their interpolation type if the fcurve is new
            key.interpolation = edit.keyframe_new_interpolation_type

        if len(fc.keyframe_points) > count:
            # New keyframe was added
            key.type = keyframe_type

        results.append((fc, key))

    if kargs.get('index', -1) == -1:
        return results
    else:
        return results[0]
예제 #14
0
def draw_header(self, context):
    layout = self.layout

    prefs = utils.prefs(__package__).motion

    if context.mode == 'POSE':
        src = context.active_pose_bone
    else:
        src = context.object

    if not src:
        return

    layout.separator()
    sub = layout.row()
    sub.emboss = ('PULLDOWN_MENU', 'NORMAL')[prefs.show_panel]
    sub.active = prefs.show_panel
    sub.prop(prefs, 'show_panel', text="", icon='CURVE_DATA')

    if not prefs.show_panel:
        return

    if Is.posebone(src):
        mp = src.id_data.pose.animation_visualization.motion_path
    else:
        mp = src.animation_visualization.motion_path

    if mp.type == 'CURRENT_FRAME':
        mp_text = "Around Frame"
        mp_icon = 'PREVIEW_RANGE'
        mp_start = 'frame_before'
        mp_end = 'frame_after'
        mp_type = 'RANGE'  # value to toggle to
    else:  # mp.type == 'RANGE':
        mp_icon = 'TIME'
        mp_text = "      In Range   "
        mp_start = 'frame_start'
        mp_end = 'frame_end'
        mp_type = 'CURRENT_FRAME'  # value to toggle to

    row = layout.row(align=True)
    row.context_pointer_set('src', src)
    row.context_pointer_set('mp', mp)

    row.menu('MOTIONP_MT_subpanel', text="", icon='THREE_DOTS')

    sub = row.row(align=True)
    sub.scale_x = 0.6
    sub.prop(mp, mp_start, text="")
    row.operator('zpy.motion_path_toggle_type',
                 text=mp_text,
                 icon=mp_icon,
                 depress=False).type = mp_type

    sub = row.row()
    sub.scale_x = 0.6
    sub.prop(mp, mp_end, text="")

    # prefs.operator(row, 'toggle mp relative range', text="",
    #            icon=('TIME', 'PREVIEW_RANGE')
    #            [prefs.prefs().motion.use_relative_range],
    #            emboss=True, depress=False, code='''
    # mot = prefs.prefs().motion
    # mot.use_relative_range = not mot.use_relative_range
    sub = row.row()
    sub.emboss = 'PULLDOWN_MENU'

    if prefs.use_relative_range:
        text = "Around"
        icon = 'PREVIEW_RANGE'
    else:
        text = "Range"
        icon = 'TIME'
    sub.prop(prefs, 'use_relative_range', text=text, icon=icon, icon_only=True)

    mpath = src.motion_path
    if mpath:
        sub = row.row(align=True)
        # sub.scale_x = 0.5
        if mpath.use_custom_color:
            sub.prop(mpath, 'color', icon_only=True)
        else:
            sub.active = False
            sub.prop(mpath,
                     'use_custom_color',
                     icon_only=True,
                     icon='COLORSET_20_VEC')
        sub = row.row(align=True)
        sub.scale_x = 0.5
        sub.prop(mpath, 'line_thickness', icon_only=True, slider=True)

    if mp.has_motion_paths:
        if context.mode == 'POSE':
            clear = 'pose.paths_clear'
        else:
            clear = 'object.paths_clear'

        row.operator(clear, text="", icon='PANEL_CLOSE')
예제 #15
0
    def modal(self, context, event):
        addon_prefs = utils.prefs(__package__).change_frame
        scene = context.scene
        space_data = context.space_data

        def set_text(items=None):
            if items is None:
                bpy.types.STATUSBAR_HT_header.remove(self.draw_status)
                context.window.workspace.status_text_set(None)
            else:
                context.window.workspace.status_text_set("")
                self.text = items

        if scene.use_preview_range:
            start = scene.frame_preview_start
            end = scene.frame_preview_end
        else:
            start = scene.frame_start
            end = scene.frame_end

        scrolled = False
        if event.value == 'PRESS':
            if event.type == 'WHEELUPMOUSE':
                self.sensitivity_factor -= 1
                scrolled = True
            if event.type == 'WHEELDOWNMOUSE':
                self.sensitivity_factor += 1
                scrolled = True

        sensitivity = self.sensitivity
        for i in range(abs(self.sensitivity_factor)):
            if self.sensitivity_factor < 0:
                # sensitivity += sensitivity * 0.1  # faster
                sensitivity *= 1.1  # faster
            else:
                # sensitivity -= sensitivity * 0.1  # slower
                sensitivity *= 0.9  # slower

        looping = addon_prefs.boolLoopTimeline
        # if (event.value == 'PRESS' and event.type == 'CTRL'):
        if (event.value == 'PRESS' and event.type == 'LEFT_CTRL'):
            addon_prefs.boolLoopTimeline = not looping

        # change frame
        if (event.type == 'MOUSEMOVE') or scrolled:

            delta = self.mouseOffset - event.mouse_x
            offset = (-delta * sensitivity) + self.frameOffset

            if looping:

                dist = abs(start - end)

                if (start != end):  # prevent loop freeze/crash
                    if offset > end:
                        while offset > end:
                            offset -= dist
                    elif offset < start:
                        while offset < start:
                            offset += dist

            if (addon_prefs.boolSmoothDrag):
                current = int(offset)
                subframe = offset - int(offset)
                if (current < 0 and subframe) or subframe < 0:
                    # Negative numbers have to offset a little for frame_set
                    current -= 1
                    subframe = 1 - abs(subframe)
                scene.frame_current = current
                scene.frame_subframe = subframe
            else:
                scene.frame_current = offset

        # end of modal
        elif (event.type == self.startButton and event.value == 'RELEASE'):
            set_text()

            # previous viewport setting
            if (context.area.type == 'VIEW_3D'):
                space_data.show_gizmo = self.previousManipulator

                if (self.renderOnly):
                    space_data.overlay.show_overlays = self.previousOnlyRender

            # cursor back
            context.window.cursor_set("DEFAULT")

            # snap back
            if (addon_prefs.boolSmoothSnap):
                scene.frame_subframe = 0

            return {'FINISHED'}

        set_text([
            (('REW'), f"<{start :02}>"),
            (('NONE'), f"({scene.frame_current :05.2f})"),
            (('FF'), f"<{end :02}>"),
            (('MOUSE_MMB_DRAG'), F"Sensitivity: {((sensitivity / self.sensitivity) * 100) :.1f}%"),
            (('PLAY', 'FILE_REFRESH')[looping], f"""{("", "(Loop Animation) Left Ctrl to Disable")[looping]}"""),
            ])

        return {'RUNNING_MODAL'}
예제 #16
0
def prefs():
    return utils.prefs(__addon__).bone_widgets