Skip to content

Commit

Permalink
Add feature manager and associated preference panel.
Browse files Browse the repository at this point in the history
  • Loading branch information
cmeyer committed Dec 3, 2024
1 parent 6767fd3 commit 8fba3f9
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 0 deletions.
67 changes: 67 additions & 0 deletions nion/swift/Application.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
from nion.swift.model import ApplicationData
from nion.swift.model import ColorMaps
from nion.swift.model import DocumentModel
from nion.swift.model import Feature
from nion.swift.model import FileStorageSystem
from nion.swift.model import PlugInManager
from nion.swift.model import Profile
Expand All @@ -48,13 +49,15 @@
from nion.ui import CanvasItem
from nion.ui import Declarative
from nion.ui import Dialog
from nion.ui import PreferencesDialog
from nion.ui import UserInterface
from nion.ui import Window as UIWindow
from nion.utils import Event
from nion.utils import Geometry
from nion.utils import ListModel
from nion.utils import Model
from nion.utils import Registry
from nion.utils import Stream

if typing.TYPE_CHECKING:
from nion.swift.model import DisplayItem
Expand Down Expand Up @@ -246,6 +249,7 @@ def initialize(self, *, load_plug_ins: bool = True, use_root_dir: bool = True) -
app_data_file_path = self.ui.get_configuration_location() / pathlib.Path("nionswift_appdata.json")
ApplicationData.set_file_path(app_data_file_path)
logging.info("Application data: " + str(app_data_file_path))
self.__initialize_features()
PlugInManager.load_plug_ins(self.ui.get_document_location(), self.ui.get_data_location(), get_root_dir() if use_root_dir else None)
color_maps_dir = self.ui.get_configuration_location() / pathlib.Path("Color Maps")
if color_maps_dir.exists():
Expand All @@ -269,6 +273,18 @@ def deinitialize(self) -> None:
self.__class__.count -= 1
super().deinitialize()

def __initialize_features(self) -> None:
enabled_feature_str = UserInterface.StringPersistentModel(self.ui, "enabled_feature_str", "")

feature_manager = Feature.FeatureManager()
feature_manager.enabled_feature_str = enabled_feature_str.value or str()

def handle_feature_manager_property_changed(property_name: str) -> None:
if property_name == "enabled_feature_str":
enabled_feature_str.value = feature_manager.enabled_feature_str

self.__enabled_feature_str_listener = feature_manager.property_changed_event.listen(handle_feature_manager_property_changed)

@property
def profile(self) -> Profile.Profile:
assert self.__profile
Expand Down Expand Up @@ -797,6 +813,57 @@ def get_root_dir() -> str:
return root_dir


class FeaturesPreferencePanel:
def __init__(self) -> None:
self.identifier = "nion.swift.features-panel"
self.label = _("Features")

def build(self, ui: UserInterface.UserInterface, event_loop: typing.Optional[asyncio.AbstractEventLoop] = None, **kwargs: typing.Any) -> Declarative.DeclarativeWidget:
u = Declarative.DeclarativeUI()

class FeatureHandler(Declarative.Handler):
def __init__(self, item: Feature.Feature) -> None:
super().__init__()
self.feature = item
self.ui_view = u.create_column(
u.create_row(
u.create_check_box(text="@binding(feature.description)", checked="@binding(feature.enabled)"),
u.create_stretch(),
spacing=8
),
spacing=8
)

class Handler(Declarative.Handler):
def __init__(self) -> None:
super().__init__()
self.features = Feature.FeatureManager().features
self.ui_view = u.create_column(
u.create_row(
u.create_label(text="Optional Features", width=120),
u.create_stretch(),
spacing=8
),
u.create_divider(orientation="horizontal"),
u.create_scroll_area(content=u.create_column(u.create_column(items="features", item_component_id="feature-component", spacing=4), u.create_stretch())),
u.create_stretch(),
spacing=8
)

def create_handler(self, component_id: str, container: typing.Any = None, item: typing.Any = None, **kwargs: typing.Any) -> typing.Optional[Declarative.HandlerLike]:
# this is called to construct contained declarative component handlers within this handler.
if component_id == "feature-component":
assert container is not None
assert item is not None
return FeatureHandler(item)
return None

return Declarative.DeclarativeWidget(ui, event_loop or asyncio.get_event_loop(), Handler())


PreferencesDialog.PreferencesManager().register_preference_pane(FeaturesPreferencePanel())


class NewProjectAction(UIWindow.Action):
action_id = "project.new_project"
action_name = _("New Project...")
Expand Down
67 changes: 67 additions & 0 deletions nion/swift/model/Feature.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from __future__ import annotations

import typing

from nion.swift.model import Utility
from nion.utils import Event
from nion.utils import Observable


class Feature(Observable.Observable):
def __init__(self, feature_id: str, description: str) -> None:
super().__init__()
self.feature_id = feature_id
self.description = description
self.__enabled = False

@property
def enabled(self) -> bool:
return self.__enabled

@enabled.setter
def enabled(self, enabled: bool) -> None:
if self.__enabled != enabled:
self.__enabled = enabled
self.notify_property_changed("enabled")


class FeatureManager(Observable.Observable, metaclass=Utility.Singleton):
def __init__(self) -> None:
super().__init__()
self.__features = list[Feature]()
self.__feature_listeners = list[Event.EventListener]()

@property
def enabled_feature_str(self) -> str:
return ",".join(feature.feature_id for feature in self.features if feature.enabled)

@enabled_feature_str.setter
def enabled_feature_str(self, enabled_features_str: str) -> None:
for enabled_feature_id in enabled_features_str.split(","):
print(f"{enabled_feature_id=}")
feature = self.get_feature(enabled_feature_id)
if feature:
feature.enabled = True

@property
def features(self) -> typing.Sequence[Feature]:
return list(self.__features)

def add_feature(self, feature: Feature) -> None:
self.__features.append(feature)
self.__feature_listeners.append(feature.property_changed_event.listen(self.__feature_property_changed))

def __feature_property_changed(self, property_name: str) -> None:
if property_name == "enabled":
self.notify_property_changed("enabled_feature_str")

def get_feature(self, feature_id: str) -> typing.Optional[Feature]:
for feature in self.__features:
if feature.feature_id == feature_id:
return feature
return None

def is_feature_enabled(self, feature_id: str) -> bool:
feature = self.get_feature(feature_id)
return feature.enabled if feature else False

0 comments on commit 8fba3f9

Please sign in to comment.