Skip to content

Commit a727452

Browse files
vantu5zsam-m888
authored andcommitted
[GraphView]Add options for Vertical/horizontal spacing between nodes[gramps51] (#208)
* [GraphView] Add option to set vertical spacing * move spacing spinner on toolbar * use icons instead of font arrows * fix rebase * add nodes spacing * fix tooltips and spelling * code optimization * pack spinners to popovers for toolbar space economy * code optimization
1 parent 9967a16 commit a727452

File tree

1 file changed

+94
-48
lines changed

1 file changed

+94
-48
lines changed

GraphView/graphview.py

Lines changed: 94 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@
107107

108108
WIKI_PAGE = 'https://gramps-project.org/wiki/index.php?title=Graph_View'
109109

110+
# gtk version
111+
gtk_version = float("%s.%s" % (Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION))
112+
110113
#-------------------------------------------------------------------------
111114
#
112115
# Search widget module
@@ -142,7 +145,9 @@ class GraphView(NavigationView):
142145
('interface.graphview-animation-count', 4),
143146
('interface.graphview-search-all-db', True),
144147
('interface.graphview-search-show-images', True),
145-
('interface.graphview-search-marked-first', True))
148+
('interface.graphview-search-marked-first', True),
149+
('interface.graphview-ranksep', 5),
150+
('interface.graphview-nodesep', 2))
146151

147152
def __init__(self, pdata, dbstate, uistate, nav_group=0):
148153
NavigationView.__init__(self, _('Graph View'), pdata, dbstate, uistate,
@@ -481,6 +486,12 @@ def cb_update_search_marked_first(self, client, cnxn_id, entry, data):
481486
value = entry == 'True'
482487
self.graph_widget.search_widget.set_options(marked_first=value)
483488

489+
def cb_update_spacing(self, client, cnxd_id, entry, data):
490+
"""
491+
Called when the ranksep or nodesep setting changed.
492+
"""
493+
self.graph_widget.populate(self.get_active())
494+
484495
def config_connect(self):
485496
"""
486497
Overwriten from :class:`~gui.views.pageview.PageView method
@@ -517,6 +528,10 @@ def config_connect(self):
517528
self.cb_update_search_show_images)
518529
self._config.connect('interface.graphview-search-marked-first',
519530
self.cb_update_search_marked_first)
531+
self._config.connect('interface.graphview-ranksep',
532+
self.cb_update_spacing)
533+
self._config.connect('interface.graphview-nodesep',
534+
self.cb_update_spacing)
520535

521536
def _get_configure_page_funcs(self):
522537
"""
@@ -804,25 +819,35 @@ def __init__(self, view, dbstate, uistate):
804819
Gtk.AccelFlags.VISIBLE)
805820

806821
# add spinners for quick generations change
807-
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
808-
box.pack_start(Gtk.Label(label='↑'), False, False, 1)
809-
self.ancestors_spinner = Gtk.SpinButton.new_with_range(0, 50, 1)
810-
self.ancestors_spinner.set_tooltip_text(_('Ancestor generations'))
811-
self.ancestors_spinner.set_value(
812-
self.view._config.get('interface.graphview-ancestor-generations'))
813-
self.ancestors_spinner.connect("value-changed",
814-
self.set_ancestors_generations)
815-
box.pack_start(self.ancestors_spinner, False, False, 1)
816-
817-
box.pack_start(Gtk.Label(label='↓'), False, False, 1)
818-
self.descendants_spinner = Gtk.SpinButton.new_with_range(0, 50, 1)
819-
self.descendants_spinner.set_tooltip_text(_('Descendant generations'))
820-
self.descendants_spinner.set_value(self.view._config.get(
821-
'interface.graphview-descendant-generations'))
822-
self.descendants_spinner.connect("value-changed",
823-
self.set_descendants_generations)
824-
box.pack_start(self.descendants_spinner, False, False, 1)
825-
self.toolbar.pack_start(box, False, False, 1)
822+
gen_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
823+
box = self.build_spinner('go-up-symbolic', 0, 50,
824+
_('Ancestor generations'),
825+
'interface.graphview-ancestor-generations')
826+
gen_box.add(box)
827+
box = self.build_spinner('go-down-symbolic', 0, 50,
828+
_('Descendant generations'),
829+
'interface.graphview-descendant-generations')
830+
gen_box.add(box)
831+
# pack generation spinners to popover
832+
gen_btn = Gtk.Button(_('Generations'))
833+
self.add_popover(gen_btn, gen_box)
834+
self.toolbar.pack_start(gen_btn, False, False, 1)
835+
836+
# add spiner for generation (vertical) spacing
837+
spacing_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
838+
box = self.build_spinner('object-flip-vertical', 1, 50,
839+
_('Vertical spacing between generations'),
840+
'interface.graphview-ranksep')
841+
spacing_box.add(box)
842+
# add spiner for node (horizontal) spacing
843+
box = self.build_spinner('object-flip-horizontal', 1, 50,
844+
_('Horizontal spacing between generations'),
845+
'interface.graphview-nodesep')
846+
spacing_box.add(box)
847+
# pack spacing spinners to popover
848+
spacing_btn = Gtk.Button(_('Spacings'))
849+
self.add_popover(spacing_btn, spacing_box)
850+
self.toolbar.pack_start(spacing_btn, False, False, 1)
826851

