Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GraphView] add custom avatars #459

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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