diff --git a/GraphView/avatars.py b/GraphView/avatars.py new file mode 100644 index 000000000..a67698dd0 --- /dev/null +++ b/GraphView/avatars.py @@ -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 '<.../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 + diff --git a/GraphView/person_female.png b/GraphView/avatars/cartoon/person_female.png similarity index 100% rename from GraphView/person_female.png rename to GraphView/avatars/cartoon/person_female.png diff --git a/GraphView/person_male.png b/GraphView/avatars/cartoon/person_male.png similarity index 100% rename from GraphView/person_male.png rename to GraphView/avatars/cartoon/person_male.png diff --git a/GraphView/avatars/dark/person_female.png b/GraphView/avatars/dark/person_female.png new file mode 100644 index 000000000..f542a59d8 Binary files /dev/null and b/GraphView/avatars/dark/person_female.png differ diff --git a/GraphView/avatars/dark/person_male.png b/GraphView/avatars/dark/person_male.png new file mode 100644 index 000000000..85ad73f67 Binary files /dev/null and b/GraphView/avatars/dark/person_male.png differ diff --git a/GraphView/avatars/light/person_female.png b/GraphView/avatars/light/person_female.png new file mode 100644 index 000000000..56506f73c Binary files /dev/null and b/GraphView/avatars/light/person_female.png differ diff --git a/GraphView/avatars/light/person_male.png b/GraphView/avatars/light/person_male.png new file mode 100644 index 000000000..126cbd5b6 Binary files /dev/null and b/GraphView/avatars/light/person_male.png differ diff --git a/GraphView/graphview.py b/GraphView/graphview.py index 1776c9b6f..ab4cb09b8 100644 --- a/GraphView/graphview.py +++ b/GraphView/graphview.py @@ -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 #------------------------------------------------------------------------- @@ -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), @@ -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() @@ -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. @@ -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', @@ -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): @@ -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. @@ -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') @@ -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). @@ -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 = '' % image