Skip to content

Commit 27c4aed

Browse files
authored
[GraphView] add custom avatars (#459)
1 parent 871089a commit 27c4aed

File tree

8 files changed

+198
-13
lines changed

8 files changed

+198
-13
lines changed

GraphView/avatars.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# Gramps - a GTK+/GNOME based genealogy program
4+
#
5+
# Copyright (C) 2020- Ivan Komaritsyn
6+
#
7+
# This program is free software; you can redistribute it and/or modify
8+
# it under the terms of the GNU General Public License as published by
9+
# the Free Software Foundation; either version 2 of the License, or
10+
# (at your option) any later version.
11+
#
12+
# This program is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
# GNU General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU General Public License
18+
# along with this program; if not, write to the Free Software
19+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20+
21+
#-------------------------------------------------------------------------
22+
#
23+
# Python modules
24+
#
25+
#-------------------------------------------------------------------------
26+
import os
27+
28+
#-------------------------------------------------------------------------
29+
#
30+
# Gramps Modules
31+
#
32+
#-------------------------------------------------------------------------
33+
from gramps.gen.lib import Person
34+
35+
from gramps.gen.const import GRAMPS_LOCALE as glocale
36+
try:
37+
_trans = glocale.get_addon_translator(__file__)
38+
except ValueError:
39+
_trans = glocale.translation
40+
_ = _trans.gettext
41+
42+
43+
class Avatars():
44+
"""
45+
Avatar support for GraphView.
46+
"""
47+
def __init__(self, config):
48+
"""
49+
config param - gramps.gen.config.
50+
"""
51+
self.config = config
52+
53+
# set avatars path '<...<GraphView_addon_path>/avatars>'
54+
self.path, _filename = os.path.split(__file__)
55+
self.path = os.path.join(self.path, 'avatars')
56+
57+
# define styles dictionary
58+
# dic item: (id: name, directory)
59+
self.styles = {0: (_('Custom'), None),
60+
1: (_('Dark (default)'), 'dark'),
61+
2: (_('Light'), 'light'),
62+
3: (_('Cartoon'), 'cartoon'),
63+
}
64+
65+
self.style = 1
66+
self.custom = False
67+
self.update_current_style()
68+
69+
def update_current_style(self):
70+
"""
71+
Update and check current style.
72+
"""
73+
self.style = self.config.get('interface.graphview-avatars-style')
74+
if self.styles.get(self.style) is None:
75+
self.style = 1
76+
77+
# set custom style mark
78+
self.custom = self.style == 0
79+
80+
def get_avatar(self, gender):
81+
"""
82+
Return person gender avatar or None.
83+
"""
84+
if self.custom:
85+
avatar = ''
86+
if gender == Person.MALE:
87+
avatar = self.config.get('interface.graphview-avatars-male')
88+
elif gender == Person.FEMALE:
89+
avatar = self.config.get('interface.graphview-avatars-female')
90+
if avatar:
91+
return avatar
92+
else:
93+
return None
94+
95+
style = self.styles.get(self.style)[1] # get style directory
96+
97+
if gender == Person.MALE:
98+
return os.path.join(self.path, style, 'person_male.png')
99+
if gender == Person.FEMALE:
100+
return os.path.join(self.path, style, 'person_female.png')
101+
102+
def get_styles_list(self):
103+
"""
104+
List of styles.
105+
List item: (id, name)
106+
"""
107+
styles_list = []
108+
for key, item in self.styles.items():
109+
styles_list.append((key, item[0]))
110+
return styles_list
111+
File renamed without changes.
File renamed without changes.
5.59 KB
Loading
6.64 KB
Loading
12.2 KB
Loading
14.4 KB
Loading

GraphView/graphview.py

Lines changed: 87 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,13 @@
122122

123123
#-------------------------------------------------------------------------
124124
#
125-
# Search widget module
125+
# GraphView modules
126126
#
127127
#-------------------------------------------------------------------------
128128
import sys
129129
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
130-
from search_widget import SearchWidget, Popover, ListBoxRow
130+
from search_widget import SearchWidget, Popover, ListBoxRow, get_person_tooltip
131+
from avatars import Avatars
131132

132133

133134
#-------------------------------------------------------------------------
@@ -144,6 +145,9 @@ class GraphView(NavigationView):
144145
CONFIGSETTINGS = (
145146
('interface.graphview-show-images', True),
146147
('interface.graphview-show-avatars', True),
148+
('interface.graphview-avatars-style', 1),
149+
('interface.graphview-avatars-male', ''), # custom avatar
150+
('interface.graphview-avatars-female', ''), # custom avatar
147151
('interface.graphview-show-full-dates', False),
148152
('interface.graphview-show-places', False),
149153
('interface.graphview-place-format', 0),
@@ -193,6 +197,8 @@ def __init__(self, pdata, dbstate, uistate, nav_group=0):
193197

194198
# for disable animation options in config dialog
195199
self.ani_widgets = []
200+
# for disable custom avatar options in config dialog
201+
self.avatar_widgets = []
196202

197203
self.additional_uis.append(self.additional_ui)
198204
self.define_print_actions()
@@ -407,6 +413,38 @@ def cb_update_show_avatars(self, _client, _cnxn_id, entry, _data):
407413
self.show_avatars = entry == 'True'
408414
self.graph_widget.populate(self.get_active())
409415

416+
def cb_update_avatars_style(self, _client, _cnxn_id, entry, _data):
417+
"""
418+
Called when the configuration menu changes the avatars setting.
419+
"""
420+
for widget in self.avatar_widgets:
421+
widget.set_visible(entry == '0')
422+
self.graph_widget.populate(self.get_active())
423+
424+
def cb_on_combo_show(self, combobox):
425+
"""
426+
Called when the configuration menu show combobox widget for avatars.
427+
Used to hide custom avatars settings.
428+
"""
429+
for widget in self.avatar_widgets:
430+
widget.set_visible(combobox.get_active() == 0)
431+
432+
def cb_male_avatar_set(self, file_chooser_button):
433+
"""
434+
Called when the configuration menu changes the male avatar.
435+
"""
436+
self._config.set('interface.graphview-avatars-male',
437+
file_chooser_button.get_filename())
438+
self.graph_widget.populate(self.get_active())
439+
440+
def cb_female_avatar_set(self, file_chooser_button):
441+
"""
442+
Called when the configuration menu changes the female avatar.
443+
"""
444+
self._config.set('interface.graphview-avatars-female',
445+
file_chooser_button.get_filename())
446+
self.graph_widget.populate(self.get_active())
447+
410448
def cb_update_show_full_dates(self, _client, _cnxn_id, entry, _data):
411449
"""
412450
Called when the configuration menu changes the date setting.
@@ -566,6 +604,8 @@ def config_connect(self):
566604
self.cb_update_show_images)
567605
self._config.connect('interface.graphview-show-avatars',
568606
self.cb_update_show_avatars)
607+
self._config.connect('interface.graphview-avatars-style',
608+
self.cb_update_avatars_style)
569609
self._config.connect('interface.graphview-show-full-dates',
570610
self.cb_update_show_full_dates)
571611
self._config.connect('interface.graphview-show-places',
@@ -696,6 +736,47 @@ def theme_config_panel(self, configdialog):
696736
font_btn.connect('font-set', self.config_change_font)
697737
font_btn.set_filter_func(self.font_filter_func)
698738

739+
# Avatars options
740+
# ===================================================================
741+
row += 1
742+
avatars = Avatars(self._config)
743+
combo = configdialog.add_combo(grid, _('Avatars style'), row,
744+
'interface.graphview-avatars-style',
745+
avatars.get_styles_list())
746+
combo.connect('show', self.cb_on_combo_show)
747+
748+
file_filter = Gtk.FileFilter()
749+
file_filter.set_name(_('PNG files'))
750+
file_filter.add_pattern("*.png")
751+
752+
self.avatar_widgets.clear()
753+
row += 1
754+
lbl = Gtk.Label(label=_('Male avatar:'), halign=Gtk.Align.END)
755+
FCB_male = Gtk.FileChooserButton.new(_('Choose male avatar'),
756+
Gtk.FileChooserAction.OPEN)
757+
FCB_male.add_filter(file_filter)
758+
FCB_male.set_filename(
759+
self._config.get('interface.graphview-avatars-male'))
760+
FCB_male.connect('file-set', self.cb_male_avatar_set)
761+
grid.attach(lbl, 1, row, 1, 1)
762+
grid.attach(FCB_male, 2, row, 1, 1)
763+
self.avatar_widgets.append(lbl)
764+
self.avatar_widgets.append(FCB_male)
765+
766+
row += 1
767+
lbl = Gtk.Label(label=_('Female avatar:'), halign=Gtk.Align.END)
768+
FCB_female = Gtk.FileChooserButton.new(_('Choose female avatar'),
769+
Gtk.FileChooserAction.OPEN)
770+
FCB_female.connect('file-set', self.cb_female_avatar_set)
771+
FCB_female.add_filter(file_filter)
772+
FCB_female.set_filename(
773+
self._config.get('interface.graphview-avatars-female'))
774+
grid.attach(lbl, 1, row, 1, 1)
775+
grid.attach(FCB_female, 2, row, 1, 1)
776+
self.avatar_widgets.append(lbl)
777+
self.avatar_widgets.append(FCB_female)
778+
# ===================================================================
779+
699780
return _('Themes'), grid
700781

701782
def animation_config_panel(self, configdialog):
@@ -2130,6 +2211,8 @@ def __init__(self, dbstate, view, bold_size=0, norm_size=0):
21302211
# font if we use genealogical symbols
21312212
self.sym_font = None
21322213

2214+
self.avatars = Avatars(self.view._config)
2215+
21332216
def __del__(self):
21342217
"""
21352218
Free stream file on destroy.
@@ -2175,6 +2258,7 @@ def init_dot(self):
21752258
ranksep = ranksep * 0.1
21762259
nodesep = self.view._config.get('interface.graphview-nodesep')
21772260
nodesep = nodesep * 0.1
2261+
self.avatars.update_current_style()
21782262
# get background color from gtk theme and convert it to hex
21792263
# else use white background
21802264
bg_color = self.context.lookup_color('theme_bg_color')
@@ -2838,16 +2922,6 @@ def get_person_themes(self, index=-1):
28382922
else:
28392923
return person_themes[0]
28402924

2841-
def get_avatar(self, gender):
2842-
"""
2843-
Return person gender avatar.
2844-
"""
2845-
path, _filename = os.path.split(__file__)
2846-
if gender == Person.MALE:
2847-
return os.path.join(path, 'person_male.png')
2848-
if gender == Person.FEMALE:
2849-
return os.path.join(path, 'person_female.png')
2850-
28512925
def get_person_label(self, person):
28522926
"""
28532927
Return person label string (with tags).
@@ -2871,7 +2945,7 @@ def get_person_label(self, person):
28712945
image = self.view.graph_widget.get_person_image(person,
28722946
kind='path')
28732947
if not image and self.show_avatars:
2874-
image = self.get_avatar(gender=person.gender)
2948+
image = self.avatars.get_avatar(gender=person.gender)
28752949

28762950
if image is not None:
28772951
image = '<IMG SRC="%s"/>' % image

0 commit comments

Comments
 (0)