107
107
108
108
WIKI_PAGE = 'https://gramps-project.org/wiki/index.php?title=Graph_View'
109
109
110
+ # gtk version
111
+ gtk_version = float ("%s.%s" % (Gtk .MAJOR_VERSION , Gtk .MINOR_VERSION ))
112
+
110
113
#-------------------------------------------------------------------------
111
114
#
112
115
# Search widget module
@@ -142,7 +145,9 @@ class GraphView(NavigationView):
142
145
('interface.graphview-animation-count' , 4 ),
143
146
('interface.graphview-search-all-db' , True ),
144
147
('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 ))
146
151
147
152
def __init__ (self , pdata , dbstate , uistate , nav_group = 0 ):
148
153
NavigationView .__init__ (self , _ ('Graph View' ), pdata , dbstate , uistate ,
@@ -481,6 +486,12 @@ def cb_update_search_marked_first(self, client, cnxn_id, entry, data):
481
486
value = entry == 'True'
482
487
self .graph_widget .search_widget .set_options (marked_first = value )
483
488
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
+
484
495
def config_connect (self ):
485
496
"""
486
497
Overwriten from :class:`~gui.views.pageview.PageView method
@@ -517,6 +528,10 @@ def config_connect(self):
517
528
self .cb_update_search_show_images )
518
529
self ._config .connect ('interface.graphview-search-marked-first' ,
519
530
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 )
520
535
521
536
def _get_configure_page_funcs (self ):
522
537
"""
@@ -804,25 +819,35 @@ def __init__(self, view, dbstate, uistate):
804
819
Gtk .AccelFlags .VISIBLE )
805
820
806
821
# 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 )
826
851
827
852
self .vbox .pack_start (scrolled_win , True , True , 0 )
828
853
@@ -840,16 +865,51 @@ def __init__(self, view, dbstate, uistate):
840
865
# for detecting double click
841
866
self .click_events = []
842
867
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
846
870
847
871
# Gtk style context for scrollwindow to operate with theme colors
848
872
self .sw_style_context = scrolled_win .get_style_context ()
849
873
850
874
# used for popup menu, prevent destroy menu as local variable
851
875
self .menu = None
852
876
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
+
853
913
def set_available (self , state ):
854
914
"""
855
915
Set state for GraphView.
@@ -892,37 +952,21 @@ def activate_popover(self, widget, person_handle):
892
952
# move view to person with animation
893
953
self .move_to_person (None , person_handle , True )
894
954
895
- def set_ancestors_generations (self , widget ):
955
+ def apply_spinner_delayed (self , widget , conf_const ):
896
956
"""
897
- Set count of ancestors generations to show .
957
+ Set params by spinners ( generations, spacing) .
898
958
Use timeout for better interface responsiveness.
899
959
"""
900
960
value = int (widget .get_value ())
901
961
# 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 ())
904
965
# timeout saving setting for better interface responsiveness
905
966
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 )
924
968
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 )
926
970
927
971
def build_bkmark_ext_panel (self ):
928
972
"""
@@ -1878,6 +1922,10 @@ def init_dot(self):
1878
1922
'interface.graphview-descendant-generations' )
1879
1923
self .ancestor_generations = self .view ._config .get (
1880
1924
'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
1881
1929
1882
1930
# get background color from gtk theme and convert it to hex
1883
1931
# else use white background
@@ -1912,10 +1960,8 @@ def init_dot(self):
1912
1960
dpi = 72
1913
1961
fontfamily = ""
1914
1962
fontsize = 14
1915
- nodesep = 0.20
1916
1963
pagedir = "BL"
1917
1964
rankdir = "TB"
1918
- ranksep = 0.40
1919
1965
ratio = "compress"
1920
1966
# as we are not using paper,
1921
1967
# choose a large 'page' size with no margin
0 commit comments