Skip to content

Commit

Permalink
[GraphView] add custom avatars (#459)
Browse files Browse the repository at this point in the history
  • Loading branch information
vantu5z authored Jan 18, 2021
1 parent 871089a commit 27c4aed
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 13 deletions.
111 changes: 111 additions & 0 deletions GraphView/avatars.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2020- Ivan Komaritsyn
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
import os

#-------------------------------------------------------------------------
#
# Gramps Modules
#
#-------------------------------------------------------------------------
from gramps.gen.lib import Person

from gramps.gen.const import GRAMPS_LOCALE as glocale
try:
_trans = glocale.get_addon_translator(__file__)
except ValueError:
_trans = glocale.translation
_ = _trans.gettext


class Avatars():
"""
Avatar support for GraphView.
"""
def __init__(self, config):
"""
config param - gramps.gen.config.
"""
self.config = config

# set avatars path '<...<GraphView_addon_path>/avatars>'
self.path, _filename = os.path.split(__file__)
self.path = os.path.join(self.path, 'avatars')

# define styles dictionary
# dic item: (id: name, directory)
self.styles = {0: (_('Custom'), None),
1: (_('Dark (default)'), 'dark'),
2: (_('Light'), 'light'),
3: (_('Cartoon'), 'cartoon'),
}

self.style = 1
self.custom = False
self.update_current_style()

def update_current_style(self):
"""
Update and check current style.
"""
self.style = self.config.get('interface.graphview-avatars-style')
if self.styles.get(self.style) is None:
self.style = 1

# set custom style mark
self.custom = self.style == 0

def get_avatar(self, gender):
"""
Return person gender avatar or None.
"""
if self.custom:
avatar = ''
if gender == Person.MALE:
avatar = self.config.get('interface.graphview-avatars-male')
elif gender == Person.FEMALE:
avatar = self.config.get('interface.graphview-avatars-female')
if avatar:
return avatar
else:
return None

style = self.styles.get(self.style)[1] # get style directory

if gender == Person.MALE:
return os.path.join(self.path, style, 'person_male.png')
if gender == Person.FEMALE:
return os.path.join(self.path, style, 'person_female.png')

def get_styles_list(self):
"""
List of styles.
List item: (id, name)
"""
styles_list = []
for key, item in self.styles.items():
styles_list.append((key, item[0]))
return styles_list

File renamed without changes
File renamed without changes
Binary file added GraphView/avatars/dark/person_female.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added GraphView/avatars/dark/person_male.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added GraphView/avatars/light/person_female.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added GraphView/avatars/light/person_male.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
100 changes: 87 additions & 13 deletions GraphView/graphview.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,13 @@

#-------------------------------------------------------------------------
#
# Search widget module
# GraphView modules
#
#-------------------------------------------------------------------------
import sys
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
from search_widget import SearchWidget, Popover, ListBoxRow
from search_widget import SearchWidget, Popover, ListBoxRow, get_person_tooltip
from avatars import Avatars


#-------------------------------------------------------------------------
Expand All @@ -144,6 +145,9 @@ class GraphView(NavigationView):
CONFIGSETTINGS = (
('interface.graphview-show-images', True),
('interface.graphview-show-avatars', True),
('interface.graphview-avatars-style', 1),
('interface.graphview-avatars-male', ''), # custom avatar
('interface.graphview-avatars-female', ''), # custom avatar
('interface.graphview-show-full-dates', False),
('interface.graphview-show-places', False),
('interface.graphview-place-format', 0),
Expand Down Expand Up @@ -193,6 +197,8 @@ def __init__(self, pdata, dbstate, uistate, nav_group=0):

# for disable animation options in config dialog
self.ani_widgets = []
# for disable custom avatar options in config dialog
self.avatar_widgets = []

self.additional_uis.append(self.additional_ui)
self.define_print_actions()
Expand Down Expand Up @@ -407,6 +413,38 @@ def cb_update_show_avatars(self, _client, _cnxn_id, entry, _data):
self.show_avatars = entry == 'True'
self.graph_widget.populate(self.get_active())

def cb_update_avatars_style(self, _client, _cnxn_id, entry, _data):
"""
Called when the configuration menu changes the avatars setting.
"""
for widget in self.avatar_widgets:
widget.set_visible(entry == '0')
self.graph_widget.populate(self.get_active())

def cb_on_combo_show(self, combobox):
"""
Called when the configuration menu show combobox widget for avatars.
Used to hide custom avatars settings.
"""
for widget in self.avatar_widgets:
widget.set_visible(combobox.get_active() == 0)

def cb_male_avatar_set(self, file_chooser_button):
"""
Called when the configuration menu changes the male avatar.
"""
self._config.set('interface.graphview-avatars-male',
file_chooser_button.get_filename())
self.graph_widget.populate(self.get_active())

def cb_female_avatar_set(self, file_chooser_button):
"""
Called when the configuration menu changes the female avatar.
"""
self._config.set('interface.graphview-avatars-female',
file_chooser_button.get_filename())
self.graph_widget.populate(self.get_active())

def cb_update_show_full_dates(self, _client, _cnxn_id, entry, _data):
"""
Called when the configuration menu changes the date setting.
Expand Down Expand Up @@ -566,6 +604,8 @@ def config_connect(self):
self.cb_update_show_images)
self._config.connect('interface.graphview-show-avatars',
self.cb_update_show_avatars)
self._config.connect('interface.graphview-avatars-style',
self.cb_update_avatars_style)
self._config.connect('interface.graphview-show-full-dates',
self.cb_update_show_full_dates)
self._config.connect('interface.graphview-show-places',
Expand Down Expand Up @@ -696,6 +736,47 @@ def theme_config_panel(self, configdialog):
font_btn.connect('font-set', self.config_change_font)
font_btn.set_filter_func(self.font_filter_func)

# Avatars options
# ===================================================================
row += 1
avatars = Avatars(self._config)
combo = configdialog.add_combo(grid, _('Avatars style'), row,
'interface.graphview-avatars-style',
avatars.get_styles_list())
combo.connect('show', self.cb_on_combo_show)

file_filter = Gtk.FileFilter()
file_filter.set_name(_('PNG files'))
file_filter.add_pattern("*.png")

self.avatar_widgets.clear()
row += 1
lbl = Gtk.Label(label=_('Male avatar:'), halign=Gtk.Align.END)
FCB_male = Gtk.FileChooserButton.new(_('Choose male avatar'),
Gtk.FileChooserAction.OPEN)
FCB_male.add_filter(file_filter)
FCB_male.set_filename(
self._config.get('interface.graphview-avatars-male'))
FCB_male.connect('file-set', self.cb_male_avatar_set)
grid.attach(lbl, 1, row, 1, 1)
grid.attach(FCB_male, 2, row, 1, 1)
self.avatar_widgets.append(lbl)
self.avatar_widgets.append(FCB_male)

row += 1
lbl = Gtk.Label(label=_('Female avatar:'), halign=Gtk.Align.END)
FCB_female = Gtk.FileChooserButton.new(_('Choose female avatar'),
Gtk.FileChooserAction.OPEN)
FCB_female.connect('file-set', self.cb_female_avatar_set)
FCB_female.add_filter(file_filter)
FCB_female.set_filename(
self._config.get('interface.graphview-avatars-female'))
grid.attach(lbl, 1, row, 1, 1)
grid.attach(FCB_female, 2, row, 1, 1)
self.avatar_widgets.append(lbl)
self.avatar_widgets.append(FCB_female)
# ===================================================================

return _('Themes'), grid

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

self.avatars = Avatars(self.view._config)

def __del__(self):
"""
Free stream file on destroy.
Expand Down Expand Up @@ -2175,6 +2258,7 @@ def init_dot(self):
ranksep = ranksep * 0.1
nodesep = self.view._config.get('interface.graphview-nodesep')
nodesep = nodesep * 0.1
self.avatars.update_current_style()
# get background color from gtk theme and convert it to hex
# else use white background
bg_color = self.context.lookup_color('theme_bg_color')
Expand Down Expand Up @@ -2838,16 +2922,6 @@ def get_person_themes(self, index=-1):
else:
return person_themes[0]

def get_avatar(self, gender):
"""
Return person gender avatar.
"""
path, _filename = os.path.split(__file__)
if gender == Person.MALE:
return os.path.join(path, 'person_male.png')
if gender == Person.FEMALE:
return os.path.join(path, 'person_female.png')

def get_person_label(self, person):
"""
Return person label string (with tags).
Expand All @@ -2871,7 +2945,7 @@ def get_person_label(self, person):
image = self.view.graph_widget.get_person_image(person,
kind='path')
if not image and self.show_avatars:
image = self.get_avatar(gender=person.gender)
image = self.avatars.get_avatar(gender=person.gender)

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

0 comments on commit 27c4aed

Please sign in to comment.