mirror of
https://github.com/olivierkes/manuskript.git
synced 2024-06-01 10:39:34 +12:00
Implement world view: selection and simple changes
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
This commit is contained in:
parent
9129d1fa5a
commit
906d05e377
|
@ -18,3 +18,4 @@ from manuskript.data.summary import Summary
|
|||
from manuskript.data.template import Template, TemplateLevel, TemplateKind
|
||||
from manuskript.data.unique_id import UniqueIDHost, UniqueID
|
||||
from manuskript.data.version import Version
|
||||
from manuskript.data.world import World, WorldItem
|
||||
|
|
|
@ -22,6 +22,7 @@ class Links:
|
|||
self.callbacks.append(callback)
|
||||
|
||||
def remove(self, callback: Callable[[LinkAction, UniqueID, any], None]):
|
||||
if callback in self.callbacks:
|
||||
self.callbacks.remove(callback)
|
||||
|
||||
def call(self, action: LinkAction, UID: UniqueID, host: any):
|
||||
|
|
|
@ -19,6 +19,12 @@ class WorldItem:
|
|||
self.conflict = None
|
||||
self.children = list()
|
||||
|
||||
def remove(self):
|
||||
for child in self.children:
|
||||
child.remove()
|
||||
|
||||
self.world.removeItem(self)
|
||||
|
||||
def __iter__(self):
|
||||
return self.children.__iter__()
|
||||
|
||||
|
@ -48,6 +54,9 @@ class World:
|
|||
self.host.removeID(item.UID)
|
||||
self.items.pop(item.UID.value)
|
||||
|
||||
def getItemByID(self, ID: int) -> WorldItem:
|
||||
return self.items.get(ID, None)
|
||||
|
||||
def __iter__(self):
|
||||
return self.items.values().__iter__()
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ class MainWindow:
|
|||
self.summaryView = MainWindow.packViewIntoSlot(builder, "summary_slot", SummaryView, self.project.summary)
|
||||
self.charactersView = MainWindow.packViewIntoSlot(builder, "characters_slot", CharactersView, self.project.characters)
|
||||
self.plotView = MainWindow.packViewIntoSlot(builder, "plot_slot", PlotView, self.project.plots)
|
||||
self.worldView = MainWindow.packViewIntoSlot(builder, "world_slot", WorldView)
|
||||
self.worldView = MainWindow.packViewIntoSlot(builder, "world_slot", WorldView, self.project.world)
|
||||
self.outlineView = MainWindow.packViewIntoSlot(builder, "outline_slot", OutlineView)
|
||||
self.editorView = MainWindow.packViewIntoSlot(builder, "editor_slot", EditorView)
|
||||
|
||||
|
|
|
@ -6,14 +6,184 @@ import gi
|
|||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk
|
||||
|
||||
from manuskript.data import World, WorldItem
|
||||
from manuskript.util import validString, invalidString, validInt, invalidInt
|
||||
|
||||
|
||||
class WorldView:
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, world: World):
|
||||
self.world = world
|
||||
self.worldItem = None
|
||||
|
||||
builder = Gtk.Builder()
|
||||
builder.add_from_file("ui/world.glade")
|
||||
|
||||
self.widget = builder.get_object("world_view")
|
||||
|
||||
self.worldStore = builder.get_object("world_store")
|
||||
self.refreshWorldStore()
|
||||
|
||||
self.filteredWorldStore = builder.get_object("filtered_world_store")
|
||||
self.filterWorldBuffer = builder.get_object("filter_world")
|
||||
|
||||
self.filterWorldBuffer.connect("deleted-text", self.filterWorldDeletedText)
|
||||
self.filterWorldBuffer.connect("inserted-text", self.filterWorldInsertedText)
|
||||
|
||||
self.filteredWorldStore.set_visible_func(self.filterWorld)
|
||||
self.filteredWorldStore.refilter()
|
||||
|
||||
self.worldSelection = builder.get_object("world_selection")
|
||||
|
||||
self.worldSelection.connect("changed", self.worldSelectionChanged)
|
||||
|
||||
self.worldTreeView = builder.get_object("world_tree_view")
|
||||
self.worldTreeView.expand_all()
|
||||
|
||||
self.nameBuffer = builder.get_object("name")
|
||||
self.descriptionBuffer = builder.get_object("description")
|
||||
self.sourceOfPassionBuffer = builder.get_object("source_of_passion")
|
||||
self.sourceOfConflictBuffer = builder.get_object("source_of_conflict")
|
||||
|
||||
self.nameBuffer.connect("deleted-text", self.nameDeletedText)
|
||||
self.nameBuffer.connect("inserted-text", self.nameInsertedText)
|
||||
|
||||
self.descriptionBuffer.connect("changed", self.descriptionChanged)
|
||||
self.sourceOfPassionBuffer.connect("changed", self.sourceOfPassionChanged)
|
||||
self.sourceOfConflictBuffer.connect("changed", self.sourceOfConflictChanged)
|
||||
|
||||
self.unloadWorldData()
|
||||
|
||||
def __appendWorldItem(self, worldItem: WorldItem, parent_iter = None):
|
||||
tree_iter = self.worldStore.append(parent_iter)
|
||||
|
||||
if tree_iter is None:
|
||||
return
|
||||
|
||||
self.worldStore.set_value(tree_iter, 0, worldItem.UID.value)
|
||||
self.worldStore.set_value(tree_iter, 1, validString(worldItem.name))
|
||||
|
||||
for item in worldItem:
|
||||
self.__appendWorldItem(item, tree_iter)
|
||||
|
||||
def refreshWorldStore(self):
|
||||
self.worldStore.clear()
|
||||
|
||||
for item in self.world.top:
|
||||
self.__appendWorldItem(item)
|
||||
|
||||
def loadWorldData(self, worldItem: WorldItem):
|
||||
self.worldItem = None
|
||||
|
||||
self.nameBuffer.set_text(validString(worldItem.name), -1)
|
||||
self.descriptionBuffer.set_text(validString(worldItem.description), -1)
|
||||
self.sourceOfPassionBuffer.set_text(validString(worldItem.passion), -1)
|
||||
self.sourceOfConflictBuffer.set_text(validString(worldItem.conflict), -1)
|
||||
|
||||
self.worldItem = worldItem
|
||||
|
||||
def unloadWorldData(self):
|
||||
self.worldItem = None
|
||||
|
||||
self.nameBuffer.set_text("", -1)
|
||||
self.descriptionBuffer.set_text("", -1)
|
||||
self.sourceOfPassionBuffer.set_text("", -1)
|
||||
self.sourceOfConflictBuffer.set_text("", -1)
|
||||
|
||||
def worldSelectionChanged(self, selection: Gtk.TreeSelection):
|
||||
model, tree_iter = selection.get_selected()
|
||||
|
||||
if tree_iter is None:
|
||||
self.unloadWorldData()
|
||||
return
|
||||
|
||||
worldItem = self.world.getItemByID(model[tree_iter][0])
|
||||
|
||||
if worldItem is None:
|
||||
self.unloadWorldData()
|
||||
else:
|
||||
self.loadWorldData(worldItem)
|
||||
|
||||
def __matchWorldItemByText(self, worldItem: WorldItem, text: str):
|
||||
for item in worldItem:
|
||||
if self.__matchWorldItemByText(item, text):
|
||||
return True
|
||||
|
||||
name = validString(worldItem.name)
|
||||
return text in name.lower()
|
||||
|
||||
def filterWorld(self, model, iter, userdata):
|
||||
worldItem = self.world.getItemByID(model[iter][0])
|
||||
|
||||
if worldItem is None:
|
||||
return False
|
||||
|
||||
text = validString(self.filterWorldBuffer.get_text())
|
||||
return self.__matchWorldItemByText(worldItem, text.lower())
|
||||
|
||||
def filterWorldChanged(self, buffer: Gtk.EntryBuffer):
|
||||
self.filteredWorldStore.refilter()
|
||||
|
||||
def filterWorldDeletedText(self, buffer: Gtk.EntryBuffer, position: int, n_chars: int):
|
||||
self.filterWorldChanged(buffer)
|
||||
|
||||
def filterWorldInsertedText(self, buffer: Gtk.EntryBuffer, position: int, chars: str, n_chars: int):
|
||||
self.filterWorldChanged(buffer)
|
||||
|
||||
def nameChanged(self, buffer: Gtk.EntryBuffer):
|
||||
if self.worldItem is None:
|
||||
return
|
||||
|
||||
text = buffer.get_text()
|
||||
name = invalidString(text)
|
||||
|
||||
self.worldItem.name = name
|
||||
|
||||
world_id = self.worldItem.UID.value
|
||||
|
||||
for row in self.worldStore:
|
||||
if row[0] == world_id:
|
||||
row[1] = validString(name)
|
||||
break
|
||||
|
||||
def nameDeletedText(self, buffer: Gtk.EntryBuffer, position: int, n_chars: int):
|
||||
self.nameChanged(buffer)
|
||||
|
||||
def nameInsertedText(self, buffer: Gtk.EntryBuffer, position: int, chars: str, n_chars: int):
|
||||
self.nameChanged(buffer)
|
||||
|
||||
def descriptionChanged(self, buffer: Gtk.TextBuffer):
|
||||
if self.worldItem is None:
|
||||
return
|
||||
|
||||
start_iter = buffer.get_start_iter()
|
||||
end_iter = buffer.get_end_iter()
|
||||
|
||||
text = buffer.get_text(start_iter, end_iter, False)
|
||||
|
||||
self.worldItem.description = invalidString(text)
|
||||
|
||||
def sourceOfPassionChanged(self, buffer: Gtk.TextBuffer):
|
||||
if self.worldItem is None:
|
||||
return
|
||||
|
||||
start_iter = buffer.get_start_iter()
|
||||
end_iter = buffer.get_end_iter()
|
||||
|
||||
text = buffer.get_text(start_iter, end_iter, False)
|
||||
|
||||
self.worldItem.passion = invalidString(text)
|
||||
|
||||
def sourceOfConflictChanged(self, buffer: Gtk.TextBuffer):
|
||||
if self.worldItem is None:
|
||||
return
|
||||
|
||||
start_iter = buffer.get_start_iter()
|
||||
end_iter = buffer.get_end_iter()
|
||||
|
||||
text = buffer.get_text(start_iter, end_iter, False)
|
||||
|
||||
self.worldItem.conflict = invalidString(text)
|
||||
|
||||
def show(self):
|
||||
self.widget.show_all()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.38.2
|
||||
<!-- Generated with glade 3.40.0
|
||||
|
||||
Copyright (C) 2015-2021 Olivier Keshavjee et al.
|
||||
|
||||
|
@ -25,18 +25,22 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
|
|||
<!-- interface-name Manuskript -->
|
||||
<!-- interface-description Manuskript is an open-source tool for writers. -->
|
||||
<!-- interface-copyright 2015-2021 Olivier Keshavjee et al. -->
|
||||
<object class="GtkTextBuffer" id="description"/>
|
||||
<object class="GtkEntryBuffer" id="filter_world"/>
|
||||
<object class="GtkEntryBuffer" id="name"/>
|
||||
<object class="GtkTextBuffer" id="source_of_conflict"/>
|
||||
<object class="GtkTextBuffer" id="source_of_passion"/>
|
||||
<object class="GtkTreeStore" id="world_store">
|
||||
<columns>
|
||||
<!-- column-name ID -->
|
||||
<column type="gint"/>
|
||||
<!-- column-name name -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name description -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name passion -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name conflict -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkTreeModelFilter" id="filtered_world_store">
|
||||
<property name="child-model">world_store</property>
|
||||
</object>
|
||||
<object class="GtkScrolledWindow" id="world_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
|
@ -69,14 +73,14 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
|
|||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkTreeView">
|
||||
<object class="GtkTreeView" id="world_tree_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="model">world_store</property>
|
||||
<property name="model">filtered_world_store</property>
|
||||
<property name="search-column">0</property>
|
||||
<property name="enable-tree-lines">True</property>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection"/>
|
||||
<object class="GtkTreeSelection" id="world_selection"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn">
|
||||
|
@ -84,7 +88,7 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
|
|||
<child>
|
||||
<object class="GtkCellRendererText"/>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
<attribute name="text">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
|
@ -109,7 +113,7 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
|
|||
<property name="margin-bottom">8</property>
|
||||
<property name="spacing">4</property>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<object class="GtkButton" id="add_to_world">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
|
@ -128,7 +132,7 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<object class="GtkButton" id="remove_from_world">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
|
@ -150,6 +154,7 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
|
|||
<object class="GtkEntry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="buffer">filter_world</property>
|
||||
<property name="placeholder-text" translatable="yes">Filter</property>
|
||||
</object>
|
||||
<packing>
|
||||
|
@ -216,6 +221,7 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
|
|||
<object class="GtkEntry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="buffer">name</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
@ -249,6 +255,8 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
|
|||
<property name="height-request">300</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="wrap-mode">word-char</property>
|
||||
<property name="buffer">description</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
|
@ -323,6 +331,8 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
|
|||
<property name="height-request">300</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="wrap-mode">word-char</property>
|
||||
<property name="buffer">source_of_passion</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
|
@ -361,6 +371,8 @@ along with Manuskript. If not, see <http://www.gnu.org/licenses/>.
|
|||
<property name="height-request">300</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="wrap-mode">word-char</property>
|
||||
<property name="buffer">source_of_conflict</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
|
|
Loading…
Reference in a new issue