Add a preferences dialog to house the settings
Now they do not need a place in the menu anymore.
This commit is contained in:
9
.gitignore
vendored
9
.gitignore
vendored
@ -6,6 +6,7 @@ html
|
||||
*.pyo
|
||||
*.swp
|
||||
*.egg
|
||||
*~
|
||||
.eggs/
|
||||
gaphor.egg-info/
|
||||
tmp.gaphor
|
||||
@ -34,14 +35,6 @@ flatpak/build
|
||||
flatpak/gaphor-repo
|
||||
flatpak/.flatpak-builder
|
||||
|
||||
# Briefcase build directories
|
||||
iOS/
|
||||
macOS/
|
||||
windows/
|
||||
android/
|
||||
linux/
|
||||
django/
|
||||
|
||||
# Windows Install
|
||||
win-installer/_build_root
|
||||
|
||||
|
@ -18,7 +18,3 @@ class ActionProvider(metaclass=abc.ABCMeta):
|
||||
An action provider is a special service that provides actions
|
||||
(see gaphor/action.py) and the accompanying XML for the UI manager.
|
||||
"""
|
||||
|
||||
menu_xml: str # "The menu XML"
|
||||
|
||||
action_group: object # "The accompanying ActionGroup"
|
||||
|
@ -15,12 +15,13 @@ from gaphor.abc import Service
|
||||
|
||||
|
||||
class PropertyChangeEvent:
|
||||
"""
|
||||
This event is triggered any time a property is changed. This event
|
||||
holds the property key, the current value, and the new value.
|
||||
"""
|
||||
|
||||
"""This event is triggered any time a property is changed. This event
|
||||
holds the property name, the current value, and the new value."""
|
||||
|
||||
def __init__(self, name, old_value, new_value):
|
||||
self.name = name
|
||||
def __init__(self, key, old_value, new_value):
|
||||
self.key = key
|
||||
self.old_value = old_value
|
||||
self.new_value = new_value
|
||||
|
||||
|
@ -26,7 +26,7 @@ class TestProperties(TestCase):
|
||||
prop.set("test1", 2)
|
||||
assert len(self.events) == 1, self.events
|
||||
event = self.events[0]
|
||||
assert "test1" == event.name
|
||||
assert "test1" == event.key
|
||||
assert None is event.old_value
|
||||
assert 2 == event.new_value
|
||||
assert 2 == prop("test1")
|
||||
@ -37,7 +37,7 @@ class TestProperties(TestCase):
|
||||
prop.set("test1", "foo")
|
||||
assert len(self.events) == 2
|
||||
event = self.events[1]
|
||||
assert "test1" == event.name
|
||||
assert "test1" == event.key
|
||||
assert 2 == event.old_value
|
||||
assert "foo" == event.new_value
|
||||
assert "foo" == prop("test1")
|
||||
|
@ -48,6 +48,12 @@ def iter_actions(provider, scope):
|
||||
yield (attrname, act)
|
||||
|
||||
|
||||
def set_action_state(action_group, action_name, state):
|
||||
action_group.lookup_action(action_name).set_state(
|
||||
GLib.Variant.new_boolean(bool(state))
|
||||
)
|
||||
|
||||
|
||||
def _action_activate(_action, _param, obj, name):
|
||||
method = getattr(obj, name)
|
||||
method()
|
||||
|
@ -21,6 +21,7 @@ from gaphor.abc import ActionProvider
|
||||
from gaphor.UML.event import ElementDeleteEvent
|
||||
from gaphor.core import _, event_handler, transactional, action, build_action_group
|
||||
from gaphor.diagram.support import get_diagram_item
|
||||
from gaphor.services.properties import PropertyChangeEvent
|
||||
from gaphor.transaction import Transaction
|
||||
from gaphor.ui.diagramtoolbox import DiagramToolbox
|
||||
from gaphor.ui.event import DiagramSelectionChange
|
||||
@ -47,8 +48,6 @@ class DiagramPage(ActionProvider):
|
||||
<menuitem action="diagram-zoom-in" />
|
||||
<menuitem action="diagram-zoom-out" />
|
||||
<menuitem action="diagram-zoom-100" />
|
||||
<separator />
|
||||
<menuitem action="diagram-close" />
|
||||
</placeholder>
|
||||
</menu>
|
||||
</menubar>
|
||||
@ -81,6 +80,7 @@ class DiagramPage(ActionProvider):
|
||||
self.action_group = build_action_group(self)
|
||||
self.toolbox = None
|
||||
self.event_manager.subscribe(self._on_element_delete)
|
||||
self.event_manager.subscribe(self._on_sloppy_lines)
|
||||
|
||||
title = property(lambda s: s.diagram and s.diagram.name or _("<None>"))
|
||||
|
||||
@ -135,6 +135,8 @@ class DiagramPage(ActionProvider):
|
||||
self.properties,
|
||||
)
|
||||
|
||||
self._on_sloppy_lines()
|
||||
|
||||
return self.widget
|
||||
|
||||
@event_handler(ElementDeleteEvent)
|
||||
@ -142,11 +144,15 @@ class DiagramPage(ActionProvider):
|
||||
if event.element is self.diagram:
|
||||
self.close()
|
||||
|
||||
@action(name="diagram-close", label=_("_Close"), icon_name="window-close")
|
||||
@event_handler(PropertyChangeEvent)
|
||||
def _on_sloppy_lines(self, event=None):
|
||||
if not event or event.key == "diagram.sloppiness":
|
||||
self.set_drawing_style(self.properties.get("diagram.sloppiness"))
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
Tab is destroyed. Do the same thing that would
|
||||
be done if File->Close was pressed.
|
||||
be done if Close was pressed.
|
||||
"""
|
||||
self.widget.destroy()
|
||||
self.event_manager.unsubscribe(self._on_element_delete)
|
||||
@ -217,12 +223,9 @@ class DiagramPage(ActionProvider):
|
||||
view = self.view
|
||||
|
||||
if sloppiness:
|
||||
|
||||
item_painter = FreeHandPainter(ItemPainter(), sloppiness=sloppiness)
|
||||
box_painter = FreeHandPainter(BoundingBoxPainter(), sloppiness=sloppiness)
|
||||
|
||||
else:
|
||||
|
||||
item_painter = ItemPainter()
|
||||
box_painter = BoundingBoxPainter()
|
||||
|
||||
|
@ -89,10 +89,6 @@ def create_hamburger_model(import_menu, export_menu, tools_menu):
|
||||
part.append_submenu(_("Export"), export_menu)
|
||||
model.append_section(None, part)
|
||||
|
||||
part = Gio.Menu.new()
|
||||
part.append(_("Hand-Drawn Style"), "win.diagram-drawing-style")
|
||||
model.append_section(None, part)
|
||||
|
||||
part = Gio.Menu.new()
|
||||
part.append_submenu(_("Tools"), tools_menu)
|
||||
model.append_section(None, part)
|
||||
@ -574,15 +570,3 @@ class Diagrams(UIComponent, ActionProvider):
|
||||
self._notebook.set_tab_label(
|
||||
widget, self.tab_label(event.new_value, widget)
|
||||
)
|
||||
|
||||
@toggle_action(name="diagram-drawing-style", label="Hand drawn style", active=False)
|
||||
def hand_drawn_style(self, active):
|
||||
"""Toggle between straight diagrams and "hand drawn" diagram style."""
|
||||
|
||||
if active:
|
||||
sloppiness = 0.5
|
||||
else:
|
||||
sloppiness = 0.0
|
||||
for page, widget in self.get_widgets_on_pages():
|
||||
widget.diagram_page.set_drawing_style(sloppiness)
|
||||
self.properties.set("diagram.sloppiness", sloppiness)
|
||||
|
95
gaphor/ui/mockups.glade
Normal file
95
gaphor/ui/mockups.glade
Normal file
@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkDialog" id="preferences">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">8</property>
|
||||
<property name="title" translatable="yes">Preferences</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkBox">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">2</property>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkButtonBox">
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="row_spacing">12</property>
|
||||
<property name="column_spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes">Sloppy lines</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes">Reset to pointer tool after placing an item on a diagram</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSwitch">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="action_name">pref.hand-drawn-style</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSwitch">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="action_name">pref.reset-tool-after-create</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="padding">16</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
63
gaphor/ui/preferences.py
Normal file
63
gaphor/ui/preferences.py
Normal file
@ -0,0 +1,63 @@
|
||||
import importlib
|
||||
from gi.repository import GLib, Gio, Gtk
|
||||
|
||||
from gaphor.abc import Service, ActionProvider
|
||||
from gaphor.core import action, toggle_action
|
||||
from gaphor.ui.actiongroup import add_actions_to_group, set_action_state
|
||||
|
||||
|
||||
class Preferences(Service, ActionProvider):
|
||||
def __init__(self, main_window, properties):
|
||||
self.main_window = main_window
|
||||
self.properties = properties
|
||||
|
||||
@action(name="app.preferences")
|
||||
def open(self):
|
||||
# self.hand_drawn_style.active = self.properties.get("diagram.sloppiness", 0.0) > 0.0
|
||||
|
||||
builder = Gtk.Builder()
|
||||
with importlib.resources.path("gaphor.ui", "mockups.glade") as glade_file:
|
||||
builder.add_objects_from_file(str(glade_file), ("preferences",))
|
||||
|
||||
prefs = builder.get_object("preferences")
|
||||
prefs.set_transient_for(self.main_window.window)
|
||||
prefs.set_modal(True)
|
||||
|
||||
prefs.insert_action_group("pref", self.create_action_group())
|
||||
|
||||
prefs.show_all()
|
||||
return prefs
|
||||
|
||||
def shutdown(self):
|
||||
pass
|
||||
|
||||
def create_action_group(self):
|
||||
action_group = Gio.SimpleActionGroup.new()
|
||||
add_actions_to_group(action_group, self, "pref")
|
||||
|
||||
set_action_state(
|
||||
action_group,
|
||||
"hand-drawn-style",
|
||||
self.properties.get("diagram.sloppiness", 0.0) > 0.0,
|
||||
)
|
||||
|
||||
set_action_state(
|
||||
action_group,
|
||||
"reset-tool-after-create",
|
||||
self.properties.get("reset-tool-after-create", True),
|
||||
)
|
||||
return action_group
|
||||
|
||||
@toggle_action(name="pref.hand-drawn-style", active=False)
|
||||
def hand_drawn_style(self, active):
|
||||
print("""Toggle between straight diagrams and "hand drawn" diagram style.""")
|
||||
|
||||
if active:
|
||||
sloppiness = 0.5
|
||||
else:
|
||||
sloppiness = 0.0
|
||||
self.properties.set("diagram.sloppiness", sloppiness)
|
||||
|
||||
@toggle_action(name="pref.reset-tool-after-create", active=False)
|
||||
def reset_tool_after_create(self, active):
|
||||
self.properties.set("reset-tool-after-create", active)
|
32
gaphor/ui/tests/test_preferences.py
Normal file
32
gaphor/ui/tests/test_preferences.py
Normal file
@ -0,0 +1,32 @@
|
||||
import pytest
|
||||
|
||||
from gi.repository import Gtk
|
||||
from gaphor.ui.preferences import Preferences
|
||||
|
||||
|
||||
class MainWindowMock:
|
||||
def __init__(self):
|
||||
self.window = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
|
||||
|
||||
|
||||
def test_preferences_window():
|
||||
prefs = Preferences(MainWindowMock(), {})
|
||||
|
||||
dialog = prefs.open()
|
||||
action_group = dialog.get_action_group("pref")
|
||||
|
||||
assert (
|
||||
action_group.lookup_action("hand-drawn-style").get_state().get_boolean()
|
||||
== False
|
||||
)
|
||||
|
||||
|
||||
def test_with_hand_drawn_style_enabled():
|
||||
prefs = Preferences(MainWindowMock(), {"diagram.sloppiness": 0.5})
|
||||
|
||||
dialog = prefs.open()
|
||||
action_group = dialog.get_action_group("pref")
|
||||
|
||||
assert (
|
||||
action_group.lookup_action("hand-drawn-style").get_state().get_boolean() == True
|
||||
)
|
@ -33,18 +33,6 @@ class Toolbox(UIComponent, ActionProvider):
|
||||
|
||||
title = _("Toolbox")
|
||||
|
||||
menu_xml = """
|
||||
<ui>
|
||||
<menubar name="mainwindow">
|
||||
<menu action="diagram">
|
||||
<separator/>
|
||||
<menuitem action="reset-tool-after-create" />
|
||||
<separator/>
|
||||
</menu>
|
||||
</menubar>
|
||||
</ui>
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, event_manager, main_window, properties, toolbox_actions=TOOLBOX_ACTIONS
|
||||
):
|
||||
@ -53,10 +41,6 @@ class Toolbox(UIComponent, ActionProvider):
|
||||
self.properties = properties
|
||||
self._toolbox = None
|
||||
self._toolbox_actions = toolbox_actions
|
||||
self.action_group = build_action_group(self)
|
||||
self.action_group.get_action("reset-tool-after-create").set_active(
|
||||
self.properties.get("reset-tool-after-create", True)
|
||||
)
|
||||
self.buttons: List[Gtk.Button] = []
|
||||
self.shortcuts: Dict[str, str] = {}
|
||||
|
||||
@ -144,10 +128,6 @@ class Toolbox(UIComponent, ActionProvider):
|
||||
def _on_toolbox_destroyed(self, widget):
|
||||
self._toolbox = None
|
||||
|
||||
@toggle_action(name="reset-tool-after-create", label=_("_Reset tool"), active=False)
|
||||
def reset_tool_after_create(self, active):
|
||||
self.properties.set("reset-tool-after-create", active)
|
||||
|
||||
@event_handler(DiagramPageChange)
|
||||
def _on_diagram_page_change(self, event):
|
||||
self.update_toolbox(event.diagram_page.toolbox.action_group)
|
||||
|
@ -63,6 +63,7 @@ gaphorconvert = 'gaphor.tools.gaphorconvert:main'
|
||||
"diagram_export_manager" = "gaphor.services.diagramexportmanager:DiagramExportManager"
|
||||
"action_manager" = "gaphor.services.actionmanager:ActionManager"
|
||||
"main_window" = "gaphor.ui.mainwindow:MainWindow"
|
||||
"preferences" = "gaphor.ui.preferences:Preferences"
|
||||
"export_menu" = "gaphor.ui.menufragment:MenuFragment"
|
||||
"import_menu" = "gaphor.ui.menufragment:MenuFragment"
|
||||
"tools_menu" = "gaphor.ui.menufragment:MenuFragment"
|
||||
|
1
setup.py
1
setup.py
@ -111,6 +111,7 @@ setup(
|
||||
"recent_files = gaphor.ui.recentfiles:RecentFiles",
|
||||
"action_manager = gaphor.services.actionmanager:ActionManager",
|
||||
"main_window = gaphor.ui.mainwindow:MainWindow",
|
||||
"preferences = gaphor.ui.preferences:Preferences",
|
||||
"export_menu = gaphor.ui.menufragment:MenuFragment",
|
||||
"import_menu = gaphor.ui.menufragment:MenuFragment",
|
||||
"tools_menu = gaphor.ui.menufragment:MenuFragment",
|
||||
|
Reference in New Issue
Block a user