Add a preferences dialog to house the settings

Now they do not need a place in the menu anymore.
This commit is contained in:
Arjan Molenaar
2019-10-03 22:32:59 +02:00
parent 354906bd78
commit b50a2f24e5
13 changed files with 217 additions and 62 deletions

9
.gitignore vendored
View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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")

View File

@ -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()

View File

@ -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()

View File

@ -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
View 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
View 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)

View 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
)

View File

@ -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)

View File

@ -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"

View File

@ -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",