Split addon code up by purpose
This commit is contained in:
69
__init__.py
69
__init__.py
@@ -1,54 +1,26 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
bl_info = {
|
bl_info = {
|
||||||
'name': 'Package Manager',
|
'name': 'Package Manager',
|
||||||
'description': 'Testing package management',
|
'description': 'Testing package management',
|
||||||
'category': 'System',
|
'category': 'System',
|
||||||
'support': 'TESTING',
|
'support': 'TESTING',
|
||||||
}
|
}
|
||||||
import bpy
|
|
||||||
from bpy.props import CollectionProperty
|
|
||||||
from bpy.types import PropertyGroup, Panel, UIList, AddonPreferences
|
|
||||||
|
|
||||||
class RepositoryProperty(PropertyGroup):
|
# from bpy.utils import register_class, unregister_class
|
||||||
url = bpy.props.StringProperty(name="URL")
|
import importlib
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
|
||||||
class PACKAGE_UL_repositories(UIList):
|
log = logging.getLogger(__name__)
|
||||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
|
||||||
split = layout.split(0.3)
|
|
||||||
split.prop(item, "name")
|
|
||||||
split.prop(item, "url")
|
|
||||||
|
|
||||||
def invoke(self, onctext, event):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class PackagePreferences(AddonPreferences):
|
|
||||||
bl_idname = __package__
|
|
||||||
|
|
||||||
repositories = CollectionProperty(type=RepositoryProperty)
|
|
||||||
active_repository = bpy.props.IntProperty()
|
|
||||||
|
|
||||||
def draw(self, context):
|
|
||||||
layout = self.layout
|
|
||||||
row = layout.row()
|
|
||||||
row.template_list("PACKAGE_UL_repositories", "", self, "repositories", self, "active_repository")
|
|
||||||
col = row.column(align=True)
|
|
||||||
col.operator("package.add_repository", icon="ZOOMIN", text="")
|
|
||||||
col.operator("package.remove_repository", icon="ZOOMOUT", text="")
|
|
||||||
|
|
||||||
# class PackageManager:
|
|
||||||
# # For some reason accessing *Property objects stored in this class gives a TypeError:
|
|
||||||
# # UILayout.prop(): error with argument 1, "data" - Function.data expected a AnyType type, not tuple
|
|
||||||
# # But accessing them when not stored in a class or dict is fine?
|
|
||||||
# settings = bpy.props.PointerProperty(type=PackageSettings)
|
|
||||||
# last_response_code = bpy.props.PointerProperty(type=bpy.types.StringProperty)
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
|
|
||||||
# Reload support
|
# Reload support
|
||||||
import sys
|
if '%s.blender_common' % __name__ in sys.modules:
|
||||||
if '%s.pkg_ops' % __name__ in sys.modules:
|
|
||||||
import importlib
|
|
||||||
def reload_mod(name):
|
def reload_mod(name):
|
||||||
print("Reloading %s" % name)
|
log.debug("Reloading %s", name)
|
||||||
modname = '%s.%s' % (__name__, name)
|
modname = '%s.%s' % (__name__, name)
|
||||||
try:
|
try:
|
||||||
old_module = sys.modules[modname]
|
old_module = sys.modules[modname]
|
||||||
@@ -61,26 +33,13 @@ def register():
|
|||||||
sys.modules[modname] = new_module
|
sys.modules[modname] = new_module
|
||||||
return new_module
|
return new_module
|
||||||
|
|
||||||
pkg_ops = reload_mod('pkg_ops')
|
blender_common = reload_mod('blender_common')
|
||||||
pkg_ui = reload_mod('pkg_ui')
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
from . import (pkg_ops, pkg_ui)
|
from . import blender_common
|
||||||
|
|
||||||
bpy.utils.register_class(RepositoryProperty)
|
blender_common.register()
|
||||||
bpy.utils.register_class(PACKAGE_UL_repositories)
|
|
||||||
bpy.utils.register_class(PackagePreferences)
|
|
||||||
pkg_ops.register()
|
|
||||||
pkg_ui.register()
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
from . import (pkg_ops, pkg_ui)
|
blender_common.unregister()
|
||||||
|
|
||||||
pkg_ops.unregister()
|
|
||||||
pkg_ui.unregister();
|
|
||||||
bpy.utils.unregister_class(RepositoryProperty)
|
|
||||||
bpy.utils.unregister_class(PACKAGE_UL_repositories)
|
|
||||||
bpy.utils.unregister_class(PackagePreferences)
|
|
||||||
del bpy.types.Scene.custom
|
|
||||||
del bpy.types.Scene.custom_idx
|
|
||||||
|
|
||||||
|
@@ -1,54 +1,36 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# This file is for code dealing specifically with blender
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import logging
|
from bpy.props import CollectionProperty
|
||||||
from multiprocessing import Process, Pipe
|
from bpy.types import PropertyGroup, Panel, UIList, AddonPreferences, Operator
|
||||||
from . import blenderpack
|
from .subprocess_adapter import SubprocessOperatorMixin
|
||||||
|
|
||||||
class SubprocessOperatorMixin:
|
class RepositoryProperty(PropertyGroup):
|
||||||
timer = None
|
url = bpy.props.StringProperty(name="URL")
|
||||||
log = logging.getLogger("%s.SubprocessOperatorMixin" % __name__)
|
|
||||||
|
|
||||||
# run once in invoke
|
class PACKAGE_UL_repositories(UIList):
|
||||||
def setup(self):
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||||
pass
|
split = layout.split(0.3)
|
||||||
# run on receipt of data from subprocess
|
split.prop(item, "name")
|
||||||
def handle_response(self, resp):
|
split.prop(item, "url")
|
||||||
|
|
||||||
|
def invoke(self, onctext, event):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __init__(self):
|
class PackagePreferences(AddonPreferences):
|
||||||
self.pipe = Pipe()
|
bl_idname = __package__
|
||||||
self.subprocess = None
|
|
||||||
|
|
||||||
def execute(self, context):
|
repositories = CollectionProperty(type=RepositoryProperty)
|
||||||
return self.invoke(context, None)
|
active_repository = bpy.props.IntProperty()
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def draw(self, context):
|
||||||
self.subprocess.start()
|
layout = self.layout
|
||||||
# we have to explicitly close the end of the pipe we are NOT using,
|
row = layout.row()
|
||||||
# otherwise no exception will be generated when the other process closes its end.
|
row.template_list("PACKAGE_UL_repositories", "", self, "repositories", self, "active_repository")
|
||||||
self.pipe[1].close()
|
col = row.column(align=True)
|
||||||
|
col.operator("package.add_repository", icon="ZOOMIN", text="")
|
||||||
wm = context.window_manager
|
col.operator("package.remove_repository", icon="ZOOMOUT", text="")
|
||||||
wm.modal_handler_add(self)
|
|
||||||
self.timer = wm.event_timer_add(.01, context.window)
|
|
||||||
|
|
||||||
self.setup()
|
|
||||||
|
|
||||||
return {'RUNNING_MODAL'}
|
|
||||||
|
|
||||||
def modal(self, context, event):
|
|
||||||
self.log.debug("polling")
|
|
||||||
try:
|
|
||||||
if self.pipe[0].poll():
|
|
||||||
newdata = self.pipe[0].recv()
|
|
||||||
else:
|
|
||||||
newdata = None
|
|
||||||
except EOFError:
|
|
||||||
self.log.debug("done polling")
|
|
||||||
return {'FINISHED'}
|
|
||||||
|
|
||||||
if newdata is not None:
|
|
||||||
self.handle_response(newdata)
|
|
||||||
return {'PASS_THROUGH'}
|
|
||||||
|
|
||||||
class PACKAGE_OT_fetch(SubprocessOperatorMixin, bpy.types.Operator):
|
class PACKAGE_OT_fetch(SubprocessOperatorMixin, bpy.types.Operator):
|
||||||
bl_idname = "package.fetch"
|
bl_idname = "package.fetch"
|
||||||
@@ -88,11 +70,22 @@ class PACKAGE_OT_remove_repository(bpy.types.Operator):
|
|||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
|
bpy.utils.register_class(RepositoryProperty)
|
||||||
|
bpy.utils.register_class(PackagePreferences)
|
||||||
|
|
||||||
bpy.utils.register_class(PACKAGE_OT_fetch)
|
bpy.utils.register_class(PACKAGE_OT_fetch)
|
||||||
|
|
||||||
bpy.utils.register_class(PACKAGE_OT_add_repository)
|
bpy.utils.register_class(PACKAGE_OT_add_repository)
|
||||||
bpy.utils.register_class(PACKAGE_OT_remove_repository)
|
bpy.utils.register_class(PACKAGE_OT_remove_repository)
|
||||||
|
bpy.utils.register_class(PACKAGE_UL_repositories)
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
bpy.utils.unregister_class(PACKAGE_OT_fetch)
|
bpy.utils.unregister_class(RepositoryProperty)
|
||||||
bpy.utils.unregister_class(PACKAGE_OT_remove_repository)
|
bpy.utils.unregister_class(PackagePreferences)
|
||||||
|
|
||||||
|
bpy.utils.unregister_class(PACKAGE_OT_fetch)
|
||||||
|
|
||||||
|
bpy.utils.unregister_class(PACKAGE_OT_add_repository)
|
||||||
|
bpy.utils.unregister_class(PACKAGE_OT_remove_repository)
|
||||||
|
bpy.utils.unregister_class(PACKAGE_UL_repositories)
|
||||||
|
|
33
pkg_ui.py
33
pkg_ui.py
@@ -1,33 +0,0 @@
|
|||||||
import bpy
|
|
||||||
from . import pkg_ops
|
|
||||||
|
|
||||||
class USERPREF_PT_packages(bpy.types.Panel):
|
|
||||||
bl_label = "Package Management"
|
|
||||||
bl_space_type = 'USER_PREFERENCES'
|
|
||||||
bl_region_type = 'WINDOW'
|
|
||||||
bl_options = {'HIDE_HEADER'}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def poll(cls, context):
|
|
||||||
userpref = context.user_preferences
|
|
||||||
return (userpref.active_section == 'PACKAGES')
|
|
||||||
|
|
||||||
def draw(self, context):
|
|
||||||
wm = context.window_manager
|
|
||||||
# see comment in __init__.py
|
|
||||||
pm_settings = wm.package_manager_settings
|
|
||||||
layout = self.layout
|
|
||||||
|
|
||||||
row = layout.row()
|
|
||||||
row.prop(pm_settings, "url")
|
|
||||||
row.operator(pkg_ops.PACKAGE_OT_fetch.bl_idname, text="Fetch")
|
|
||||||
|
|
||||||
row = layout.row()
|
|
||||||
# just a demonstration
|
|
||||||
row.label(text="Last response: %s" % pkg_ops.PACKAGE_OT_fetch.last_response)
|
|
||||||
|
|
||||||
def register():
|
|
||||||
bpy.utils.register_class(USERPREF_PT_packages)
|
|
||||||
|
|
||||||
def unregister():
|
|
||||||
bpy.utils.unregister_class(USERPREF_PT_packages)
|
|
50
subprocess_adapter.py
Normal file
50
subprocess_adapter.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import logging
|
||||||
|
from multiprocessing import Process, Pipe
|
||||||
|
|
||||||
|
class SubprocessOperatorMixin:
|
||||||
|
timer = None
|
||||||
|
log = logging.getLogger("%s.SubprocessOperatorMixin" % __name__)
|
||||||
|
|
||||||
|
# run once in invoke
|
||||||
|
def setup(self):
|
||||||
|
pass
|
||||||
|
# run on receipt of data from subprocess
|
||||||
|
def handle_response(self, resp):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.pipe = Pipe()
|
||||||
|
self.subprocess = None
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
return self.invoke(context, None)
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
self.subprocess.start()
|
||||||
|
# we have to explicitly close the end of the pipe we are NOT using,
|
||||||
|
# otherwise no exception will be generated when the other process closes its end.
|
||||||
|
self.pipe[1].close()
|
||||||
|
|
||||||
|
wm = context.window_manager
|
||||||
|
wm.modal_handler_add(self)
|
||||||
|
self.timer = wm.event_timer_add(.01, context.window)
|
||||||
|
|
||||||
|
self.setup()
|
||||||
|
|
||||||
|
return {'RUNNING_MODAL'}
|
||||||
|
|
||||||
|
def modal(self, context, event):
|
||||||
|
self.log.debug("polling")
|
||||||
|
try:
|
||||||
|
if self.pipe[0].poll():
|
||||||
|
newdata = self.pipe[0].recv()
|
||||||
|
else:
|
||||||
|
newdata = None
|
||||||
|
except EOFError:
|
||||||
|
self.log.debug("done polling")
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
if newdata is not None:
|
||||||
|
self.handle_response(newdata)
|
||||||
|
return {'PASS_THROUGH'}
|
||||||
|
|
Reference in New Issue
Block a user