""" UI session is running as long as any of the ngSkinTools UI windows are open. """ import functools from ngSkinTools2 import cleanup, signal from ngSkinTools2.api import Layers, PaintTool, events, mirror, plugin from ngSkinTools2.api.log import getLogger from ngSkinTools2.api.python_compatibility import Object from ngSkinTools2.observableValue import ObservableValue from ngSkinTools2.signal import SignalHub log = getLogger("events") class CurrentLayerState(Object): def __init__(self): self.selectedSkinCluster = None # will be None, when no current layer is available self.layer = None # type: ngSkinTools2.api.Layer class CurrentPaintTargetState(Object): def __init__(self): self.skinCluster = None self.layerId = None self.targets = None class State(Object): def __init__(self): self.layersAvailable = False self.selection = [] self.selectedSkinCluster = None self.skin_cluster_dq_channel_used = False self.all_layers = [] # type: List[ngSkinTools2.api.Layer] self.currentLayer = CurrentLayerState() self.currentInfluence = CurrentPaintTargetState() def set_skin_cluster(self, cluster): self.selectedSkinCluster = cluster self.layers = None if cluster is None else Layers(cluster) def mirror(self): # type: () -> mirror.Mirror return mirror.Mirror(self.selectedSkinCluster) class Context(Object): def __init__(self): self.selected_layers = ObservableValue() # [] layerId class Session(Object): def __init__(self): # reference objects that are keeping the session self.references = set() self.state = None # type: State self.events = None # type: events.Events self.signal_hub = None # type: SignalHub self.context = None # type: Context self.referenceId = 0 def active(self): return len(self.references) > 0 def start(self): log.info("STARTING SESSION") plugin.load_plugin() self.paint_tool = PaintTool() self.state = State() self.events = events.Events(self.state) self.signal_hub = SignalHub() self.signal_hub.activate() cleanup.registerCleanupHandler(self.signal_hub.deactivate) self.context = Context() @signal.on(self.events.targetChanged) def on_target_change(): log.info("target changed: clearing target context") self.context.selected_layers.set([]) self.events.nodeSelectionChanged.emit() def end(self): log.info("ENDING SESSION") cleanup.cleanup() self.state = None self.events = None self.context = None self.signal_hub = None pass def addReference(self): """ returns unique ID for this added reference; this value needs to be passed into removeReference(); this ensures that reference holder does not remove other references rather than his own. :return: """ self.referenceId += 1 if not self.active(): self.start() self.references.add(self.referenceId) return self.referenceId def removeReference(self, referenceId): try: self.references.remove(referenceId) except KeyError: pass if not self.active(): self.end() def addQtWidgetReference(self, widget): ref = self.addReference() widget.destroyed.connect(lambda: self.removeReference(ref)) def reference(self): class Context(Object): def __init__(self, session): """ :type session: Session :type refObj: object """ self.session = session def __enter__(self): self.ref = self.session.addReference() def __exit__(self, exc_type, exc_val, exc_tb): self.session.removeReference(self.ref) return Context(self) session = Session() def withSession(func): """ decorator makes sure that single session is running throughout function's lifetime """ @functools.wraps(func) def result(*args, **kwargs): ref = session.addReference() try: return func(*args, **kwargs) finally: session.removeReference(ref) return result