2025-12-09
This commit is contained in:
@@ -10,7 +10,6 @@ module_names = (
|
||||
"op_pie_wrappers",
|
||||
"op_copy_to_selected",
|
||||
"bs_utils",
|
||||
"hotkeys",
|
||||
"prefs",
|
||||
"sidebar",
|
||||
"tweak_builtin_pies",
|
||||
@@ -83,10 +82,4 @@ def register():
|
||||
bpy.app.timers.register(delayed_register, first_interval=0.5, persistent=True)
|
||||
|
||||
def unregister():
|
||||
# save add-on prefs to file before unregistering.
|
||||
from .bs_utils.prefs import get_addon_prefs, update_prefs_on_file
|
||||
addon_prefs = get_addon_prefs()
|
||||
if addon_prefs:
|
||||
if bpy.context.preferences.use_preferences_save:
|
||||
update_prefs_on_file()
|
||||
register_unregister_modules(reversed(modules), False)
|
||||
register_unregister_modules(reversed(modules), False)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
schema_version = "1.0.0"
|
||||
id = "viewport_pie_menus"
|
||||
name = "3D Viewport Pie Menus"
|
||||
version = "1.7.0"
|
||||
version = "1.7.1"
|
||||
tagline = "Various pie menus to speed up your workflow"
|
||||
maintainer = "Community"
|
||||
type = "add-on"
|
||||
|
||||
@@ -7,24 +7,8 @@
|
||||
import bpy
|
||||
from bpy.types import KeyMap, KeyMapItem, UILayout
|
||||
|
||||
ADDON_KEYMAPS = []
|
||||
|
||||
class HotkeyDrawMixin:
|
||||
"""Expose these functions as a mix-in class so that add-ons can more easily override functionality as needed.
|
||||
Add-ons should simply inherit this class in their AddonPreferences class.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def draw_hotkey_list(context, layout, compact=False, debug=False, sort_mode='BY_KEYMAP', ignore_missing=False):
|
||||
draw_hotkey_list(context, layout, compact, debug, sort_mode, ignore_missing)
|
||||
|
||||
@staticmethod
|
||||
def get_user_kmis_of_addon(context) -> list[tuple[KeyMap, KeyMapItem]]:
|
||||
return get_user_kmis_of_addon(context)
|
||||
|
||||
@staticmethod
|
||||
def draw_kmi(km: KeyMap, kmi: KeyMapItem, layout: UILayout, compact=False, debug=False):
|
||||
draw_kmi(km, kmi, layout, compact=compact, debug=debug)
|
||||
if "ADDON_KEYMAPS" not in locals():
|
||||
ADDON_KEYMAPS = []
|
||||
|
||||
KEYMAP_ICONS = {
|
||||
'Object Mode': 'OBJECT_DATAMODE',
|
||||
@@ -57,7 +41,6 @@ def register_hotkey(
|
||||
hotkey_kwargs={'type': "SPACE", 'value': "PRESS"},
|
||||
keymap_name='Window'
|
||||
):
|
||||
|
||||
global ADDON_KEYMAPS
|
||||
wm = bpy.context.window_manager
|
||||
|
||||
@@ -80,8 +63,8 @@ def register_hotkey(
|
||||
# it is SUPPOSED TO stick around for ever.
|
||||
# This allows Blender to store the associated user keymap, meaning the user's modifications
|
||||
# will be stored and restored as expected, whenever the add-on is enabled again.
|
||||
if (addon_km, existing_kmi) not in ADDON_KEYMAPS:
|
||||
ADDON_KEYMAPS.append((addon_km, existing_kmi))
|
||||
# if (addon_km, existing_kmi) not in ADDON_KEYMAPS:
|
||||
# ADDON_KEYMAPS.append((addon_km, existing_kmi))
|
||||
return
|
||||
addon_kmi = addon_km.keymap_items.new(bl_idname, **hotkey_kwargs)
|
||||
for key in op_kwargs:
|
||||
@@ -204,8 +187,6 @@ def find_kmi_in_km_by_data(km: KeyMap, hotkey_kwargs: dict, op_idname: str, op_k
|
||||
def is_kmi_matching(kmi: KeyMapItem, hotkey_kwargs: dict, op_idname: str, op_kwargs: dict) -> bool:
|
||||
if kmi.idname != op_idname:
|
||||
return False
|
||||
if kmi.properties == None:
|
||||
return False
|
||||
|
||||
combined_hotkey = KMI_DEFAULTS.copy()
|
||||
combined_hotkey.update(hotkey_kwargs)
|
||||
@@ -213,11 +194,17 @@ def find_kmi_in_km_by_data(km: KeyMap, hotkey_kwargs: dict, op_idname: str, op_k
|
||||
if value != getattr(kmi, key):
|
||||
return False
|
||||
|
||||
for key, value in op_kwargs.items():
|
||||
if key not in kmi.properties:
|
||||
return False
|
||||
if value != kmi.properties[key]:
|
||||
want_to_crash = False
|
||||
if want_to_crash:
|
||||
# These checks cause https://projects.blender.org/Mets/CloudRig/issues/201
|
||||
# They don't seem necessary.
|
||||
if kmi.properties == None:
|
||||
return False
|
||||
for key, value in op_kwargs.items():
|
||||
if key not in kmi.properties:
|
||||
return False
|
||||
if value != kmi.properties[key]:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@@ -342,18 +329,27 @@ def restore_deleted_keymap_items_global(context) -> int:
|
||||
keyconfigs = context.window_manager.keyconfigs
|
||||
user_kc = keyconfigs.user
|
||||
total_restored = 0
|
||||
for user_km in user_kc.keymaps:
|
||||
total_restored += restore_deleted_keymap_items(context, user_km)
|
||||
keymap_names = [km.name for km in user_kc.keymaps]
|
||||
for km_name in keymap_names:
|
||||
num_restored = restore_deleted_keymap_items(context, km_name)
|
||||
user_km = user_kc.keymaps[km_name]
|
||||
if num_restored != 0:
|
||||
user_km = user_kc.keymaps[km_name]
|
||||
print(f"{user_km.name}: Restored {num_restored}")
|
||||
total_restored += num_restored
|
||||
return total_restored
|
||||
|
||||
def restore_deleted_keymap_items(context, user_km) -> int:
|
||||
def restore_deleted_keymap_items(context, user_km_name) -> int:
|
||||
keyconfigs = context.window_manager.keyconfigs
|
||||
user_kc = keyconfigs.user
|
||||
default_kc = keyconfigs.default
|
||||
addon_kc = keyconfigs.addon
|
||||
|
||||
user_km = user_kc.keymaps[user_km_name]
|
||||
|
||||
# Step 1: Store modified and added KeyMapItems in a temp keymap.
|
||||
temp_km = user_kc.keymaps.new("temp_"+user_km.name)
|
||||
temp_km_name = "temp_"+user_km_name
|
||||
temp_km = user_kc.keymaps.new(temp_km_name)
|
||||
kmis_user_modified = []
|
||||
kmis_user_defined = []
|
||||
for user_kmi in user_km.keymap_items:
|
||||
@@ -374,6 +370,10 @@ def restore_deleted_keymap_items(context, user_km) -> int:
|
||||
# Step 2: Restore User KeyMap to default.
|
||||
num_kmis = len(user_km.keymap_items)
|
||||
user_km.restore_to_default()
|
||||
# XXX: restore_to_default() will shuffle the memory addresses, so we need to re-reference user_km.
|
||||
# I don't think this was the case pre-Blender 5.0!!
|
||||
user_km = user_kc.keymaps[user_km_name]
|
||||
temp_km = user_kc.keymaps[temp_km_name]
|
||||
|
||||
# Step 3: Restore modified and added KeyMapItems.
|
||||
for temp_def_kmi in kmis_user_defined:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from pathlib import Path
|
||||
|
||||
import bpy, json
|
||||
import bpy, json, os
|
||||
from bpy.types import PropertyGroup
|
||||
from rna_prop_ui import IDPropertyGroup
|
||||
from bpy.types import AddonPreferences
|
||||
@@ -40,12 +40,14 @@ class PrefsFileSaveLoadMixin:
|
||||
# This could still fail if Blender loads too slowly, so it could be better.
|
||||
# Ideally, Blender would simply save add-on preferences to disk, and none of this should be needed.
|
||||
def timer_func(_scene=None):
|
||||
prefs = None
|
||||
try:
|
||||
prefs = get_addon_prefs()
|
||||
except KeyError:
|
||||
# Add-on got un-registered in the meantime.
|
||||
return
|
||||
prefs.load_and_apply_prefs_from_file()
|
||||
if prefs:
|
||||
prefs.load_and_apply_prefs_from_file()
|
||||
bpy.app.timers.register(timer_func, first_interval=delay)
|
||||
|
||||
def apply_prefs_from_dict_recursive(self, propgroup: PropertyGroup, data: dict):
|
||||
@@ -71,6 +73,8 @@ class PrefsFileSaveLoadMixin:
|
||||
def save_prefs_to_file(self, _context=None):
|
||||
filepath = get_prefs_filepath()
|
||||
|
||||
os.makedirs(os.path.dirname(filepath), exist_ok=True)
|
||||
|
||||
with open(filepath, "w") as f:
|
||||
json.dump(self.to_dict(), f, indent=4)
|
||||
|
||||
|
||||
@@ -4,18 +4,19 @@
|
||||
|
||||
from bpy.types import UILayout
|
||||
|
||||
def aligned_label(layout: UILayout, text: str, icon=None, alert=False, alignment='LEFT', **kwargs):
|
||||
def aligned_label(layout: UILayout, *, alert=False, alignment='LEFT', **kwargs):
|
||||
"""Draw some text in the single-column-layout style, ie. offset by 60%."""
|
||||
row = layout.split(factor=0.4)
|
||||
row.separator()
|
||||
row.alert = alert
|
||||
row.alignment = alignment
|
||||
row.label(text=text, icon=icon, **kwargs)
|
||||
row.label(**kwargs)
|
||||
|
||||
def label_split(layout: UILayout, text: str, icon=None, alert=False, **kwargs) -> UILayout:
|
||||
def label_split(layout: UILayout, *, alert=False, **kwargs) -> UILayout:
|
||||
"""Return an empty UILayout with a text label to its left in the single-column-layout style."""
|
||||
split = layout.split(factor=0.4, align=True)
|
||||
split.alert = alert
|
||||
row = split.row(align=True)
|
||||
row.alignment = 'RIGHT'
|
||||
row.label(text=text)
|
||||
row.label(**kwargs)
|
||||
return split
|
||||
@@ -1,52 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2016-2024 Blender Foundation
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import bpy
|
||||
|
||||
class WM_OT_toggle_keymap_item_on_drag(bpy.types.Operator):
|
||||
"When Drag is enabled, this pie menu will only appear when the mouse is dragged while the assigned key combo is held down"
|
||||
bl_idname = "wm.toggle_keymap_item_property"
|
||||
bl_label = "Toggle On Drag"
|
||||
bl_options = {'REGISTER', 'INTERNAL'}
|
||||
|
||||
km_name: bpy.props.StringProperty(options={'SKIP_SAVE'})
|
||||
kmi_idname: bpy.props.StringProperty(options={'SKIP_SAVE'})
|
||||
pie_name: bpy.props.StringProperty(options={'SKIP_SAVE'})
|
||||
prop_name: bpy.props.StringProperty(options={'SKIP_SAVE'})
|
||||
|
||||
def execute(self, context):
|
||||
# Another sign of the fragility of Blender's keymap API.
|
||||
# The reason for the existence of this property wrapper operator is that
|
||||
# when we draw the `on_drag` property in the UI directly, Blender's keymap
|
||||
# system (for some reason??) doesn't realize that a keymap entry has changed,
|
||||
# and fails to refresh caches, which has disasterous results.
|
||||
# This operator fires a refreshing of internal keymap data via
|
||||
# `user_kmi.type = user_kmi.type`
|
||||
|
||||
user_kc = context.window_manager.keyconfigs.user
|
||||
user_km = user_kc.keymaps.get(self.km_name)
|
||||
if not user_km:
|
||||
# This really shouldn't happen.
|
||||
self.report({'ERROR'}, f"Couldn't find KeyMap: {self.km_name}")
|
||||
return {'CANCELLED'}
|
||||
|
||||
for user_kmi in user_km.keymap_items:
|
||||
if user_kmi.idname == self.kmi_idname and user_kmi.properties and user_kmi.properties.name == self.pie_name:
|
||||
if hasattr(user_kmi.properties, self.prop_name):
|
||||
setattr(
|
||||
user_kmi.properties,
|
||||
self.prop_name,
|
||||
not getattr(user_kmi.properties, self.prop_name),
|
||||
)
|
||||
# This is the magic line that causes internal keymap data to be kept up to date and not break.
|
||||
user_kmi.type = user_kmi.type
|
||||
else:
|
||||
self.report({'ERROR'}, "Property not in keymap: " + self.prop_name)
|
||||
return {'CANCELLED'}
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
registry = [
|
||||
WM_OT_toggle_keymap_item_on_drag,
|
||||
]
|
||||
@@ -29,12 +29,19 @@ class WM_OT_call_menu_pie_drag_only(Operator):
|
||||
bl_label = "Pie Menu on Drag"
|
||||
bl_options = {'REGISTER', 'INTERNAL'}
|
||||
|
||||
def update_kmi(self, context):
|
||||
if not hasattr(context, 'keymapitem'):
|
||||
return
|
||||
kmi = context.keymapitem # Set via UILayout.context_pointer_set().
|
||||
kmi.type = kmi.type
|
||||
|
||||
name: StringProperty(options={'SKIP_SAVE'})
|
||||
on_drag: BoolProperty(
|
||||
name="On Drag",
|
||||
default=True,
|
||||
description="Only show this pie menu on mouse drag, otherwise execute a default operator",
|
||||
options={'SKIP_SAVE'},
|
||||
update=update_kmi,
|
||||
)
|
||||
fallback_operator: StringProperty(options={'SKIP_SAVE'})
|
||||
fallback_op_kwargs: StringProperty(default="{}", options={'SKIP_SAVE'})
|
||||
@@ -102,6 +109,7 @@ class WM_OT_call_menu_pie_drag_only(Operator):
|
||||
if km:
|
||||
for kmi in km.keymap_items:
|
||||
for i, condition in enumerate([
|
||||
kmi.idname != 'wm.call_menu_pie_drag_only',
|
||||
kmi.type == hotkey_kwargs.get('type', ""),
|
||||
kmi.value == hotkey_kwargs.get('value', "PRESS"),
|
||||
kmi.ctrl == hotkey_kwargs.get('ctrl', False),
|
||||
|
||||
@@ -61,8 +61,6 @@ class OUTLINER_MT_relationship_pie(Menu):
|
||||
remap = pie.operator(
|
||||
'outliner.remap_users_ui', icon='FILE_REFRESH', text="Remap Users"
|
||||
)
|
||||
remap.id_type = id.id_type
|
||||
remap.id_name_source = id.name
|
||||
if id.library:
|
||||
remap.library_path_source = id.library.filepath
|
||||
else:
|
||||
@@ -290,7 +288,7 @@ class RemapTarget(bpy.types.PropertyGroup):
|
||||
|
||||
|
||||
class OUTLINER_OT_remap_users_ui(bpy.types.Operator):
|
||||
"""Remap users of a selected ID to any other ID of the same type"""
|
||||
"""Remap users of selected IDs to any other ID of the same type"""
|
||||
|
||||
bl_idname = "outliner.remap_users_ui"
|
||||
bl_label = "Remap Users"
|
||||
@@ -300,9 +298,9 @@ class OUTLINER_OT_remap_users_ui(bpy.types.Operator):
|
||||
# Prepare the ID selector.
|
||||
remap_targets = context.scene.remap_targets
|
||||
remap_targets.clear()
|
||||
source_id = get_id(self.id_name_source, self.id_type, self.library_path_source)
|
||||
for id in get_id_storage_by_type_str(self.id_type)[0]:
|
||||
if id == source_id:
|
||||
source_ids = get_selected_ids_of_active_type(context)
|
||||
for id in get_id_storage_by_type_str(source_ids[0].id_type)[0]:
|
||||
if id in source_ids:
|
||||
continue
|
||||
if (self.library_path == 'Local Data' and not id.library) or (
|
||||
id.library and (self.library_path == id.library.filepath)
|
||||
@@ -315,44 +313,50 @@ class OUTLINER_OT_remap_users_ui(bpy.types.Operator):
|
||||
description="Library path, if we want to remap to a linked ID",
|
||||
update=update_library_path,
|
||||
)
|
||||
id_type: StringProperty(description="ID type, eg. 'OBJECT' or 'MESH'")
|
||||
library_path_source: StringProperty()
|
||||
id_name_source: StringProperty(
|
||||
name="Source ID Name", description="Name of the ID we're remapping the users of"
|
||||
)
|
||||
id_name_target: StringProperty(
|
||||
name="Target ID Name", description="Name of the ID we're remapping users to"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
source_ids = get_selected_ids_of_active_type(context)
|
||||
if not source_ids:
|
||||
cls.poll_message_set("No selected IDs.")
|
||||
return False
|
||||
return True
|
||||
|
||||
def invoke(self, context, _event):
|
||||
# Populate the remap_targets string list with possible options based on
|
||||
# what was passed to the operator.
|
||||
|
||||
assert (
|
||||
self.id_type and self.id_name_source
|
||||
), "Error: UI must provide ID and ID type to this operator."
|
||||
# selection context.
|
||||
|
||||
# Prepare the library selector.
|
||||
remap_target_libraries = context.scene.remap_target_libraries
|
||||
remap_target_libraries.clear()
|
||||
local = remap_target_libraries.add()
|
||||
local.name = "Local Data"
|
||||
source_id = get_id(self.id_name_source, self.id_type, self.library_path_source)
|
||||
source_ids = get_selected_ids_of_active_type(context)
|
||||
for lib in bpy.data.libraries:
|
||||
for id in lib.users_id:
|
||||
if type(id) == type(source_id):
|
||||
if type(id) == type(source_ids[0]):
|
||||
lib_entry = remap_target_libraries.add()
|
||||
lib_entry.name = lib.filepath
|
||||
break
|
||||
|
||||
container = get_id_storage_by_type_str(source_ids[0].id_type)[0]
|
||||
|
||||
self.library_path = "Local Data"
|
||||
if source_id.name[-4] == ".":
|
||||
storage = get_id_storage_by_type_str(self.id_type)[0]
|
||||
suggestion = storage.get(source_id.name[:-4])
|
||||
if suggestion:
|
||||
self.id_name_target = suggestion.name
|
||||
if suggestion.library:
|
||||
self.library_path = suggestion.library.filepath
|
||||
suffixed_id = next((id for id in source_ids if id.name[-4] == "."), None)
|
||||
|
||||
if suffixed_id:
|
||||
default_target = container.get(suffixed_id.name[:-4])
|
||||
if default_target:
|
||||
self.id_name_target = default_target.name
|
||||
if default_target.library:
|
||||
self.library_path = default_target.library.filepath
|
||||
else:
|
||||
self.id_name_target = ""
|
||||
self.library_path = 'Local Data'
|
||||
|
||||
return context.window_manager.invoke_props_dialog(self, width=600)
|
||||
|
||||
@@ -362,14 +366,18 @@ class OUTLINER_OT_remap_users_ui(bpy.types.Operator):
|
||||
layout.use_property_decorate = False
|
||||
|
||||
scene = context.scene
|
||||
row = layout.row()
|
||||
id = get_id(self.id_name_source, self.id_type, self.library_path_source)
|
||||
id_icon = get_datablock_icon(id)
|
||||
split = row.split()
|
||||
split.row().label(text="Anything that was referencing this:")
|
||||
row = split.row()
|
||||
row.prop(self, 'id_name_source', text="", icon=id_icon)
|
||||
row.enabled = False
|
||||
source_ids = get_selected_ids_of_active_type(context)
|
||||
id_icon = get_datablock_icon(source_ids[0])
|
||||
for i, source_id in enumerate(source_ids):
|
||||
row = layout.row()
|
||||
split = row.split()
|
||||
if i==0:
|
||||
split.row().label(text="Anything that was referencing these:")
|
||||
else:
|
||||
split.row()
|
||||
row = split.row()
|
||||
row.prop(source_id, 'name', text="", icon=id_icon)
|
||||
row.enabled = False
|
||||
|
||||
layout.separator()
|
||||
col = layout.column()
|
||||
@@ -392,11 +400,12 @@ class OUTLINER_OT_remap_users_ui(bpy.types.Operator):
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
source_id = get_id(self.id_name_source, self.id_type, self.library_path_source)
|
||||
target_id = get_id(self.id_name_target, self.id_type, self.library_path)
|
||||
assert source_id and target_id, "Error: Failed to find source or target."
|
||||
source_ids = get_selected_ids_of_active_type(context)
|
||||
target_id = get_id(self.id_name_target, source_ids[0].id_type, self.library_path)
|
||||
assert source_ids and target_id, "Error: Failed to find source or target."
|
||||
|
||||
source_id.user_remap(target_id)
|
||||
for source_id in source_ids:
|
||||
source_id.user_remap(target_id)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
@@ -409,9 +418,7 @@ class OBJECT_OT_instancer_empty_to_collection(Operator):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
obj = context.active_object
|
||||
if context.area.ui_type == 'OUTLINER':
|
||||
obj = context.id
|
||||
obj = get_active_id(context)
|
||||
|
||||
if not (
|
||||
obj
|
||||
@@ -429,9 +436,7 @@ class OBJECT_OT_instancer_empty_to_collection(Operator):
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.active_object
|
||||
if context.area.ui_type == 'OUTLINER':
|
||||
obj = context.id
|
||||
obj = get_active_id(context)
|
||||
|
||||
coll = obj.instance_collection
|
||||
bpy.data.objects.remove(obj)
|
||||
@@ -559,6 +564,13 @@ def get_fundamental_id_type(datablock: ID) -> tuple[Any, str]:
|
||||
)
|
||||
|
||||
|
||||
def get_selected_ids_of_active_type(context):
|
||||
active_id = get_active_id(context)
|
||||
return [
|
||||
id for id in context.selected_ids
|
||||
if type(id) == type(active_id)
|
||||
]
|
||||
|
||||
def get_id(id_name: str, id_type: str, lib_path="") -> ID:
|
||||
container = get_id_storage_by_type_str(id_type)[0]
|
||||
if lib_path and lib_path != 'Local Data':
|
||||
|
||||
@@ -6,16 +6,14 @@ import platform, struct, urllib
|
||||
|
||||
import bpy
|
||||
import addon_utils
|
||||
from bpy.types import AddonPreferences, Operator, KeyMap, KeyMapItem
|
||||
from bpy.types import AddonPreferences, KeyMap, KeyMapItem
|
||||
from bpy.props import BoolProperty
|
||||
from bl_ui.space_userpref import USERPREF_PT_interface_menus_pie
|
||||
|
||||
from .bs_utils.prefs import PrefsFileSaveLoadMixin, update_prefs_on_file, get_addon_prefs
|
||||
from .bs_utils.hotkeys import HotkeyDrawMixin, get_sidebar, draw_hotkey_list
|
||||
from .bs_utils.prefs import get_addon_prefs
|
||||
from .bs_utils.hotkeys import get_sidebar, draw_hotkey_list
|
||||
|
||||
class ExtraPies_AddonPrefs(
|
||||
PrefsFileSaveLoadMixin,
|
||||
HotkeyDrawMixin,
|
||||
AddonPreferences,
|
||||
USERPREF_PT_interface_menus_pie, # We use this class's `draw_centered` function to draw built-in pie settings.
|
||||
):
|
||||
@@ -83,16 +81,9 @@ def button_draw_func(layout, km: KeyMap, kmi: KeyMapItem, compact=False):
|
||||
|
||||
sub = split.row(align=True)
|
||||
sub.enabled = kmi.active
|
||||
op = sub.operator(
|
||||
'wm.toggle_keymap_item_property',
|
||||
text=text,
|
||||
icon='MOUSE_MOVE',
|
||||
depress=kmi.properties.on_drag,
|
||||
)
|
||||
op.km_name = km.name
|
||||
op.kmi_idname = kmi.idname
|
||||
op.pie_name = kmi.properties.name
|
||||
op.prop_name = 'on_drag'
|
||||
sub.context_pointer_set("keymapitem", kmi)
|
||||
sub.use_property_split=False
|
||||
sub.prop(kmi.properties, 'on_drag', icon='MOUSE_MOVE', text=text)
|
||||
|
||||
def get_bug_report_url():
|
||||
op_sys = "%s %d Bits\n" % (
|
||||
@@ -123,46 +114,4 @@ def get_bug_report_url():
|
||||
+ urllib.parse.quote(op_sys)
|
||||
)
|
||||
|
||||
|
||||
class WINDOW_OT_extra_pies_prefs_save(Operator):
|
||||
"""Save Extra Pies add-on preferences"""
|
||||
|
||||
bl_idname = "window.extra_pies_prefs_save"
|
||||
bl_label = "Save Pie Hotkeys"
|
||||
bl_options = {'REGISTER'}
|
||||
|
||||
def execute(self, context):
|
||||
filepath, data = update_prefs_on_file(context)
|
||||
self.report({'INFO'}, f"Saved Pie Prefs to {filepath}.")
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class WINDOW_OT_extra_pies_prefs_load(Operator):
|
||||
"""Load Extra Pies add-on preferences"""
|
||||
|
||||
bl_idname = "window.extra_pies_prefs_load"
|
||||
bl_label = "Load Pie Hotkeys"
|
||||
bl_options = {'REGISTER'}
|
||||
|
||||
def execute(self, context):
|
||||
prefs = get_addon_prefs(context)
|
||||
filepath = prefs.get_prefs_filepath()
|
||||
success = prefs.load_and_apply_prefs_from_file()
|
||||
|
||||
if success:
|
||||
self.report({'INFO'}, f"Loaded pie preferences from {filepath}.")
|
||||
else:
|
||||
self.report({'ERROR'}, "Failed to load Pie preferences.")
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
registry = [
|
||||
ExtraPies_AddonPrefs,
|
||||
WINDOW_OT_extra_pies_prefs_save,
|
||||
WINDOW_OT_extra_pies_prefs_load,
|
||||
]
|
||||
|
||||
|
||||
def register():
|
||||
ExtraPies_AddonPrefs.register_autoload_from_file()
|
||||
registry = [ExtraPies_AddonPrefs]
|
||||
|
||||
Reference in New Issue
Block a user