827852
self.vbox.pack_start(scrolled_win, True, True, 0)
828853

@@ -840,16 +865,51 @@ def __init__(self, view, dbstate, uistate):
840865
# for detecting double click
841866
self.click_events = []
842867

843-
# for timeout on changing generation settings
844-
self.set_anc_event = False
845-
self.set_des_event = False
868+
# for timeout on changing settings by spinners
869+
self.timeout_event = False
846870

847871
# Gtk style context for scrollwindow to operate with theme colors
848872
self.sw_style_context = scrolled_win.get_style_context()
849873

850874
# used for popup menu, prevent destroy menu as local variable
851875
self.menu = None
852876

877+
def add_popover(self, widget, container):
878+
"""
879+
Add popover for button.
880+
"""
881+
popover = Gtk.Popover()
882+
popover.set_relative_to(widget)
883+
popover.add(container)
884+
widget.connect("clicked", self.spinners_popup, popover)
885+
container.show_all()
886+
887+
def build_spinner(self, icon, start, end, tooltip, conf_const):
888+
"""
889+
Build spinner with icon and pack it into box.
890+
Chenges apply to config with delay.
891+
"""
892+
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
893+
img = Gtk.Image.new_from_icon_name(icon, Gtk.IconSize.MENU)
894+
box.pack_start(img, False, False, 1)
895+
spinner = Gtk.SpinButton.new_with_range(start, end, 1)
896+
spinner.set_tooltip_text(tooltip)
897+
spinner.set_value(self.view._config.get(conf_const))
898+
spinner.connect("value-changed", self.apply_spinner_delayed,
899+
conf_const)
900+
box.pack_start(spinner, False, False, 1)
901+
return box
902+
903+
def spinners_popup(self, widget, popover):
904+
"""
905+
Popover for generations and spacing params.
906+
Different popup depending on gtk version.
907+
"""
908+
if gtk_version >= 3.22:
909+
popover.popup()
910+
else:
911+
popover.show()
912+
853913
def set_available(self, state):
854914
"""
855915
Set state for GraphView.
@@ -892,37 +952,21 @@ def activate_popover(self, widget, person_handle):
892952
# move view to person with animation
893953
self.move_to_person(None, person_handle, True)
894954

895-
def set_ancestors_generations(self, widget):
955+
def apply_spinner_delayed(self, widget, conf_const):
896956
"""
897-
Set count of ancestors generations to show.
957+
Set params by spinners (generations, spacing).
898958
Use timeout for better interface responsiveness.
899959
"""
900960
value = int(widget.get_value())
901961
# try to remove planed event (changing setting)
902-
if self.set_anc_event and not self.set_anc_event.is_destroyed():
903-
GLib.source_remove(self.set_anc_event.get_id())
962+
if self.timeout_event and \
963+
not self.timeout_event.is_destroyed():
964+
GLib.source_remove(self.timeout_event.get_id())
904965
# timeout saving setting for better interface responsiveness
905966
event_id = GLib.timeout_add(300, self.view._config.set,
906-
'interface.graphview-ancestor-generations',
907-
value)
908-
context = GLib.main_context_default()
909-
self.set_anc_event = context.find_source_by_id(event_id)
910-
911-
def set_descendants_generations(self, widget):
912-
"""
913-
Set count of descendants generations to show.
914-
Use timeout for better interface responsiveness.
915-
"""
916-
value = int(widget.get_value())
917-
# try to remove planed event (changing setting)
918-
if self.set_des_event and not self.set_des_event.is_destroyed():
919-
GLib.source_remove(self.set_des_event.get_id())
920-
# timeout saving setting for better interface responsiveness
921-
event_id = GLib.timeout_add(
922-
300, self.view._config.set,
923-
'interface.graphview-descendant-generations', value)
967+
conf_const, value)
924968
context = GLib.main_context_default()
925-
self.set_des_event = context.find_source_by_id(event_id)
969+
self.timeout_event = context.find_source_by_id(event_id)
926970

927971
def build_bkmark_ext_panel(self):
928972
"""
@@ -1878,6 +1922,10 @@ def init_dot(self):
18781922
'interface.graphview-descendant-generations')
18791923
self.ancestor_generations = self.view._config.get(
18801924
'interface.graphview-ancestor-generations')
1925+
ranksep = self.view._config.get('interface.graphview-ranksep')
1926+
ranksep = ranksep * 0.1
1927+
nodesep = self.view._config.get('interface.graphview-nodesep')
1928+
nodesep = nodesep * 0.1
18811929

18821930
# get background color from gtk theme and convert it to hex
18831931
# else use white background
@@ -1912,10 +1960,8 @@ def init_dot(self):
19121960
dpi = 72
19131961
fontfamily = ""
19141962
fontsize = 14
1915-
nodesep = 0.20
19161963
pagedir = "BL"
19171964
rankdir = "TB"
1918-
ranksep = 0.40
19191965
ratio = "compress"
19201966
# as we are not using paper,
19211967
# choose a large 'page' size with no margin

0 commit comments

Comments
 (0)