From 7fd205cd7fb156054c8d587ecc19e2c51c40897d Mon Sep 17 00:00:00 2001 From: TheJackiMonster Date: Sun, 20 Nov 2022 00:13:41 +0100 Subject: [PATCH] Implement grid view with navigation Signed-off-by: TheJackiMonster --- manuskript/data/outline.py | 13 +++ manuskript/ui/editor/__init__.py | 4 + manuskript/ui/editor/gridItem.py | 38 +++++++++ manuskript/ui/startup/templateEntry.py | 1 - manuskript/ui/util.py | 11 ++- manuskript/ui/views/editorView.py | 102 ++++++++++++++--------- ui/editor.glade | 9 +-- ui/editor/grid-item.glade | 108 +++++++++++++++++++++++++ 8 files changed, 240 insertions(+), 46 deletions(-) create mode 100644 manuskript/ui/editor/__init__.py create mode 100644 manuskript/ui/editor/gridItem.py create mode 100644 ui/editor/grid-item.glade diff --git a/manuskript/data/outline.py b/manuskript/data/outline.py index 6de7c55..1ce3e9f 100644 --- a/manuskript/data/outline.py +++ b/manuskript/data/outline.py @@ -40,6 +40,16 @@ class OutlineItem: self.compile = True self.goal = None + def parentItem(self): + for item in self.outline.all(): + if item.contains(self): + return item + + return None + + def contains(self, item): + return False + @classmethod def loadMetadata(cls, item, metadata: dict): ID = metadata.get("ID") @@ -144,6 +154,9 @@ class OutlineFolder(OutlineItem): def __iter__(self): return self.items.__iter__() + def contains(self, item): + return item in self.items + @classmethod def loadItems(cls, outline, folder, recursive: bool = True): folder.items.clear() diff --git a/manuskript/ui/editor/__init__.py b/manuskript/ui/editor/__init__.py new file mode 100644 index 0000000..761244b --- /dev/null +++ b/manuskript/ui/editor/__init__.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from manuskript.ui.editor.gridItem import GridItem diff --git a/manuskript/ui/editor/gridItem.py b/manuskript/ui/editor/gridItem.py new file mode 100644 index 0000000..b803686 --- /dev/null +++ b/manuskript/ui/editor/gridItem.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gdk, Gtk + +from manuskript.data import OutlineItem +from manuskript.ui.util import iconByOutlineItemType +from manuskript.util import validString + + +class GridItem: + + def __init__(self, outlineItem: OutlineItem): + self.outlineItem = outlineItem + + builder = Gtk.Builder() + builder.add_from_file("ui/editor/grid-item.glade") + + self.widget = builder.get_object("grid_item") + + self.iconImage = builder.get_object("icon") + self.titleLabel = builder.get_object("title") + self.summaryLabel = builder.get_object("summary") + + self.reloadOutlineItem() + + def reloadOutlineItem(self): + icon = iconByOutlineItemType(self.outlineItem) + + self.iconImage.set_from_icon_name(icon, Gtk.IconSize.MENU) + self.titleLabel.set_text(validString(self.outlineItem.title)) + self.summaryLabel.set_text(validString(self.outlineItem.summaryFull)) + + def show(self): + self.widget.show_all() diff --git a/manuskript/ui/startup/templateEntry.py b/manuskript/ui/startup/templateEntry.py index 5ac6895..2cdb42d 100644 --- a/manuskript/ui/startup/templateEntry.py +++ b/manuskript/ui/startup/templateEntry.py @@ -66,4 +66,3 @@ class TemplateEntry: def show(self): self.widget.show_all() - diff --git a/manuskript/ui/util.py b/manuskript/ui/util.py index 898c62b..8b3ed0b 100644 --- a/manuskript/ui/util.py +++ b/manuskript/ui/util.py @@ -7,7 +7,7 @@ gi.require_version('Gdk', '3.0') gi.require_version('GdkPixbuf', '2.0') from gi.repository import GdkPixbuf, Gdk -from manuskript.data import Color +from manuskript.data import Color, OutlineItem, OutlineText, OutlineFolder def rgbaFromColor(color: Color) -> Gdk.RGBA: @@ -32,3 +32,12 @@ def bindMenuItem(builder, id, action): return menuItem.connect("activate", action) + + +def iconByOutlineItemType(outlineItem: OutlineItem) -> str: + if type(outlineItem) is OutlineFolder: + return "folder-symbolic" + elif type(outlineItem) is OutlineText: + return "emblem-documents-symbolic" + else: + return "folder-documents-symbolic" diff --git a/manuskript/ui/views/editorView.py b/manuskript/ui/views/editorView.py index fc35b61..055c399 100644 --- a/manuskript/ui/views/editorView.py +++ b/manuskript/ui/views/editorView.py @@ -6,9 +6,10 @@ import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk, Pango -from manuskript.data import Project, Outline, OutlineFolder, OutlineText, OutlineItem, OutlineState, Plots, PlotLine, Characters, Character, Importance, Goal -from manuskript.ui.util import rgbaFromColor, pixbufFromColor -from manuskript.util import validString, invalidString, validInt, invalidInt, CounterKind, countText +from manuskript.data import Project, OutlineFolder, OutlineText, OutlineItem, OutlineState +from manuskript.ui.editor import GridItem +from manuskript.ui.util import pixbufFromColor, iconByOutlineItemType +from manuskript.util import validString, validInt import inspect @@ -17,6 +18,7 @@ class EditorView: def __init__(self, project: Project): self.project = project + self.outlineItem = None builder = Gtk.Builder() builder.add_from_file("ui/editor.glade") @@ -32,10 +34,22 @@ class EditorView: self.outlineStore = builder.get_object("outline_store") self.refreshOutlineStore() - self.editorTextBuffer = builder.get_object("editor_text") + self.editorItems = list() + self.editorTextBuffer = builder.get_object("editor_text") self.editorFlowbox = builder.get_object("editor_flowbox") - self.loadEditorData(None) + + self.editorFlowbox.connect("child-activated", self.editorFlowboxChildActivated) + + self.upButtons = [ + builder.get_object("up"), + builder.get_object("up_") + ] + + for button in self.upButtons: + button.connect("clicked", self.upButtonClicked) + + self.unloadOutlineData() def refreshLabelStore(self): self.labelStore.clear() @@ -60,15 +74,6 @@ class EditorView: self.statusStore.set_value(tree_iter, 0, validString(status.name)) - @classmethod - def __getIconByOutlineType(cls, outlineItem: OutlineItem): - if type(outlineItem) is OutlineFolder: - return "folder-symbolic" - elif type(outlineItem) is OutlineText: - return "emblem-documents-symbolic" - else: - return "folder-documents-symbolic" - def __appendOutlineItem(self, outlineItem: OutlineItem, parent_iter=None): tree_iter = self.outlineStore.append(parent_iter) @@ -78,7 +83,7 @@ class EditorView: if outlineItem.state != OutlineState.COMPLETE: outlineItem.load(False) - icon = EditorView.__getIconByOutlineType(outlineItem) + icon = iconByOutlineItemType(outlineItem) if type(outlineItem) is OutlineFolder: for item in outlineItem: @@ -109,6 +114,18 @@ class EditorView: for item in self.project.outline.items: self.__appendOutlineItem(item) + def loadOutlineData(self, outlineItem: OutlineItem): + self.outlineItem = None + + self.loadEditorData(outlineItem) + + self.outlineItem = outlineItem + + def unloadOutlineData(self): + self.outlineItem = None + + self.loadEditorData(None) + def __appendOutlineItemText(self, outlineItem: OutlineItem): end_iter = self.editorTextBuffer.get_end_iter() @@ -136,38 +153,47 @@ class EditorView: return False def loadEditorData(self, outlineItem: OutlineItem | None): - self.editorTextBuffer.set_text("") + self.editorItems = list() + self.outlineItem = None - for item in self.project.outline.items: + start_iter, end_iter = self.editorTextBuffer.get_bounds() + self.editorTextBuffer.delete(start_iter, end_iter) + + if outlineItem is None: + self.editorItems = self.project.outline.items + elif type(outlineItem) is OutlineFolder: + self.editorItems = outlineItem.items + elif type(outlineItem) is OutlineText: + self.__appendOutlineItemText(outlineItem) + + self.editorFlowbox.foreach(self.editorFlowbox.remove) + if len(self.editorItems) <= 0: + self.outlineItem = outlineItem + return + + for item in self.editorItems: self.__appendOutlineItemText(item) - for item in self.project.outline.items: - child = Gtk.FlowBoxChild() + for item in self.editorItems: + self.editorFlowbox.insert(GridItem(item).widget, -1) - hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) - vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + self.outlineItem = outlineItem - icon = EditorView.__getIconByOutlineType(item) + def editorFlowboxChildActivated(self, box: Gtk.FlowBox, child: Gtk.FlowBoxChild): + if child is None: + return - iconImage = Gtk.Image.new_from_icon_name(icon, Gtk.IconSize.MENU) - titleLabel = Gtk.Label(item.title) - summaryLabel = Gtk.Label(item.summaryFull) + index = child.get_index() + if (index < 0) or (index >= len(self.editorItems)): + return - titleLabel.set_ellipsize(Pango.EllipsizeMode.END) - summaryLabel.set_ellipsize(Pango.EllipsizeMode.END) - summaryLabel.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR) - summaryLabel.set_line_wrap(True) - summaryLabel.set_max_width_chars(20) + self.loadEditorData(self.editorItems[index]) - hbox.pack_start(iconImage, False, True, 4) - hbox.pack_start(titleLabel, False, True, 4) + def upButtonClicked(self, button: Gtk.Button): + if self.outlineItem is None: + return - vbox.pack_start(hbox, False, True, 4) - vbox.pack_start(summaryLabel, False, True, 4) - - child.add(vbox) - - self.editorFlowbox.add(child) + self.loadOutlineData(self.outlineItem.parentItem()) def show(self): self.widget.show_all() diff --git a/ui/editor.glade b/ui/editor.glade index 7f33fcc..233526b 100644 --- a/ui/editor.glade +++ b/ui/editor.glade @@ -374,6 +374,7 @@ along with Manuskript. If not, see . True word-char editor_text + GTK_INPUT_HINT_SPELLCHECK | GTK_INPUT_HINT_WORD_COMPLETION | GTK_INPUT_HINT_NONE @@ -569,7 +570,7 @@ along with Manuskript. If not, see . 2 4 - + True True True @@ -678,15 +679,13 @@ along with Manuskript. If not, see . True False - 2 - 2 2 2 2 2 4 - + True True True @@ -728,8 +727,6 @@ along with Manuskript. If not, see . True False - 8 - 8 8 8 0 words diff --git a/ui/editor/grid-item.glade b/ui/editor/grid-item.glade new file mode 100644 index 0000000..3d74883 --- /dev/null +++ b/ui/editor/grid-item.glade @@ -0,0 +1,108 @@ + + + + + + + + + + True + False + 2 + 0 + 0 + + + True + False + 6 + vertical + 4 + + + True + False + 8 + + + True + False + info-symbolic + + + False + True + 0 + + + + + True + False + end + True + 15 + 0 + + + + + + True + True + end + 1 + + + + + False + True + 0 + + + + + True + False + True + word-char + end + 15 + 3 + 0 + 0 + + + True + True + 1 + + + + + + + + +