Add option to show the Gramps ID in parenthesis in the fan chart
Add option to show gramps id. Improve pylint score for the modified files. Fixes #11045
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -34,35 +34,25 @@
|
|||||||
# Python modules
|
# Python modules
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
from gi.repository import Pango
|
|
||||||
from gi.repository import GObject
|
|
||||||
from gi.repository import Gdk
|
|
||||||
from gi.repository import Gtk
|
|
||||||
from gi.repository import PangoCairo
|
|
||||||
import cairo
|
|
||||||
import math
|
import math
|
||||||
import colorsys
|
import cairo
|
||||||
import sys
|
|
||||||
import pickle
|
|
||||||
from html import escape
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# Gramps modules
|
# Gramps modules
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
from gramps.gen.display.name import displayer as name_displayer
|
|
||||||
from gramps.gen.errors import WindowActiveError
|
|
||||||
from ..editors import EditPerson, EditFamily
|
|
||||||
from ..utils import hex_to_rgb
|
from ..utils import hex_to_rgb
|
||||||
from ..ddtargets import DdTargets
|
from .fanchart import (FanChartWidget, PIXELS_PER_GENERATION, BORDER_EDGE_WIDTH)
|
||||||
from gramps.gen.utils.alive import probably_alive
|
from .fanchartdesc import (FanChartBaseWidget,
|
||||||
from gramps.gen.utils.libformatting import FormattingHelper
|
FanChartDescWidget,
|
||||||
from gramps.gen.utils.db import (find_children, find_parents, find_witnessed_people,
|
FanChartGrampsGUI,
|
||||||
get_age, get_timeperiod)
|
NORMAL, EXPANDED, COLLAPSED,
|
||||||
from gramps.gen.plug.report.utils import find_spouse
|
TRANSLATE_PX, CHILDRING_WIDTH,
|
||||||
from .fanchart import *
|
BACKGROUND_GRAD_GEN,
|
||||||
from .fanchartdesc import *
|
BACKGROUND_GRAD_AGE,
|
||||||
|
BACKGROUND_GRAD_PERIOD,
|
||||||
|
FORM_CIRCLE, TYPE_BOX_NORMAL, TYPE_BOX_FAMILY)
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@@ -70,12 +60,14 @@ from .fanchartdesc import *
|
|||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
PIXELS_PER_GENPERSON_RATIO = 0.55 # ratio of generation radius for person (rest for partner)
|
PIXELS_PER_GENPERSON_RATIO = 0.55 # ratio of generation radius for person
|
||||||
|
# (rest for partner)
|
||||||
PIXELS_PER_GEN_SMALL = 80
|
PIXELS_PER_GEN_SMALL = 80
|
||||||
PIXELS_PER_GEN_LARGE = 160
|
PIXELS_PER_GEN_LARGE = 160
|
||||||
N_GEN_SMALL = 4
|
N_GEN_SMALL = 4
|
||||||
PIXELS_PER_GENFAMILY = 25 # size of radius for family
|
PIXELS_PER_GENFAMILY = 25 # size of radius for family
|
||||||
PIXELS_PER_RECLAIM = 4 # size of the radius of pixels taken from family to reclaim space
|
PIXELS_PER_RECLAIM = 4 # size of the radius of pixels taken from family
|
||||||
|
# to reclaim space
|
||||||
PIXELS_PARTNER_GAP = 0 # Padding between someone and his partner
|
PIXELS_PARTNER_GAP = 0 # Padding between someone and his partner
|
||||||
PIXELS_CHILDREN_GAP = 5 # Padding between generations
|
PIXELS_CHILDREN_GAP = 5 # Padding between generations
|
||||||
PARENTRING_WIDTH = 12 # width of the parent ring inside the person
|
PARENTRING_WIDTH = 12 # width of the parent ring inside the person
|
||||||
@@ -103,8 +95,14 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
Fan Chart Widget. Handles visualization of data in self.data.
|
Fan Chart Widget. Handles visualization of data in self.data.
|
||||||
See main() of FanChartGramplet for example of model format.
|
See main() of FanChartGramplet for example of model format.
|
||||||
"""
|
"""
|
||||||
self.set_values(None, 6, 5, True, True, BACKGROUND_GRAD_GEN, True, 'Sans', '#0000FF',
|
self.gen2people = {}
|
||||||
'#FF0000', None, 0.5, ANGLE_WEIGHT, '#888a85')
|
self.gen2fam = {}
|
||||||
|
self.rootangle_rad_desc = [math.radians(275), math.radians(275 + 170)]
|
||||||
|
self.rootangle_rad_asc = [math.radians(90), math.radians(270)]
|
||||||
|
self.data = {}
|
||||||
|
self.set_values(None, 6, 5, True, True, BACKGROUND_GRAD_GEN, True,
|
||||||
|
'Sans', '#0000FF', '#FF0000', None, 0.5, ANGLE_WEIGHT,
|
||||||
|
'#888a85', False)
|
||||||
FanChartBaseWidget.__init__(self, dbstate, uistate, callback_popup)
|
FanChartBaseWidget.__init__(self, dbstate, uistate, callback_popup)
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
@@ -118,30 +116,35 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
self._fill_data_structures()
|
self._fill_data_structures()
|
||||||
|
|
||||||
# prepare the colors for the boxes
|
# prepare the colors for the boxes
|
||||||
self.prepare_background_box(self.generations_asc + self.generations_desc - 1)
|
self.prepare_background_box(self.generations_asc +
|
||||||
|
self.generations_desc - 1)
|
||||||
|
|
||||||
def set_values(self, root_person_handle, maxgen_asc, maxgen_desc, flipupsidedownname, twolinename, background,
|
def set_values(self, root_person_handle, maxgen_asc, maxgen_desc,
|
||||||
|
flipupsidedownname, twolinename, background,
|
||||||
background_gradient, fontdescr, grad_start, grad_end,
|
background_gradient, fontdescr, grad_start, grad_end,
|
||||||
filter, alpha_filter, angle_algo, dupcolor):
|
filtr, alpha_filter, angle_algo, dupcolor, showid):
|
||||||
"""
|
"""
|
||||||
Reset the values to be used:
|
Reset the values to be used:
|
||||||
|
|
||||||
:param root_person_handle: person to show
|
:param root_person_handle: person to show
|
||||||
:param maxgen_asc: maximum of ascendant generations to show
|
:param maxgen_asc: maximum of ascendant generations to show
|
||||||
:param maxgen_desc: maximum of descendant generations to show
|
:param maxgen_desc: maximum of descendant generations to show
|
||||||
:param flipupsidedownname: flip name on the left of the fanchart for the display of person's name
|
:param flipupsidedownname: flip name on the left of the fanchart
|
||||||
|
for the display of person's name
|
||||||
:param background: config setting of which background procedure to use
|
:param background: config setting of which background procedure to use
|
||||||
:type background: int
|
:type background: int
|
||||||
:param background_gradient: option to add an overall gradient for distinguishing Asc/Desc
|
:param background_gradient: option to add an overall gradient
|
||||||
|
for distinguishing Asc/Desc
|
||||||
:param fontdescr: string describing the font to use
|
:param fontdescr: string describing the font to use
|
||||||
:param grad_start: colors to use for background procedure
|
:param grad_start: colors to use for background procedure
|
||||||
:param grad_end: colors to use for background procedure
|
:param grad_end: colors to use for background procedure
|
||||||
:param filter: the person filter to apply to the people in the chart
|
:param filtr: the person filter to apply to the people in the chart
|
||||||
:param alpha_filter: the alpha transparency value (0-1) to apply to
|
:param alpha_filter: the alpha transparency value (0-1) to apply to
|
||||||
filtered out data
|
filtered out data
|
||||||
:param angle_algo: alorithm to use to calculate the sizes of the boxes
|
:param angle_algo: alorithm to use to calculate the sizes of the boxes
|
||||||
:param dupcolor: color to use for people or families that occur a second
|
:param dupcolor: color to use for people or families that occur a second
|
||||||
or more time
|
or more time
|
||||||
|
:param showid: option to show the gramps id or not
|
||||||
"""
|
"""
|
||||||
self.rootpersonh = root_person_handle
|
self.rootpersonh = root_person_handle
|
||||||
self.generations_asc = maxgen_asc
|
self.generations_asc = maxgen_asc
|
||||||
@@ -151,7 +154,7 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
self.fontdescr = fontdescr
|
self.fontdescr = fontdescr
|
||||||
self.grad_start = grad_start
|
self.grad_start = grad_start
|
||||||
self.grad_end = grad_end
|
self.grad_end = grad_end
|
||||||
self.filter = filter
|
self.filter = filtr
|
||||||
self.form = FORM_CIRCLE
|
self.form = FORM_CIRCLE
|
||||||
self.alpha_filter = alpha_filter
|
self.alpha_filter = alpha_filter
|
||||||
self.anglealgo = angle_algo
|
self.anglealgo = angle_algo
|
||||||
@@ -159,6 +162,7 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
self.childring = False
|
self.childring = False
|
||||||
self.flipupsidedownname = flipupsidedownname
|
self.flipupsidedownname = flipupsidedownname
|
||||||
self.twolinename = twolinename
|
self.twolinename = twolinename
|
||||||
|
self.showid = showid
|
||||||
|
|
||||||
def set_generations(self):
|
def set_generations(self):
|
||||||
"""
|
"""
|
||||||
@@ -172,12 +176,14 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
self.handle2fam = {}
|
self.handle2fam = {}
|
||||||
self.gen2people = {}
|
self.gen2people = {}
|
||||||
self.gen2fam = {}
|
self.gen2fam = {}
|
||||||
self.gen2people[0] = [(None, False, 0, 2 * math.pi, 0, 0, [], NORMAL)] # no center person
|
# no center person
|
||||||
|
self.gen2people[0] = [(None, False, 0, 2 * math.pi, 0, 0, [], NORMAL)]
|
||||||
self.gen2fam[0] = [] # no families
|
self.gen2fam[0] = [] # no families
|
||||||
for i in range(1, self.generations_desc):
|
for i in range(1, self.generations_desc):
|
||||||
self.gen2fam[i] = []
|
self.gen2fam[i] = []
|
||||||
self.gen2people[i] = []
|
self.gen2people[i] = []
|
||||||
self.gen2people[self.generations_desc] = [] # indication of more children
|
# indication of more children
|
||||||
|
self.gen2people[self.generations_desc] = []
|
||||||
|
|
||||||
# Ascendance part
|
# Ascendance part
|
||||||
self.angle = {}
|
self.angle = {}
|
||||||
@@ -187,13 +193,17 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
self.data[i] = [(None,) * 4] * 2 ** i
|
self.data[i] = [(None,) * 4] * 2 ** i
|
||||||
self.angle[i] = []
|
self.angle[i] = []
|
||||||
angle = self.rootangle_rad_asc[0]
|
angle = self.rootangle_rad_asc[0]
|
||||||
slice = 1 / (2 ** i) * (self.rootangle_rad_asc[1] - self.rootangle_rad_asc[0])
|
portion = 1 / (2 ** i) * (self.rootangle_rad_asc[1] -
|
||||||
for count in range(len(self.data[i])):
|
self.rootangle_rad_asc[0])
|
||||||
|
for dummy_count in range(len(self.data[i])):
|
||||||
# start, stop, state
|
# start, stop, state
|
||||||
self.angle[i].append([angle, angle + slice, NORMAL])
|
self.angle[i].append([angle, angle + portion, NORMAL])
|
||||||
angle += slice
|
angle += portion
|
||||||
|
|
||||||
def _fill_data_structures(self):
|
def _fill_data_structures(self):
|
||||||
|
"""
|
||||||
|
Initialize the data structures
|
||||||
|
"""
|
||||||
self.set_generations()
|
self.set_generations()
|
||||||
if not self.rootpersonh:
|
if not self.rootpersonh:
|
||||||
return
|
return
|
||||||
@@ -221,9 +231,10 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
for current in range(1, self.generations_asc):
|
for current in range(1, self.generations_asc):
|
||||||
parent = 0
|
parent = 0
|
||||||
# name, person, parents, children
|
# name, person, parents, children
|
||||||
for (p, q, c, d) in self.data[current - 1]:
|
for (pers, dummy_q, dummy_c, dummy_d) in self.data[current - 1]:
|
||||||
# Get father's and mother's details:
|
# Get father's and mother's details:
|
||||||
for person in [self._get_parent(p, True), self._get_parent(p, False)]:
|
for person in [self._get_parent(pers, True),
|
||||||
|
self._get_parent(pers, False)]:
|
||||||
if current == self.generations_asc - 1:
|
if current == self.generations_asc - 1:
|
||||||
parents = self._have_parents(person)
|
parents = self._have_parents(person)
|
||||||
else:
|
else:
|
||||||
@@ -235,17 +246,22 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
parent += 1
|
parent += 1
|
||||||
|
|
||||||
def nrgen_desc(self):
|
def nrgen_desc(self):
|
||||||
# compute the number of generations present
|
"""
|
||||||
|
compute the number of generations present
|
||||||
|
"""
|
||||||
for gen in range(self.generations_desc - 1, 0, -1):
|
for gen in range(self.generations_desc - 1, 0, -1):
|
||||||
if len(self.gen2people[gen]) > 0:
|
if self.gen2people[gen]:
|
||||||
return gen + 1
|
return gen + 1
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def nrgen_asc(self):
|
def nrgen_asc(self):
|
||||||
# compute the number of generations present
|
"""
|
||||||
|
compute the number of generations present
|
||||||
|
"""
|
||||||
for generation in range(self.generations_asc - 1, 0, -1):
|
for generation in range(self.generations_asc - 1, 0, -1):
|
||||||
for p in range(len(self.data[generation])):
|
for idx in range(len(self.data[generation])):
|
||||||
(person, parents, child, userdata) = self.data[generation][p]
|
(person, dummy_parents, dummy_child,
|
||||||
|
dummy_userdata) = self.data[generation][idx]
|
||||||
if person:
|
if person:
|
||||||
return generation
|
return generation
|
||||||
return 1
|
return 1
|
||||||
@@ -254,59 +270,73 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
"""
|
"""
|
||||||
Compute the current half radius of the ascendant circle
|
Compute the current half radius of the ascendant circle
|
||||||
"""
|
"""
|
||||||
radiusin, radius_asc = self.get_radiusinout_for_generation_asc(generation)
|
(dummy_radiusin,
|
||||||
|
radius_asc) = self.get_radiusinout_for_gen_asc(generation)
|
||||||
return radius_asc + BORDER_EDGE_WIDTH
|
return radius_asc + BORDER_EDGE_WIDTH
|
||||||
|
|
||||||
def maxradius_desc(self, generation):
|
def maxradius_desc(self, generation):
|
||||||
"""
|
"""
|
||||||
Compute the current radius of the descendant circle
|
Compute the current radius of the descendant circle
|
||||||
"""
|
"""
|
||||||
radiusin_pers, radiusout_pers, radiusin_partner, radius_desc = self.get_radiusinout_for_generation_pair(generation-1)
|
(dummy_radiusin_pers, dummy_radiusout_pers, dummy_radiusin_partner,
|
||||||
|
radius_desc) = self.get_radiusinout_for_gen_pair(generation-1)
|
||||||
return radius_desc + BORDER_EDGE_WIDTH
|
return radius_desc + BORDER_EDGE_WIDTH
|
||||||
|
|
||||||
def halfdist(self):
|
def halfdist(self):
|
||||||
"""
|
"""
|
||||||
Compute the current max half radius of the circle
|
Compute the current max half radius of the circle
|
||||||
"""
|
"""
|
||||||
return max(self.maxradius_desc(self.nrgen_desc()), self.maxradius_asc(self.nrgen_asc()))
|
return max(self.maxradius_desc(self.nrgen_desc()),
|
||||||
|
self.maxradius_asc(self.nrgen_asc()))
|
||||||
|
|
||||||
def get_radiusinout_for_generation_desc(self, generation):
|
def get_radiusinout_for_gen_desc(self, generation):
|
||||||
"""
|
"""
|
||||||
Get the in and out radius for descendant generation (starting with center pers = 0)
|
Get the in and out radius for descendant generation
|
||||||
|
(starting with center pers = 0)
|
||||||
"""
|
"""
|
||||||
radius_first_gen = self.CENTER - (1 - PIXELS_PER_GENPERSON_RATIO) * PIXELS_PER_GEN_SMALL
|
radius_first_gen = (self.CENTER -
|
||||||
|
(1 - PIXELS_PER_GENPERSON_RATIO) *
|
||||||
|
PIXELS_PER_GEN_SMALL)
|
||||||
if generation < N_GEN_SMALL:
|
if generation < N_GEN_SMALL:
|
||||||
radius_start = PIXELS_PER_GEN_SMALL * generation + radius_first_gen
|
radius_start = PIXELS_PER_GEN_SMALL * generation + radius_first_gen
|
||||||
return (radius_start, radius_start + PIXELS_PER_GEN_SMALL)
|
return (radius_start, radius_start + PIXELS_PER_GEN_SMALL)
|
||||||
else:
|
else:
|
||||||
radius_start = PIXELS_PER_GEN_SMALL * N_GEN_SMALL + PIXELS_PER_GEN_LARGE \
|
radius_start = (PIXELS_PER_GEN_SMALL * N_GEN_SMALL +
|
||||||
* (generation - N_GEN_SMALL) + radius_first_gen
|
PIXELS_PER_GEN_LARGE * (generation - N_GEN_SMALL) +
|
||||||
|
radius_first_gen)
|
||||||
return (radius_start, radius_start + PIXELS_PER_GEN_LARGE)
|
return (radius_start, radius_start + PIXELS_PER_GEN_LARGE)
|
||||||
|
|
||||||
def get_radiusinout_for_generation_asc(self, generation):
|
def get_radiusinout_for_gen_asc(self, generation):
|
||||||
"""
|
"""
|
||||||
Get the in and out radius for ascendant generation (starting with center pers = 0)
|
Get the in and out radius for ascendant generation
|
||||||
|
(starting with center pers = 0)
|
||||||
"""
|
"""
|
||||||
radiusin, radius_first_gen = self.get_radiusinout_for_generation_desc(0)
|
dummy_radiusin, radius_first_gen = self.get_radiusinout_for_gen_desc(0)
|
||||||
outerradius = generation * PIXELS_PER_GENERATION + radius_first_gen
|
outerradius = generation * PIXELS_PER_GENERATION + radius_first_gen
|
||||||
innerradius = (generation - 1) * PIXELS_PER_GENERATION + radius_first_gen
|
innerradius = ((generation - 1) * PIXELS_PER_GENERATION +
|
||||||
|
radius_first_gen)
|
||||||
if generation == 0:
|
if generation == 0:
|
||||||
innerradius = CHILDRING_WIDTH + TRANSLATE_PX
|
innerradius = CHILDRING_WIDTH + TRANSLATE_PX
|
||||||
return (innerradius, outerradius)
|
return (innerradius, outerradius)
|
||||||
|
|
||||||
def get_radiusinout_for_generation_pair(self, generation):
|
def get_radiusinout_for_gen_pair(self, generation):
|
||||||
"""
|
"""
|
||||||
Get the in and out radius for descendant generation pair (starting with center pers = 0)
|
Get the in and out radius for descendant generation pair
|
||||||
:return: (radiusin_pers, radiusout_pers, radiusin_partner, radiusout_partner)
|
(starting with center pers = 0)
|
||||||
|
:return: (radiusin_pers, radiusout_pers,
|
||||||
|
radiusin_partner, radiusout_partner)
|
||||||
"""
|
"""
|
||||||
radiusin, radiusout = self.get_radiusinout_for_generation_desc(generation)
|
radiusin, radiusout = self.get_radiusinout_for_gen_desc(generation)
|
||||||
radius_spread = radiusout - radiusin - PIXELS_CHILDREN_GAP - PIXELS_PARTNER_GAP
|
radius_spread = (radiusout - radiusin -
|
||||||
|
PIXELS_CHILDREN_GAP - PIXELS_PARTNER_GAP)
|
||||||
|
|
||||||
radiusin_pers = radiusin + PIXELS_CHILDREN_GAP
|
radiusin_pers = radiusin + PIXELS_CHILDREN_GAP
|
||||||
radiusout_pers = radiusin_pers + PIXELS_PER_GENPERSON_RATIO * radius_spread
|
radiusout_pers = (radiusin_pers +
|
||||||
|
PIXELS_PER_GENPERSON_RATIO * radius_spread)
|
||||||
radiusin_partner = radiusout_pers + PIXELS_PARTNER_GAP
|
radiusin_partner = radiusout_pers + PIXELS_PARTNER_GAP
|
||||||
radiusout_partner = radiusout
|
radiusout_partner = radiusout
|
||||||
return (radiusin_pers, radiusout_pers, radiusin_partner, radiusout_partner)
|
return (radiusin_pers, radiusout_pers,
|
||||||
|
radiusin_partner, radiusout_partner)
|
||||||
|
|
||||||
def people_generator(self):
|
def people_generator(self):
|
||||||
"""
|
"""
|
||||||
@@ -319,8 +349,9 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
for data in self.gen2fam[generation]:
|
for data in self.gen2fam[generation]:
|
||||||
yield (data[7], data[6])
|
yield (data[7], data[6])
|
||||||
for generation in range(self.generations_asc):
|
for generation in range(self.generations_asc):
|
||||||
for p in range(len(self.data[generation])):
|
for idx in range(len(self.data[generation])):
|
||||||
(person, parents, child, userdata) = self.data[generation][p]
|
(person, dummy_parents, dummy_child,
|
||||||
|
userdata) = self.data[generation][idx]
|
||||||
yield (person, userdata)
|
yield (person, userdata)
|
||||||
|
|
||||||
def innerpeople_generator(self):
|
def innerpeople_generator(self):
|
||||||
@@ -330,47 +361,57 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
if False:
|
if False:
|
||||||
yield
|
yield
|
||||||
|
|
||||||
def draw_background(self, cr):
|
def draw_background(self, ctx):
|
||||||
cr.save()
|
"""
|
||||||
|
Draw the background
|
||||||
|
"""
|
||||||
|
ctx.save()
|
||||||
|
|
||||||
cr.rotate(math.radians(self.rotate_value))
|
ctx.rotate(math.radians(self.rotate_value))
|
||||||
delta = (self.rootangle_rad_asc[0] - self.rootangle_rad_desc[1]) / 2.0 % math.pi
|
delta = (self.rootangle_rad_asc[0] -
|
||||||
|
self.rootangle_rad_desc[1]) / 2.0 % math.pi
|
||||||
|
|
||||||
cr.move_to(0, 0)
|
ctx.move_to(0, 0)
|
||||||
radius_gradient_asc = 1.5 * self.maxradius_asc(self.generations_asc)
|
radius_gradient_asc = 1.5 * self.maxradius_asc(self.generations_asc)
|
||||||
gradient_asc = cairo.RadialGradient(0, 0, self.CENTER, 0, 0, radius_gradient_asc)
|
gradient_asc = cairo.RadialGradient(0, 0, self.CENTER,
|
||||||
|
0, 0, radius_gradient_asc)
|
||||||
color = hex_to_rgb(self.grad_end)
|
color = hex_to_rgb(self.grad_end)
|
||||||
gradient_asc.add_color_stop_rgba(0.0, color[0]/255, color[1]/255, color[2]/255, 0.5)
|
gradient_asc.add_color_stop_rgba(0.0, color[0] / 255, color[1] / 255,
|
||||||
|
color[2] / 255, 0.5)
|
||||||
gradient_asc.add_color_stop_rgba(1.0, 1, 1, 1, 0.0)
|
gradient_asc.add_color_stop_rgba(1.0, 1, 1, 1, 0.0)
|
||||||
start_rad, stop_rad = self.rootangle_rad_asc[0] - delta, self.rootangle_rad_asc[1] + delta
|
start_rad, stop_rad = (self.rootangle_rad_asc[0] - delta,
|
||||||
cr.set_source(gradient_asc)
|
self.rootangle_rad_asc[1] + delta)
|
||||||
cr.arc(0, 0, radius_gradient_asc, start_rad, stop_rad)
|
ctx.set_source(gradient_asc)
|
||||||
cr.fill()
|
ctx.arc(0, 0, radius_gradient_asc, start_rad, stop_rad)
|
||||||
|
ctx.fill()
|
||||||
|
|
||||||
cr.move_to(0, 0)
|
ctx.move_to(0, 0)
|
||||||
radius_gradient_desc = 1.5 * self.maxradius_desc(self.generations_desc)
|
radius_gradient_desc = 1.5 * self.maxradius_desc(self.generations_desc)
|
||||||
gradient_desc = cairo.RadialGradient(0, 0, self.CENTER, 0, 0, radius_gradient_desc)
|
gradient_desc = cairo.RadialGradient(0, 0, self.CENTER,
|
||||||
|
0, 0, radius_gradient_desc)
|
||||||
color = hex_to_rgb(self.grad_start)
|
color = hex_to_rgb(self.grad_start)
|
||||||
gradient_desc.add_color_stop_rgba(0.0, color[0]/255, color[1]/255, color[2]/255, 0.5)
|
gradient_desc.add_color_stop_rgba(0.0, color[0] / 255, color[1] / 255,
|
||||||
|
color[2] / 255, 0.5)
|
||||||
gradient_desc.add_color_stop_rgba(1.0, 1, 1, 1, 0.0)
|
gradient_desc.add_color_stop_rgba(1.0, 1, 1, 1, 0.0)
|
||||||
start_rad, stop_rad = self.rootangle_rad_desc[0] - delta, self.rootangle_rad_desc[1] + delta
|
start_rad, stop_rad = (self.rootangle_rad_desc[0] - delta,
|
||||||
cr.set_source(gradient_desc)
|
self.rootangle_rad_desc[1] + delta)
|
||||||
cr.arc(0, 0, radius_gradient_desc, start_rad, stop_rad)
|
ctx.set_source(gradient_desc)
|
||||||
cr.fill()
|
ctx.arc(0, 0, radius_gradient_desc, start_rad, stop_rad)
|
||||||
cr.restore()
|
ctx.fill()
|
||||||
|
ctx.restore()
|
||||||
|
|
||||||
def draw(self, cr=None, scale=1.0):
|
def draw(self, ctx=None, scale=1.0):
|
||||||
"""
|
"""
|
||||||
The main method to do the drawing.
|
The main method to do the drawing.
|
||||||
If cr is given, we assume we draw draw raw on the cairo context cr
|
If ctx is given, we assume we draw draw raw on the cairo context ctx
|
||||||
To draw in GTK3 and use the allocation, set cr=None.
|
To draw in GTK3 and use the allocation, set ctx=None.
|
||||||
Note: when drawing for display, to counter a Gtk issue with scrolling
|
Note: when drawing for display, to counter a Gtk issue with scrolling
|
||||||
or resizing the drawing window, we draw on a surface, then copy to the
|
or resizing the drawing window, we draw on a surface, then copy to the
|
||||||
drawing context when the Gtk 'draw' signal arrives.
|
drawing context when the Gtk 'draw' signal arrives.
|
||||||
"""
|
"""
|
||||||
# first do size request of what we will need
|
# first do size request of what we will need
|
||||||
halfdist = self.halfdist()
|
halfdist = self.halfdist()
|
||||||
if not cr: # Display
|
if not ctx: # Display
|
||||||
size_w = size_h = 2 * halfdist
|
size_w = size_h = 2 * halfdist
|
||||||
|
|
||||||
size_w_a = self.get_allocated_width()
|
size_w_a = self.get_allocated_width()
|
||||||
@@ -380,81 +421,101 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
size_h = self.get_allocated_height()
|
size_h = self.get_allocated_height()
|
||||||
self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
|
self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
|
||||||
size_w, size_h)
|
size_w, size_h)
|
||||||
cr = cairo.Context(self.surface)
|
ctx = cairo.Context(self.surface)
|
||||||
self.center_xy = self.center_xy_from_delta()
|
self.center_xy = self.center_xy_from_delta()
|
||||||
cr.translate(*self.center_xy)
|
ctx.translate(*self.center_xy)
|
||||||
else: # printing
|
else: # printing
|
||||||
self.center_xy = halfdist, halfdist
|
self.center_xy = halfdist, halfdist
|
||||||
cr.scale(scale, scale)
|
ctx.scale(scale, scale)
|
||||||
cr.translate(halfdist, halfdist)
|
ctx.translate(halfdist, halfdist)
|
||||||
|
|
||||||
cr.save()
|
ctx.save()
|
||||||
# Draw background
|
# Draw background
|
||||||
if self.background_gradient:
|
if self.background_gradient:
|
||||||
self.draw_background(cr)
|
self.draw_background(ctx)
|
||||||
# Draw center person:
|
# Draw center person:
|
||||||
(person, dup, start, slice, parentfampos, nrfam, userdata, status) \
|
(person, dup, start, portion, dummy_parentfampos, dummy_nrfam,
|
||||||
= self.gen2people[0][0]
|
userdata, status) = self.gen2people[0][0]
|
||||||
if not person:
|
if not person:
|
||||||
return
|
return
|
||||||
gen_remapped = self.generations_desc - 1 # remapped generation
|
gen_remapped = self.generations_desc - 1 # remapped generation
|
||||||
if gen_remapped == 0: gen_remapped = (self.generations_desc + self.generations_asc - 1) # remapped generation
|
if gen_remapped == 0:
|
||||||
|
# remapped generation
|
||||||
|
gen_remapped = (self.generations_desc + self.generations_asc - 1)
|
||||||
radiusin_pers, radiusout_pers, radiusin_partner, radiusout_partner = \
|
radiusin_pers, radiusout_pers, radiusin_partner, radiusout_partner = \
|
||||||
self.get_radiusinout_for_generation_pair(0)
|
self.get_radiusinout_for_gen_pair(0)
|
||||||
radiusin = TRANSLATE_PX
|
radiusin = TRANSLATE_PX
|
||||||
radiusout = radiusout_pers
|
radiusout = radiusout_pers
|
||||||
self.draw_person(cr, person, radiusin, radiusout, math.pi / 2, math.pi / 2 + 2 * math.pi,
|
self.draw_person(ctx, person, radiusin, radiusout,
|
||||||
gen_remapped, False, userdata, is_central_person=True)
|
math.pi / 2, math.pi / 2 + 2 * math.pi, gen_remapped,
|
||||||
|
False, userdata, is_central_person=True)
|
||||||
# draw center to move chart
|
# draw center to move chart
|
||||||
cr.set_source_rgb(0, 0, 0) # black
|
ctx.set_source_rgb(0, 0, 0) # black
|
||||||
cr.move_to(TRANSLATE_PX, 0)
|
ctx.move_to(TRANSLATE_PX, 0)
|
||||||
cr.arc(0, 0, TRANSLATE_PX, 0, 2 * math.pi)
|
ctx.arc(0, 0, TRANSLATE_PX, 0, 2 * math.pi)
|
||||||
cr.fill()
|
ctx.fill()
|
||||||
|
|
||||||
cr.rotate(math.radians(self.rotate_value))
|
ctx.rotate(math.radians(self.rotate_value))
|
||||||
# Ascendance
|
# Ascendance
|
||||||
for generation in range(self.generations_asc - 1, 0, -1):
|
for generation in range(self.generations_asc - 1, 0, -1):
|
||||||
for p in range(len(self.data[generation])):
|
for idx in range(len(self.data[generation])):
|
||||||
(person, parents, child, userdata) = self.data[generation][p]
|
(person, parents, dummy_child,
|
||||||
|
userdata) = self.data[generation][idx]
|
||||||
if person:
|
if person:
|
||||||
start, stop, state = self.angle[generation][p]
|
start, stop, state = self.angle[generation][idx]
|
||||||
if state in [NORMAL, EXPANDED]:
|
if state in [NORMAL, EXPANDED]:
|
||||||
radiusin, radiusout = self.get_radiusinout_for_generation_asc(generation)
|
fct = self.get_radiusinout_for_gen_asc
|
||||||
|
radiusin, radiusout = fct(generation)
|
||||||
dup = False
|
dup = False
|
||||||
gen_remapped = generation + self.generations_desc - 1 # remapped generation
|
# remapped generation
|
||||||
self.draw_person(cr, person, radiusin, radiusout, start, stop,
|
gen_remapped = generation + self.generations_desc - 1
|
||||||
gen_remapped, dup, userdata, thick=(state == EXPANDED),
|
indicator = (generation == self.generations_asc - 1
|
||||||
has_moregen_indicator=(generation == self.generations_asc - 1 and parents))
|
and parents)
|
||||||
|
self.draw_person(ctx, person, radiusin, radiusout,
|
||||||
|
start, stop, gen_remapped, dup,
|
||||||
|
userdata, thick=(state == EXPANDED),
|
||||||
|
has_moregen_indicator=indicator)
|
||||||
|
|
||||||
# Descendance
|
# Descendance
|
||||||
for gen in range(self.generations_desc):
|
for gen in range(self.generations_desc):
|
||||||
radiusin_pers, radiusout_pers, radiusin_partner, radiusout_partner = \
|
(radiusin_pers, radiusout_pers, radiusin_partner,
|
||||||
self.get_radiusinout_for_generation_pair(gen)
|
radiusout_partner) = self.get_radiusinout_for_gen_pair(gen)
|
||||||
gen_remapped = (self.generations_desc - gen - 1)
|
gen_remapped = (self.generations_desc - gen - 1)
|
||||||
if gen_remapped == 0: gen_remapped = (self.generations_desc + self.generations_asc - 1) # remapped generation
|
if gen_remapped == 0:
|
||||||
|
# remapped generation
|
||||||
|
gen_remapped = (self.generations_desc +
|
||||||
|
self.generations_asc - 1)
|
||||||
if gen > 0:
|
if gen > 0:
|
||||||
for pdata in self.gen2people[gen]:
|
for pdata in self.gen2people[gen]:
|
||||||
# person, duplicate or not, start angle, slice size,
|
# person, duplicate or not, start angle, slice size,
|
||||||
# parent pos in fam, nrfam, userdata, status
|
# parent pos in fam, nrfam, userdata, status
|
||||||
pers, dup, start, slice, pospar, nrfam, userdata, status = pdata
|
(pers, dup, start, portion, dummy_pospar, dummy_nrfam,
|
||||||
|
userdata, status) = pdata
|
||||||
if status != COLLAPSED:
|
if status != COLLAPSED:
|
||||||
self.draw_person(cr, pers, radiusin_pers, radiusout_pers,
|
self.draw_person(ctx, pers, radiusin_pers,
|
||||||
start, start + slice, gen_remapped, dup, userdata,
|
radiusout_pers,
|
||||||
|
start, start + portion,
|
||||||
|
gen_remapped, dup, userdata,
|
||||||
thick=status != NORMAL)
|
thick=status != NORMAL)
|
||||||
#if gen < self.generations_desc - 1:
|
#if gen < self.generations_desc - 1:
|
||||||
for famdata in self.gen2fam[gen]:
|
for famdata in self.gen2fam[gen]:
|
||||||
# family, duplicate or not, start angle, slice size,
|
# family, duplicate or not, start angle, slice size,
|
||||||
# spouse pos in gen, nrchildren, userdata, status
|
# spouse pos in gen, nrchildren, userdata, status
|
||||||
fam, dup, start, slice, posfam, nrchild, userdata, partner, status = famdata
|
(fam, dup, start, portion, dummy_posfam, dummy_nrchild,
|
||||||
|
userdata, partner, status) = famdata
|
||||||
if status != COLLAPSED:
|
if status != COLLAPSED:
|
||||||
more_pers_flag = (gen == self.generations_desc - 1
|
more_pers_flag = (gen == self.generations_desc - 1
|
||||||
and len(fam.get_child_ref_list()) > 0)
|
and fam.get_child_ref_list())
|
||||||
self.draw_person(cr, partner, radiusin_partner, radiusout_partner, start, start + slice,
|
self.draw_person(ctx, partner,
|
||||||
gen_remapped, dup, userdata, thick=(status != NORMAL), has_moregen_indicator=more_pers_flag)
|
radiusin_partner, radiusout_partner,
|
||||||
cr.restore()
|
start, start + portion,
|
||||||
|
gen_remapped, dup, userdata,
|
||||||
|
thick=(status != NORMAL),
|
||||||
|
has_moregen_indicator=more_pers_flag)
|
||||||
|
ctx.restore()
|
||||||
|
|
||||||
if self.background in [BACKGROUND_GRAD_AGE, BACKGROUND_GRAD_PERIOD]:
|
if self.background in [BACKGROUND_GRAD_AGE, BACKGROUND_GRAD_PERIOD]:
|
||||||
self.draw_gradient_legend(cr, halfdist)
|
self.draw_gradient_legend(ctx, halfdist)
|
||||||
|
|
||||||
def cell_address_under_cursor(self, curx, cury):
|
def cell_address_under_cursor(self, curx, cury):
|
||||||
"""
|
"""
|
||||||
@@ -462,19 +523,23 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
position x and y.
|
position x and y.
|
||||||
None if outside of diagram
|
None if outside of diagram
|
||||||
"""
|
"""
|
||||||
radius, rads, raw_rads = self.cursor_to_polar(curx, cury, get_raw_rads=True)
|
radius, rads, dummy_raw_rads = self.cursor_to_polar(curx, cury,
|
||||||
|
get_raw_rads=True)
|
||||||
|
|
||||||
if radius < TRANSLATE_PX:
|
if radius < TRANSLATE_PX:
|
||||||
return None
|
return None
|
||||||
radius_parents = self.get_radiusinout_for_generation_asc(0)[1]
|
radius_parents = self.get_radiusinout_for_gen_asc(0)[1]
|
||||||
if (radius < radius_parents) or \
|
if ((radius < radius_parents) or
|
||||||
(self.radian_in_bounds(self.rootangle_rad_desc[0], rads, self.rootangle_rad_desc[1])):
|
self.radian_in_bounds(self.rootangle_rad_desc[0], rads,
|
||||||
|
self.rootangle_rad_desc[1])):
|
||||||
cell_address = self.cell_address_under_cursor_desc(rads, radius)
|
cell_address = self.cell_address_under_cursor_desc(rads, radius)
|
||||||
if cell_address is not None:
|
if cell_address is not None:
|
||||||
return (TYPE_DESCENDANCE,) + cell_address
|
return (TYPE_DESCENDANCE,) + cell_address
|
||||||
elif self.radian_in_bounds(self.rootangle_rad_asc[0], rads, self.rootangle_rad_asc[1]):
|
elif self.radian_in_bounds(self.rootangle_rad_asc[0], rads,
|
||||||
|
self.rootangle_rad_asc[1]):
|
||||||
cell_address = self.cell_address_under_cursor_asc(rads, radius)
|
cell_address = self.cell_address_under_cursor_asc(rads, radius)
|
||||||
if cell_address and cell_address[0]==0: return None # There is a gap before first parents
|
if cell_address and cell_address[0] == 0:
|
||||||
|
return None # There is a gap before first parents
|
||||||
if cell_address is not None:
|
if cell_address is not None:
|
||||||
return (TYPE_ASCENDANCE,) + cell_address
|
return (TYPE_ASCENDANCE,) + cell_address
|
||||||
|
|
||||||
@@ -488,8 +553,8 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
"""
|
"""
|
||||||
generation, selected, btype = None, None, TYPE_BOX_NORMAL
|
generation, selected, btype = None, None, TYPE_BOX_NORMAL
|
||||||
for gen in range(self.generations_desc):
|
for gen in range(self.generations_desc):
|
||||||
radiusin_pers, radiusout_pers, radiusin_partner, radiusout_partner \
|
(radiusin_pers, radiusout_pers, radiusin_partner,
|
||||||
= self.get_radiusinout_for_generation_pair(gen)
|
radiusout_partner) = self.get_radiusinout_for_gen_pair(gen)
|
||||||
if radiusin_pers <= radius <= radiusout_pers:
|
if radiusin_pers <= radius <= radiusout_pers:
|
||||||
generation, btype = gen, TYPE_BOX_NORMAL
|
generation, btype = gen, TYPE_BOX_NORMAL
|
||||||
break
|
break
|
||||||
@@ -497,8 +562,9 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
generation, btype = gen, TYPE_BOX_FAMILY
|
generation, btype = gen, TYPE_BOX_FAMILY
|
||||||
break
|
break
|
||||||
# find what person is in this position:
|
# find what person is in this position:
|
||||||
if not (generation is None) and 0 <= generation:
|
if not (generation is None) and generation > 0:
|
||||||
selected = FanChartDescWidget.personpos_at_angle(self, generation, rads, btype)
|
selected = FanChartDescWidget.personpos_at_angle(self, generation,
|
||||||
|
rads, btype)
|
||||||
|
|
||||||
if (generation is None or selected is None):
|
if (generation is None or selected is None):
|
||||||
return None
|
return None
|
||||||
@@ -514,13 +580,13 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
|
|
||||||
generation, selected = None, None
|
generation, selected = None, None
|
||||||
for gen in range(self.generations_asc):
|
for gen in range(self.generations_asc):
|
||||||
radiusin, radiusout = self.get_radiusinout_for_generation_asc(gen)
|
radiusin, radiusout = self.get_radiusinout_for_gen_asc(gen)
|
||||||
if radiusin <= radius <= radiusout:
|
if radiusin <= radius <= radiusout:
|
||||||
generation = gen
|
generation = gen
|
||||||
break
|
break
|
||||||
|
|
||||||
# find what person is in this position:
|
# find what person is in this position:
|
||||||
if not (generation is None) and 0 <= generation:
|
if not (generation is None) and generation > 0:
|
||||||
selected = FanChartWidget.personpos_at_angle(self, generation, rads)
|
selected = FanChartWidget.personpos_at_angle(self, generation, rads)
|
||||||
if (generation is None or selected is None):
|
if (generation is None or selected is None):
|
||||||
return None
|
return None
|
||||||
@@ -556,35 +622,40 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
self.queue_draw()
|
self.queue_draw()
|
||||||
|
|
||||||
def expand_parents(self, generation, selected, current):
|
def expand_parents(self, generation, selected, current):
|
||||||
if generation >= self.generations_asc: return
|
if generation >= self.generations_asc:
|
||||||
|
return
|
||||||
selected = 2 * selected
|
selected = 2 * selected
|
||||||
start, stop, state = self.angle[generation][selected]
|
start, stop, state = self.angle[generation][selected]
|
||||||
if state in [NORMAL, EXPANDED]:
|
if state in [NORMAL, EXPANDED]:
|
||||||
slice = (stop - start) * 2.0
|
portion = (stop - start) * 2.0
|
||||||
self.angle[generation][selected] = [current, current + slice, state]
|
self.angle[generation][selected] = [current, current + portion,
|
||||||
|
state]
|
||||||
self.expand_parents(generation + 1, selected, current)
|
self.expand_parents(generation + 1, selected, current)
|
||||||
current += slice
|
current += portion
|
||||||
start, stop, state = self.angle[generation][selected + 1]
|
start, stop, state = self.angle[generation][selected + 1]
|
||||||
if state in [NORMAL, EXPANDED]:
|
if state in [NORMAL, EXPANDED]:
|
||||||
slice = (stop - start) * 2.0
|
portion = (stop - start) * 2.0
|
||||||
self.angle[generation][selected + 1] = [current, current + slice,
|
self.angle[generation][selected + 1] = [current, current + portion,
|
||||||
state]
|
state]
|
||||||
self.expand_parents(generation + 1, selected + 1, current)
|
self.expand_parents(generation + 1, selected + 1, current)
|
||||||
|
|
||||||
def show_parents(self, generation, selected, angle, slice):
|
def show_parents(self, generation, selected, angle, portion):
|
||||||
if generation >= self.generations_asc: return
|
if generation >= self.generations_asc:
|
||||||
|
return
|
||||||
selected *= 2
|
selected *= 2
|
||||||
self.angle[generation][selected][0] = angle
|
self.angle[generation][selected][0] = angle
|
||||||
self.angle[generation][selected][1] = angle + slice
|
self.angle[generation][selected][1] = angle + portion
|
||||||
self.angle[generation][selected][2] = NORMAL
|
self.angle[generation][selected][2] = NORMAL
|
||||||
self.show_parents(generation + 1, selected, angle, slice / 2.0)
|
self.show_parents(generation + 1, selected, angle, portion / 2.0)
|
||||||
self.angle[generation][selected + 1][0] = angle + slice
|
self.angle[generation][selected + 1][0] = angle + portion
|
||||||
self.angle[generation][selected + 1][1] = angle + slice + slice
|
self.angle[generation][selected + 1][1] = angle + portion + portion
|
||||||
self.angle[generation][selected + 1][2] = NORMAL
|
self.angle[generation][selected + 1][2] = NORMAL
|
||||||
self.show_parents(generation + 1, selected + 1, angle + slice, slice / 2.0)
|
self.show_parents(generation + 1, selected + 1,
|
||||||
|
angle + portion, portion / 2.0)
|
||||||
|
|
||||||
def hide_parents(self, generation, selected, angle):
|
def hide_parents(self, generation, selected, angle):
|
||||||
if generation >= self.generations_asc: return
|
if generation >= self.generations_asc:
|
||||||
|
return
|
||||||
selected = 2 * selected
|
selected = 2 * selected
|
||||||
self.angle[generation][selected][0] = angle
|
self.angle[generation][selected][0] = angle
|
||||||
self.angle[generation][selected][1] = angle
|
self.angle[generation][selected][1] = angle
|
||||||
@@ -596,19 +667,20 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
|
|||||||
self.hide_parents(generation + 1, selected + 1, angle)
|
self.hide_parents(generation + 1, selected + 1, angle)
|
||||||
|
|
||||||
def shrink_parents(self, generation, selected, current):
|
def shrink_parents(self, generation, selected, current):
|
||||||
if generation >= self.generations_asc: return
|
if generation >= self.generations_asc:
|
||||||
|
return
|
||||||
selected = 2 * selected
|
selected = 2 * selected
|
||||||
start, stop, state = self.angle[generation][selected]
|
start, stop, state = self.angle[generation][selected]
|
||||||
if state in [NORMAL, EXPANDED]:
|
if state in [NORMAL, EXPANDED]:
|
||||||
slice = (stop - start) / 2.0
|
portion = (stop - start) / 2.0
|
||||||
self.angle[generation][selected] = [current, current + slice,
|
self.angle[generation][selected] = [current, current + portion,
|
||||||
state]
|
state]
|
||||||
self.shrink_parents(generation + 1, selected, current)
|
self.shrink_parents(generation + 1, selected, current)
|
||||||
current += slice
|
current += portion
|
||||||
start, stop, state = self.angle[generation][selected + 1]
|
start, stop, state = self.angle[generation][selected + 1]
|
||||||
if state in [NORMAL, EXPANDED]:
|
if state in [NORMAL, EXPANDED]:
|
||||||
slice = (stop - start) / 2.0
|
portion = (stop - start) / 2.0
|
||||||
self.angle[generation][selected + 1] = [current, current + slice,
|
self.angle[generation][selected + 1] = [current, current + portion,
|
||||||
state]
|
state]
|
||||||
self.shrink_parents(generation + 1, selected + 1, current)
|
self.shrink_parents(generation + 1, selected + 1, current)
|
||||||
|
|
||||||
@@ -630,10 +702,13 @@ class FanChart2WayGrampsGUI(FanChartGrampsGUI):
|
|||||||
data.
|
data.
|
||||||
"""
|
"""
|
||||||
root_person_handle = self.get_active('Person')
|
root_person_handle = self.get_active('Person')
|
||||||
self.fan.set_values(root_person_handle, self.generations_asc, self.generations_desc, self.flipupsidedownname, self.twolinename, self.background,
|
self.fan.set_values(root_person_handle, self.generations_asc,
|
||||||
self.background_gradient, self.fonttype, self.grad_start, self.grad_end,
|
self.generations_desc, self.flipupsidedownname,
|
||||||
self.generic_filter, self.alpha_filter,
|
self.twolinename, self.background,
|
||||||
self.angle_algo, self.dupcolor)
|
self.background_gradient, self.fonttype,
|
||||||
|
self.grad_start, self.grad_end, self.generic_filter,
|
||||||
|
self.alpha_filter, self.angle_algo, self.dupcolor,
|
||||||
|
self.showid)
|
||||||
self.fan.reset()
|
self.fan.reset()
|
||||||
self.fan.draw()
|
self.fan.draw()
|
||||||
self.fan.queue_draw()
|
self.fan.queue_draw()
|
||||||
|
@@ -33,47 +33,37 @@
|
|||||||
# Python modules
|
# Python modules
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
from gi.repository import Pango
|
|
||||||
from gi.repository import GObject
|
|
||||||
from gi.repository import Gdk
|
|
||||||
from gi.repository import Gtk
|
|
||||||
from gi.repository import PangoCairo
|
|
||||||
import cairo
|
|
||||||
import math
|
import math
|
||||||
import colorsys
|
import cairo
|
||||||
import pickle
|
|
||||||
from html import escape
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# Gramps modules
|
# Gramps modules
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
from gramps.gen.display.name import displayer as name_displayer
|
|
||||||
from gramps.gen.errors import WindowActiveError
|
|
||||||
from ..editors import EditPerson, EditFamily
|
|
||||||
from ..utils import hex_to_rgb
|
|
||||||
from ..ddtargets import DdTargets
|
|
||||||
from gramps.gen.utils.alive import probably_alive
|
|
||||||
from gramps.gen.utils.libformatting import FormattingHelper
|
|
||||||
from gramps.gen.utils.db import (find_children, find_parents, find_witnessed_people,
|
|
||||||
get_age, get_timeperiod)
|
|
||||||
from gramps.gen.plug.report.utils import find_spouse
|
from gramps.gen.plug.report.utils import find_spouse
|
||||||
from .fanchart import *
|
from ..utils import hex_to_rgb
|
||||||
|
from .fanchart import (FanChartBaseWidget, FanChartGrampsGUI,
|
||||||
|
PAD_PX, TRANSLATE_PX,
|
||||||
|
FORM_CIRCLE, FORM_HALFCIRCLE, FORM_QUADRANT,
|
||||||
|
NORMAL, EXPANDED, COLLAPSED,
|
||||||
|
BACKGROUND_GRAD_GEN, BACKGROUND_GRAD_AGE,
|
||||||
|
BACKGROUND_GRAD_PERIOD, CHILDRING_WIDTH)
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# Constants
|
# Constants
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
pi = math.pi
|
|
||||||
|
|
||||||
PIXELS_PER_GENPERSON_RATIO = 0.55 # ratio of generation radius for person (rest for partner)
|
PIXELS_PER_GENPERSON_RATIO = 0.55 # ratio of generation radius for person
|
||||||
|
# (rest for partner)
|
||||||
PIXELS_PER_GEN_SMALL = 80
|
PIXELS_PER_GEN_SMALL = 80
|
||||||
PIXELS_PER_GEN_LARGE = 160
|
PIXELS_PER_GEN_LARGE = 160
|
||||||
N_GEN_SMALL = 4
|
N_GEN_SMALL = 4
|
||||||
PIXELS_PER_GENFAMILY = 25 # size of radius for family
|
PIXELS_PER_GENFAMILY = 25 # size of radius for family
|
||||||
PIXELS_PER_RECLAIM = 4 # size of the radius of pixels taken from family to reclaim space
|
PIXELS_PER_RECLAIM = 4 # size of the radius of pixels taken from family
|
||||||
|
# to reclaim space
|
||||||
PIXELS_PARTNER_GAP = 0 # Padding between someone and his partner
|
PIXELS_PARTNER_GAP = 0 # Padding between someone and his partner
|
||||||
PIXELS_CHILDREN_GAP = 5 # Padding between generations
|
PIXELS_CHILDREN_GAP = 5 # Padding between generations
|
||||||
PARENTRING_WIDTH = 12 # width of the parent ring inside the person
|
PARENTRING_WIDTH = 12 # width of the parent ring inside the person
|
||||||
@@ -101,31 +91,42 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
Fan Chart Widget. Handles visualization of data in self.data.
|
Fan Chart Widget. Handles visualization of data in self.data.
|
||||||
See main() of FanChartGramplet for example of model format.
|
See main() of FanChartGramplet for example of model format.
|
||||||
"""
|
"""
|
||||||
self.set_values(None, 9, True, True, BACKGROUND_GRAD_GEN, 'Sans', '#0000FF',
|
self.gen2people = {}
|
||||||
'#FF0000', None, 0.5, FORM_CIRCLE, ANGLE_WEIGHT, '#888a85')
|
self.gen2fam = {}
|
||||||
|
self.rootangle_rad = []
|
||||||
|
self.handle2desc = {}
|
||||||
|
self.famhandle2desc = {}
|
||||||
|
self.handle2fam = {}
|
||||||
|
self.innerring = []
|
||||||
|
self.angle = {}
|
||||||
|
self.set_values(None, 9, True, True, BACKGROUND_GRAD_GEN, 'Sans',
|
||||||
|
'#0000FF', '#FF0000', None, 0.5,
|
||||||
|
FORM_CIRCLE, ANGLE_WEIGHT, '#888a85', False)
|
||||||
FanChartBaseWidget.__init__(self, dbstate, uistate, callback_popup)
|
FanChartBaseWidget.__init__(self, dbstate, uistate, callback_popup)
|
||||||
|
|
||||||
def set_values(self, root_person_handle, maxgen, flipupsidedownname, twolinename, background,
|
def set_values(self, root_person_handle, maxgen, flipupsidedownname,
|
||||||
fontdescr, grad_start, grad_end,
|
twolinename, background, fontdescr, grad_start, grad_end,
|
||||||
filter, alpha_filter, form, angle_algo, dupcolor):
|
filtr, alpha_filter, form, angle_algo, dupcolor, showid):
|
||||||
"""
|
"""
|
||||||
Reset the values to be used:
|
Reset the values to be used:
|
||||||
|
|
||||||
:param root_person_handle: person to show
|
:param root_person_handle: person to show
|
||||||
:param maxgen: maximum generations to show
|
:param maxgen: maximum generations to show
|
||||||
:param flipupsidedownname: flip name on the left of the fanchart for the display of person's name
|
:param flipupsidedownname: flip name on the left of the fanchart
|
||||||
|
for the display of person's name
|
||||||
:param background: config setting of which background procedure to use
|
:param background: config setting of which background procedure to use
|
||||||
:type background: int
|
:type background: int
|
||||||
:param fontdescr: string describing the font to use
|
:param fontdescr: string describing the font to use
|
||||||
:param grad_start: colors to use for background procedure
|
:param grad_start: colors to use for background procedure
|
||||||
:param grad_end: colors to use for background procedure
|
:param grad_end: colors to use for background procedure
|
||||||
:param filter: the person filter to apply to the people in the chart
|
:param filtr: the person filter to apply to the people in the chart
|
||||||
:param alpha_filter: the alpha transparency value (0-1) to apply to
|
:param alpha_filter: the alpha transparency value (0-1) to apply to
|
||||||
filtered out data
|
filtered out data
|
||||||
:param form: the ``FORM_`` constant for the fanchart
|
:param form: the ``FORM_`` constant for the fanchart
|
||||||
:param angle_algo: alorithm to use to calculate the sizes of the boxes
|
:param angle_algo: alorithm to use to calculate the sizes of the boxes
|
||||||
:param dupcolor: color to use for people or families that occur a second
|
:param dupcolor: color to use for people or families that occur a second
|
||||||
or more time
|
or more time
|
||||||
|
:param showid: to show the gramps_id or not
|
||||||
"""
|
"""
|
||||||
self.rootpersonh = root_person_handle
|
self.rootpersonh = root_person_handle
|
||||||
self.generations = maxgen
|
self.generations = maxgen
|
||||||
@@ -133,7 +134,7 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
self.fontdescr = fontdescr
|
self.fontdescr = fontdescr
|
||||||
self.grad_start = grad_start
|
self.grad_start = grad_start
|
||||||
self.grad_end = grad_end
|
self.grad_end = grad_end
|
||||||
self.filter = filter
|
self.filter = filtr
|
||||||
self.alpha_filter = alpha_filter
|
self.alpha_filter = alpha_filter
|
||||||
self.form = form
|
self.form = form
|
||||||
self.anglealgo = angle_algo
|
self.anglealgo = angle_algo
|
||||||
@@ -141,6 +142,7 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
self.childring = False
|
self.childring = False
|
||||||
self.flipupsidedownname = flipupsidedownname
|
self.flipupsidedownname = flipupsidedownname
|
||||||
self.twolinename = twolinename
|
self.twolinename = twolinename
|
||||||
|
self.showid = showid
|
||||||
|
|
||||||
def set_generations(self):
|
def set_generations(self):
|
||||||
"""
|
"""
|
||||||
@@ -160,7 +162,8 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
self.gen2people = {}
|
self.gen2people = {}
|
||||||
self.gen2fam = {}
|
self.gen2fam = {}
|
||||||
self.innerring = []
|
self.innerring = []
|
||||||
self.gen2people[0] = [(None, False, 0, 2*pi, 0, 0, [], NORMAL)] #no center person
|
self.gen2people[0] = [(None, False, 0, 2*math.pi, 0, 0,
|
||||||
|
[], NORMAL)] #no center person
|
||||||
self.gen2fam[0] = [] #no families
|
self.gen2fam[0] = [] #no families
|
||||||
self.angle = {}
|
self.angle = {}
|
||||||
self.angle[-2] = []
|
self.angle[-2] = []
|
||||||
@@ -180,7 +183,7 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
|
|
||||||
# person, duplicate or not, start angle, slice size,
|
# person, duplicate or not, start angle, slice size,
|
||||||
# text, parent pos in fam, nrfam, userdata, status
|
# text, parent pos in fam, nrfam, userdata, status
|
||||||
self.gen2people[0] = [[person, False, 0, 2*pi, 0, 0, [], NORMAL]]
|
self.gen2people[0] = [[person, False, 0, 2*math.pi, 0, 0, [], NORMAL]]
|
||||||
self.handle2desc[self.rootpersonh] = 0
|
self.handle2desc[self.rootpersonh] = 0
|
||||||
# fill in data for the parents
|
# fill in data for the parents
|
||||||
self.innerring = []
|
self.innerring = []
|
||||||
@@ -191,7 +194,8 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
family = self.dbstate.db.get_family_from_handle(family_handle)
|
family = self.dbstate.db.get_family_from_handle(family_handle)
|
||||||
if not family:
|
if not family:
|
||||||
continue
|
continue
|
||||||
for hparent in [family.get_father_handle(), family.get_mother_handle()]:
|
for hparent in [family.get_father_handle(),
|
||||||
|
family.get_mother_handle()]:
|
||||||
if hparent and hparent not in handleparents:
|
if hparent and hparent not in handleparents:
|
||||||
parent = self.dbstate.db.get_person_from_handle(hparent)
|
parent = self.dbstate.db.get_person_from_handle(hparent)
|
||||||
if parent:
|
if parent:
|
||||||
@@ -224,26 +228,31 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
fam_duplicate = family_handle in self.famhandle2desc
|
fam_duplicate = family_handle in self.famhandle2desc
|
||||||
# family, duplicate or not, start angle, slice size,
|
# family, duplicate or not, start angle, slice size,
|
||||||
# spouse pos in gen, nrchildren, userdata, parnter, status
|
# spouse pos in gen, nrchildren, userdata, parnter, status
|
||||||
self.gen2fam[gen].append([family, fam_duplicate, 0, 0, pos, 0, [], spouse, NORMAL])
|
self.gen2fam[gen].append([family, fam_duplicate, 0, 0,
|
||||||
|
pos, 0, [], spouse, NORMAL])
|
||||||
posfam = len(self.gen2fam[gen]) - 1
|
posfam = len(self.gen2fam[gen]) - 1
|
||||||
|
|
||||||
if not fam_duplicate and gen < maxgen-1:
|
if not fam_duplicate and gen < maxgen-1:
|
||||||
nrchild = len(family.get_child_ref_list())
|
nrchild = len(family.get_child_ref_list())
|
||||||
self.gen2fam[gen][posfam][5] = nrchild
|
self.gen2fam[gen][posfam][5] = nrchild
|
||||||
for child_ref in family.get_child_ref_list():
|
for child_ref in family.get_child_ref_list():
|
||||||
child = self.dbstate.db.get_person_from_handle(child_ref.ref)
|
chld = self.dbstate.db.get_person_from_handle(child_ref.ref)
|
||||||
child_dup = child_ref.ref in self.handle2desc
|
child_dup = child_ref.ref in self.handle2desc
|
||||||
if not child_dup:
|
if not child_dup:
|
||||||
self.handle2desc[child_ref.ref] = 0 # mark this child as processed
|
# mark this child as processed
|
||||||
|
self.handle2desc[child_ref.ref] = 0
|
||||||
# person, duplicate or not, start angle, slice size,
|
# person, duplicate or not, start angle, slice size,
|
||||||
# parent pos in fam, nrfam, userdata, status
|
# parent pos in fam, nrfam, userdata, status
|
||||||
self.gen2people[gen+1].append([child, child_dup, 0, 0, posfam, 0, [], NORMAL])
|
self.gen2people[gen+1].append([chld, child_dup, 0, 0,
|
||||||
|
posfam, 0, [], NORMAL])
|
||||||
totdescfam += 1 #add this person as descendant
|
totdescfam += 1 #add this person as descendant
|
||||||
pospers = len(self.gen2people[gen + 1]) - 1
|
pospers = len(self.gen2people[gen + 1]) - 1
|
||||||
if not child_dup:
|
if not child_dup:
|
||||||
nrdesc = self._rec_fill_data(gen+1, child, pospers, maxgen)
|
nrdesc = self._rec_fill_data(gen + 1, chld,
|
||||||
|
pospers, maxgen)
|
||||||
self.handle2desc[child_ref.ref] += nrdesc
|
self.handle2desc[child_ref.ref] += nrdesc
|
||||||
totdescfam += nrdesc # add children of him as descendants
|
# add children of him as descendants
|
||||||
|
totdescfam += nrdesc
|
||||||
if not fam_duplicate:
|
if not fam_duplicate:
|
||||||
self.famhandle2desc[family_handle] = totdescfam
|
self.famhandle2desc[family_handle] = totdescfam
|
||||||
totdesc += totdescfam
|
totdesc += totdescfam
|
||||||
@@ -255,13 +264,13 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
"""
|
"""
|
||||||
#first we compute the size of the slice.
|
#first we compute the size of the slice.
|
||||||
#set angles root person
|
#set angles root person
|
||||||
start, slice = start_rad, stop_rad - start_rad
|
start, portion = start_rad, stop_rad - start_rad
|
||||||
nr_gen = len(self.gen2people)-1
|
nr_gen = len(self.gen2people)-1
|
||||||
# Fill in central person angles
|
# Fill in central person angles
|
||||||
gen = 0
|
gen = 0
|
||||||
data = self.gen2people[gen][0]
|
data = self.gen2people[gen][0]
|
||||||
data[2] = start
|
data[2] = start
|
||||||
data[3] = slice
|
data[3] = portion
|
||||||
for gen in range(0, nr_gen):
|
for gen in range(0, nr_gen):
|
||||||
prevpartnerdatahandle = None
|
prevpartnerdatahandle = None
|
||||||
offset = 0
|
offset = 0
|
||||||
@@ -281,40 +290,42 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
#partner of a new person: reset the offset
|
#partner of a new person: reset the offset
|
||||||
offset = 0
|
offset = 0
|
||||||
prevpartnerdatahandle = persondata[0].handle
|
prevpartnerdatahandle = persondata[0].handle
|
||||||
slice = personslice/(nrdescperson+nrfam)*(nrdescfam+1)
|
portion = personslice/(nrdescperson+nrfam)*(nrdescfam+1)
|
||||||
if data_fam[8] == COLLAPSED:
|
if data_fam[8] == COLLAPSED:
|
||||||
slice = 0
|
portion = 0
|
||||||
elif data_fam[8] == EXPANDED:
|
elif data_fam[8] == EXPANDED:
|
||||||
slice = personslice
|
portion = personslice
|
||||||
|
|
||||||
data_fam[2] = personstart + offset
|
data_fam[2] = personstart + offset
|
||||||
data_fam[3] = slice
|
data_fam[3] = portion
|
||||||
offset += slice
|
offset += portion
|
||||||
|
|
||||||
## if nrdescperson == 0:
|
## if nrdescperson == 0:
|
||||||
## #no offspring, draw as large as fraction of
|
## #no offspring, draw as large as fraction of
|
||||||
## #nr families
|
## #nr families
|
||||||
## nrfam = persondata[6]
|
## nrfam = persondata[6]
|
||||||
## slice = personslice/nrfam
|
## portion = personslice/nrfam
|
||||||
## data_fam[2] = personstart + offset
|
## data_fam[2] = personstart + offset
|
||||||
## data_fam[3] = slice
|
## data_fam[3] = portion
|
||||||
## offset += slice
|
## offset += portion
|
||||||
## elif nrdescfam == 0:
|
## elif nrdescfam == 0:
|
||||||
## #no offspring this family, but there is another
|
## #no offspring this family, but there is another
|
||||||
## #family. We draw this as a weight of 1
|
## #family. We draw this as a weight of 1
|
||||||
## nrfam = persondata[6]
|
## nrfam = persondata[6]
|
||||||
## slice = personslice/(nrdescperson + nrfam - 1)*(nrdescfam+1)
|
## portion = (personslice/(nrdescperson + nrfam - 1) *
|
||||||
|
## (nrdescfam + 1))
|
||||||
## data_fam[2] = personstart + offset
|
## data_fam[2] = personstart + offset
|
||||||
## data_fam[3] = slice
|
## data_fam[3] = portion
|
||||||
## offset += slice
|
## offset += portion
|
||||||
## else:
|
## else:
|
||||||
## #this family has offspring. We give it space for it's
|
## #this family has offspring. We give it space for it's
|
||||||
## #weight in offspring
|
## #weight in offspring
|
||||||
## nrfam = persondata[6]
|
## nrfam = persondata[6]
|
||||||
## slice = personslice/(nrdescperson + nrfam - 1)*(nrdescfam+1)
|
## portion = (personslice/(nrdescperson + nrfam - 1) *
|
||||||
|
## (nrdescfam + 1))
|
||||||
## data_fam[2] = personstart + offset
|
## data_fam[2] = personstart + offset
|
||||||
## data_fam[3] = slice
|
## data_fam[3] = portion
|
||||||
## offset += slice
|
## offset += portion
|
||||||
|
|
||||||
prevfamdatahandle = None
|
prevfamdatahandle = None
|
||||||
offset = 0
|
offset = 0
|
||||||
@@ -333,27 +344,30 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
#now we divide this slice to the weight of children,
|
#now we divide this slice to the weight of children,
|
||||||
#adding one for every child
|
#adding one for every child
|
||||||
if self.anglealgo == ANGLE_CHEQUI:
|
if self.anglealgo == ANGLE_CHEQUI:
|
||||||
slice = famslice / nrchild
|
portion = famslice / nrchild
|
||||||
elif self.anglealgo == ANGLE_WEIGHT:
|
elif self.anglealgo == ANGLE_WEIGHT:
|
||||||
slice = famslice/(nrdescfam) * (nrdesc + 1)
|
portion = famslice/(nrdescfam) * (nrdesc + 1)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError('Unknown angle algorithm %d' % self.anglealgo)
|
raise NotImplementedError('Unknown angle algorithm %d' %
|
||||||
|
self.anglealgo)
|
||||||
if prevfamdatahandle != parentfamdata[0].handle:
|
if prevfamdatahandle != parentfamdata[0].handle:
|
||||||
#reset the offset
|
#reset the offset
|
||||||
offset = 0
|
offset = 0
|
||||||
prevfamdatahandle = parentfamdata[0].handle
|
prevfamdatahandle = parentfamdata[0].handle
|
||||||
if persondata[7] == COLLAPSED:
|
if persondata[7] == COLLAPSED:
|
||||||
slice = 0
|
portion = 0
|
||||||
elif persondata[7] == EXPANDED:
|
elif persondata[7] == EXPANDED:
|
||||||
slice = famslice
|
portion = famslice
|
||||||
persondata[2] = famstart + offset
|
persondata[2] = famstart + offset
|
||||||
persondata[3] = slice
|
persondata[3] = portion
|
||||||
offset += slice
|
offset += portion
|
||||||
|
|
||||||
def nrgen(self):
|
def nrgen(self):
|
||||||
#compute the number of generations present
|
"""
|
||||||
|
compute the number of generations present
|
||||||
|
"""
|
||||||
for gen in range(self.generations - 1, 0, -1):
|
for gen in range(self.generations - 1, 0, -1):
|
||||||
if len(self.gen2people[gen]) > 0:
|
if self.gen2people[gen]:
|
||||||
return gen + 1
|
return gen + 1
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
@@ -364,24 +378,34 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
return self.get_radiusinout_for_generation(self.nrgen())[1]
|
return self.get_radiusinout_for_generation(self.nrgen())[1]
|
||||||
|
|
||||||
def get_radiusinout_for_generation(self, generation):
|
def get_radiusinout_for_generation(self, generation):
|
||||||
|
"""
|
||||||
|
Get the in and out radius for the generation
|
||||||
|
"""
|
||||||
radius_first_gen = 14 # fudged to make inner circle a bit tighter
|
radius_first_gen = 14 # fudged to make inner circle a bit tighter
|
||||||
if generation < N_GEN_SMALL:
|
if generation < N_GEN_SMALL:
|
||||||
radius_start = PIXELS_PER_GEN_SMALL * generation + radius_first_gen
|
radius_start = PIXELS_PER_GEN_SMALL * generation + radius_first_gen
|
||||||
return (radius_start, radius_start + PIXELS_PER_GEN_SMALL)
|
return (radius_start, radius_start + PIXELS_PER_GEN_SMALL)
|
||||||
else:
|
else:
|
||||||
radius_start = PIXELS_PER_GEN_SMALL * N_GEN_SMALL + PIXELS_PER_GEN_LARGE \
|
radius_start = (PIXELS_PER_GEN_SMALL * N_GEN_SMALL +
|
||||||
* ( generation - N_GEN_SMALL ) + radius_first_gen
|
PIXELS_PER_GEN_LARGE * (generation - N_GEN_SMALL)
|
||||||
|
+ radius_first_gen)
|
||||||
return (radius_start, radius_start + PIXELS_PER_GEN_LARGE)
|
return (radius_start, radius_start + PIXELS_PER_GEN_LARGE)
|
||||||
|
|
||||||
def get_radiusinout_for_generation_pair(self,generation):
|
def get_radiusinout_for_gen_pair(self, generation):
|
||||||
|
"""
|
||||||
|
Get the in and out radius for the father and mother
|
||||||
|
"""
|
||||||
radiusin, radiusout = self.get_radiusinout_for_generation(generation)
|
radiusin, radiusout = self.get_radiusinout_for_generation(generation)
|
||||||
radius_spread = radiusout - radiusin - PIXELS_CHILDREN_GAP - PIXELS_PARTNER_GAP
|
radius_spread = (radiusout - radiusin -
|
||||||
|
PIXELS_CHILDREN_GAP - PIXELS_PARTNER_GAP)
|
||||||
|
|
||||||
radiusin_pers = radiusin + PIXELS_CHILDREN_GAP
|
radiusin_pers = radiusin + PIXELS_CHILDREN_GAP
|
||||||
radiusout_pers = radiusin_pers + PIXELS_PER_GENPERSON_RATIO * radius_spread
|
radiusout_pers = (radiusin_pers +
|
||||||
|
PIXELS_PER_GENPERSON_RATIO * radius_spread)
|
||||||
radiusin_partner = radiusout_pers + PIXELS_PARTNER_GAP
|
radiusin_partner = radiusout_pers + PIXELS_PARTNER_GAP
|
||||||
radiusout_partner = radiusout
|
radiusout_partner = radiusout
|
||||||
return (radiusin_pers,radiusout_pers,radiusin_partner,radiusout_partner)
|
return (radiusin_pers, radiusout_pers,
|
||||||
|
radiusin_partner, radiusout_partner)
|
||||||
|
|
||||||
def people_generator(self):
|
def people_generator(self):
|
||||||
"""
|
"""
|
||||||
@@ -402,18 +426,18 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
parent, userdata = parentdata
|
parent, userdata = parentdata
|
||||||
yield (parent, userdata)
|
yield (parent, userdata)
|
||||||
|
|
||||||
def draw(self, cr=None, scale=1.0):
|
def draw(self, ctx=None, scale=1.0):
|
||||||
"""
|
"""
|
||||||
The main method to do the drawing.
|
The main method to do the drawing.
|
||||||
If cr is given, we assume we draw draw raw on the cairo context cr
|
If ctx is given, we assume we draw draw raw on the cairo context ctx
|
||||||
To draw in GTK3 and use the allocation, set cr=None.
|
To draw in GTK3 and use the allocation, set ctx=None.
|
||||||
Note: when drawing for display, to counter a Gtk issue with scrolling
|
Note: when drawing for display, to counter a Gtk issue with scrolling
|
||||||
or resizing the drawing window, we draw on a surface, then copy to the
|
or resizing the drawing window, we draw on a surface, then copy to the
|
||||||
drawing context when the Gtk 'draw' signal arrives.
|
drawing context when the Gtk 'draw' signal arrives.
|
||||||
"""
|
"""
|
||||||
# first do size request of what we will need
|
# first do size request of what we will need
|
||||||
halfdist = self.halfdist()
|
halfdist = self.halfdist()
|
||||||
if not cr: # Display
|
if not ctx: # Display
|
||||||
if self.form == FORM_CIRCLE:
|
if self.form == FORM_CIRCLE:
|
||||||
size_w = size_h = 2 * halfdist
|
size_w = size_h = 2 * halfdist
|
||||||
elif self.form == FORM_HALFCIRCLE:
|
elif self.form == FORM_HALFCIRCLE:
|
||||||
@@ -429,67 +453,73 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
size_h = self.get_allocated_height()
|
size_h = self.get_allocated_height()
|
||||||
self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
|
self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
|
||||||
size_w, size_h)
|
size_w, size_h)
|
||||||
cr = cairo.Context(self.surface)
|
ctx = cairo.Context(self.surface)
|
||||||
self.center_xy = self.center_xy_from_delta()
|
self.center_xy = self.center_xy_from_delta()
|
||||||
cr.translate(*self.center_xy)
|
ctx.translate(*self.center_xy)
|
||||||
else: # printing
|
else: # printing
|
||||||
if self.form == FORM_QUADRANT:
|
if self.form == FORM_QUADRANT:
|
||||||
self.center_xy = self.CENTER, halfdist
|
self.center_xy = self.CENTER, halfdist
|
||||||
else:
|
else:
|
||||||
self.center_xy = halfdist, halfdist
|
self.center_xy = halfdist, halfdist
|
||||||
cr.scale(scale, scale)
|
ctx.scale(scale, scale)
|
||||||
cr.translate(*self.center_xy)
|
ctx.translate(*self.center_xy)
|
||||||
|
|
||||||
cr.save()
|
ctx.save()
|
||||||
# Draw center person:
|
# Draw center person:
|
||||||
(person, dup, start, slice, parentfampos, nrfam, userdata, status) \
|
(person, dup, start, portion, dummy_parentfampos, dummy_nrfam,
|
||||||
= self.gen2people[0][0]
|
userdata, status) = self.gen2people[0][0]
|
||||||
if person:
|
if person:
|
||||||
r, g, b, a = self.background_box(person, 0, userdata)
|
#r, g, b, a = self.background_box(person, 0, userdata)
|
||||||
radiusin_pers,radiusout_pers,radiusin_partner,radiusout_partner = \
|
(radiusin_pers, radiusout_pers, radiusin_partner,
|
||||||
self.get_radiusinout_for_generation_pair(0)
|
radiusout_partner) = self.get_radiusinout_for_gen_pair(0)
|
||||||
if not self.innerring: radiusin_pers = TRANSLATE_PX
|
if not self.innerring:
|
||||||
self.draw_person(cr, person, radiusin_pers, radiusout_pers, math.pi/2, math.pi/2 + 2*math.pi,
|
radiusin_pers = TRANSLATE_PX
|
||||||
|
self.draw_person(ctx, person, radiusin_pers, radiusout_pers,
|
||||||
|
math.pi / 2, math.pi / 2 + 2 * math.pi,
|
||||||
0, False, userdata, is_central_person=True)
|
0, False, userdata, is_central_person=True)
|
||||||
#draw center to move chart
|
#draw center to move chart
|
||||||
cr.set_source_rgb(0, 0, 0) # black
|
ctx.set_source_rgb(0, 0, 0) # black
|
||||||
cr.move_to(TRANSLATE_PX, 0)
|
ctx.move_to(TRANSLATE_PX, 0)
|
||||||
cr.arc(0, 0, TRANSLATE_PX, 0, 2 * math.pi)
|
ctx.arc(0, 0, TRANSLATE_PX, 0, 2 * math.pi)
|
||||||
if self.innerring: # has at least one parent
|
if self.innerring: # has at least one parent
|
||||||
cr.fill()
|
ctx.fill()
|
||||||
self.draw_innerring_people(cr)
|
self.draw_innerring_people(ctx)
|
||||||
else:
|
else:
|
||||||
cr.stroke()
|
ctx.stroke()
|
||||||
#now write all the families and children
|
#now write all the families and children
|
||||||
cr.rotate(self.rotate_value * math.pi/180)
|
ctx.rotate(self.rotate_value * math.pi/180)
|
||||||
for gen in range(self.generations):
|
for gen in range(self.generations):
|
||||||
radiusin_pers,radiusout_pers,radiusin_partner,radiusout_partner = \
|
(radiusin_pers, radiusout_pers, radiusin_partner,
|
||||||
self.get_radiusinout_for_generation_pair(gen)
|
radiusout_partner) = self.get_radiusinout_for_gen_pair(gen)
|
||||||
if gen > 0:
|
if gen > 0:
|
||||||
for pdata in self.gen2people[gen]:
|
for pdata in self.gen2people[gen]:
|
||||||
# person, duplicate or not, start angle, slice size,
|
# person, duplicate or not, start angle, slice size,
|
||||||
# parent pos in fam, nrfam, userdata, status
|
# parent pos in fam, nrfam, userdata, status
|
||||||
pers, dup, start, slice, pospar, nrfam, userdata, status = \
|
(pers, dup, start, portion, dummy_pospar, dummy_nrfam,
|
||||||
pdata
|
userdata, status) = pdata
|
||||||
if status != COLLAPSED:
|
if status != COLLAPSED:
|
||||||
self.draw_person(cr, pers, radiusin_pers, radiusout_pers,
|
self.draw_person(ctx, pers, radiusin_pers,
|
||||||
start, start + slice, gen, dup, userdata,
|
radiusout_pers, start, start + portion,
|
||||||
|
gen, dup, userdata,
|
||||||
thick=status != NORMAL)
|
thick=status != NORMAL)
|
||||||
#if gen < self.generations-1:
|
#if gen < self.generations-1:
|
||||||
for famdata in self.gen2fam[gen]:
|
for famdata in self.gen2fam[gen]:
|
||||||
# family, duplicate or not, start angle, slice size,
|
# family, duplicate or not, start angle, slice size,
|
||||||
# spouse pos in gen, nrchildren, userdata, status
|
# spouse pos in gen, nrchildren, userdata, status
|
||||||
fam, dup, start, slice, posfam, nrchild, userdata,\
|
(fam, dup, start, portion, dummy_posfam, dummy_nrchild,
|
||||||
partner, status = famdata
|
userdata, partner, status) = famdata
|
||||||
if status != COLLAPSED:
|
if status != COLLAPSED:
|
||||||
more_pers_flag = (gen == self.generations - 1
|
more_pers_flag = (gen == self.generations - 1
|
||||||
and len(fam.get_child_ref_list()) > 0)
|
and fam.get_child_ref_list())
|
||||||
self.draw_person(cr, partner, radiusin_partner, radiusout_partner, start, start + slice,
|
self.draw_person(ctx, partner, radiusin_partner,
|
||||||
gen, dup, userdata, thick = (status != NORMAL), has_moregen_indicator = more_pers_flag )
|
radiusout_partner, start, start + portion,
|
||||||
cr.restore()
|
gen, dup, userdata,
|
||||||
|
thick=(status != NORMAL),
|
||||||
|
has_moregen_indicator=more_pers_flag)
|
||||||
|
ctx.restore()
|
||||||
|
|
||||||
if self.background in [BACKGROUND_GRAD_AGE, BACKGROUND_GRAD_PERIOD]:
|
if self.background in [BACKGROUND_GRAD_AGE, BACKGROUND_GRAD_PERIOD]:
|
||||||
self.draw_gradient_legend(cr, halfdist)
|
self.draw_gradient_legend(ctx, halfdist)
|
||||||
|
|
||||||
def cell_address_under_cursor(self, curx, cury):
|
def cell_address_under_cursor(self, curx, cury):
|
||||||
"""
|
"""
|
||||||
@@ -497,7 +527,8 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
position x and y.
|
position x and y.
|
||||||
None if outside of diagram
|
None if outside of diagram
|
||||||
"""
|
"""
|
||||||
radius, rads, raw_rads = self.cursor_to_polar(curx, cury, get_raw_rads=True)
|
radius, rads, raw_rads = self.cursor_to_polar(curx, cury,
|
||||||
|
get_raw_rads=True)
|
||||||
|
|
||||||
btype = TYPE_BOX_NORMAL
|
btype = TYPE_BOX_NORMAL
|
||||||
if radius < TRANSLATE_PX:
|
if radius < TRANSLATE_PX:
|
||||||
@@ -510,8 +541,8 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
else:
|
else:
|
||||||
generation = None
|
generation = None
|
||||||
for gen in range(self.generations):
|
for gen in range(self.generations):
|
||||||
radiusin_pers,radiusout_pers,radiusin_partner,radiusout_partner \
|
(radiusin_pers, radiusout_pers, radiusin_partner,
|
||||||
= self.get_radiusinout_for_generation_pair(gen)
|
radiusout_partner) = self.get_radiusinout_for_gen_pair(gen)
|
||||||
if radiusin_pers <= radius <= radiusout_pers:
|
if radiusin_pers <= radius <= radiusout_pers:
|
||||||
generation, btype = gen, TYPE_BOX_NORMAL
|
generation, btype = gen, TYPE_BOX_NORMAL
|
||||||
break
|
break
|
||||||
@@ -521,24 +552,27 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
|
|
||||||
# find what person is in this position:
|
# find what person is in this position:
|
||||||
selected = None
|
selected = None
|
||||||
if not (generation is None) and 0 <= generation:
|
if not (generation is None) and generation > 0:
|
||||||
selected = self.personpos_at_angle(generation, rads, btype)
|
selected = self.personpos_at_angle(generation, rads, btype)
|
||||||
elif generation == -2:
|
elif generation == -2:
|
||||||
for p in range(len(self.angle[generation])):
|
for idx in range(len(self.angle[generation])):
|
||||||
start, stop, state = self.angle[generation][p]
|
start, stop, dummy_state = self.angle[generation][idx]
|
||||||
if self.radian_in_bounds(start, raw_rads, stop):
|
if self.radian_in_bounds(start, raw_rads, stop):
|
||||||
selected = p
|
selected = idx
|
||||||
break
|
break
|
||||||
if (generation is None or selected is None):
|
if (generation is None or selected is None):
|
||||||
return None
|
return None
|
||||||
return generation, selected, btype
|
return generation, selected, btype
|
||||||
|
|
||||||
def draw_innerring_people(self, cr):
|
def draw_innerring_people(self, ctx):
|
||||||
cr.move_to(TRANSLATE_PX + CHILDRING_WIDTH, 0)
|
"""
|
||||||
cr.set_source_rgb(0, 0, 0) # black
|
Draw the innerring person
|
||||||
cr.set_line_width(1)
|
"""
|
||||||
cr.arc(0, 0, TRANSLATE_PX + CHILDRING_WIDTH, 0, 2 * math.pi)
|
ctx.move_to(TRANSLATE_PX + CHILDRING_WIDTH, 0)
|
||||||
cr.stroke()
|
ctx.set_source_rgb(0, 0, 0) # black
|
||||||
|
ctx.set_line_width(1)
|
||||||
|
ctx.arc(0, 0, TRANSLATE_PX + CHILDRING_WIDTH, 0, 2 * math.pi)
|
||||||
|
ctx.stroke()
|
||||||
nrparent = len(self.innerring)
|
nrparent = len(self.innerring)
|
||||||
#Y axis is downward. positve angles are hence clockwise
|
#Y axis is downward. positve angles are hence clockwise
|
||||||
startangle = math.pi
|
startangle = math.pi
|
||||||
@@ -549,7 +583,7 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
else:
|
else:
|
||||||
angleinc = 2 * math.pi / nrparent
|
angleinc = 2 * math.pi / nrparent
|
||||||
for data in self.innerring:
|
for data in self.innerring:
|
||||||
self.draw_innerring(cr, data[0], data[1], startangle, angleinc)
|
self.draw_innerring(ctx, data[0], data[1], startangle, angleinc)
|
||||||
startangle += angleinc
|
startangle += angleinc
|
||||||
|
|
||||||
def personpos_at_angle(self, generation, rads, btype):
|
def personpos_at_angle(self, generation, rads, btype):
|
||||||
@@ -566,12 +600,12 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
datas = self.gen2fam[generation]
|
datas = self.gen2fam[generation]
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
for p, pdata in enumerate(datas):
|
for idx, pdata in enumerate(datas):
|
||||||
# person, duplicate or not, start angle, slice size,
|
# person, duplicate or not, start angle, slice size,
|
||||||
# parent pos in fam, nrfam, userdata, status
|
# parent pos in fam, nrfam, userdata, status
|
||||||
start, stop = pdata[2], pdata[2] + pdata[3]
|
start, stop = pdata[2], pdata[2] + pdata[3]
|
||||||
if self.radian_in_bounds(start, rads, stop):
|
if self.radian_in_bounds(start, rads, stop):
|
||||||
selected = p
|
selected = idx
|
||||||
break
|
break
|
||||||
return selected
|
return selected
|
||||||
|
|
||||||
@@ -581,7 +615,7 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
"""
|
"""
|
||||||
generation, pos, btype = cell_address
|
generation, pos, btype = cell_address
|
||||||
if generation == -2:
|
if generation == -2:
|
||||||
person, userdata = self.innerring[pos]
|
person, dummy_userdata = self.innerring[pos]
|
||||||
elif btype == TYPE_BOX_NORMAL:
|
elif btype == TYPE_BOX_NORMAL:
|
||||||
# person, duplicate or not, start angle, slice size,
|
# person, duplicate or not, start angle, slice size,
|
||||||
# parent pos in fam, nrfam, userdata, status
|
# parent pos in fam, nrfam, userdata, status
|
||||||
@@ -602,7 +636,9 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
return self.gen2fam[generation][pos][0]
|
return self.gen2fam[generation][pos][0]
|
||||||
|
|
||||||
def do_mouse_click(self):
|
def do_mouse_click(self):
|
||||||
# no drag occured, expand or collapse the section
|
"""
|
||||||
|
no drag occured, expand or collapse the section
|
||||||
|
"""
|
||||||
self.toggle_cell_state(self._mouse_click_cell_address)
|
self.toggle_cell_state(self._mouse_click_cell_address)
|
||||||
self._compute_angles(*self.rootangle_rad)
|
self._compute_angles(*self.rootangle_rad)
|
||||||
self._mouse_click = False
|
self._mouse_click = False
|
||||||
@@ -610,6 +646,9 @@ class FanChartDescWidget(FanChartBaseWidget):
|
|||||||
self.queue_draw()
|
self.queue_draw()
|
||||||
|
|
||||||
def toggle_cell_state(self, cell_address):
|
def toggle_cell_state(self, cell_address):
|
||||||
|
"""
|
||||||
|
Toggle the person cell (EXPAND/COLLAPSE)
|
||||||
|
"""
|
||||||
generation, selected, btype = cell_address
|
generation, selected, btype = cell_address
|
||||||
if generation < 1:
|
if generation < 1:
|
||||||
return
|
return
|
||||||
@@ -654,10 +693,12 @@ class FanChartDescGrampsGUI(FanChartGrampsGUI):
|
|||||||
data.
|
data.
|
||||||
"""
|
"""
|
||||||
root_person_handle = self.get_active('Person')
|
root_person_handle = self.get_active('Person')
|
||||||
self.fan.set_values(root_person_handle, self.maxgen, self.flipupsidedownname, self.twolinename, self.background,
|
self.fan.set_values(root_person_handle, self.maxgen,
|
||||||
self.fonttype, self.grad_start, self.grad_end,
|
self.flipupsidedownname, self.twolinename,
|
||||||
self.generic_filter, self.alpha_filter, self.form,
|
self.background, self.fonttype, self.grad_start,
|
||||||
self.angle_algo, self.dupcolor)
|
self.grad_end, self.generic_filter,
|
||||||
|
self.alpha_filter, self.form, self.angle_algo,
|
||||||
|
self.dupcolor, self.showid)
|
||||||
self.fan.reset()
|
self.fan.reset()
|
||||||
self.fan.draw()
|
self.fan.draw()
|
||||||
self.fan.queue_draw()
|
self.fan.queue_draw()
|
||||||
|
@@ -25,16 +25,6 @@
|
|||||||
# Python modules
|
# Python modules
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
import gi
|
|
||||||
gi.require_version('Gtk', '3.0')
|
|
||||||
from gi.repository import Pango
|
|
||||||
from gi.repository import Gtk
|
|
||||||
import math
|
|
||||||
from gi.repository import Gdk
|
|
||||||
try:
|
|
||||||
import cairo
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@@ -42,14 +32,14 @@ except ImportError:
|
|||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
||||||
_ = glocale.translation.gettext
|
|
||||||
from gramps.gen.plug import Gramplet
|
from gramps.gen.plug import Gramplet
|
||||||
from gramps.gen.errors import WindowActiveError
|
from gramps.gui.widgets.fanchart2way import (FanChart2WayWidget,
|
||||||
from gramps.gui.editors import EditPerson
|
FanChart2WayGrampsGUI,
|
||||||
from gramps.gui.widgets.fanchart2way import (FanChart2WayWidget, FanChart2WayGrampsGUI,
|
|
||||||
ANGLE_WEIGHT)
|
ANGLE_WEIGHT)
|
||||||
from gramps.gui.widgets.fanchart import FORM_HALFCIRCLE, BACKGROUND_SCHEME1
|
from gramps.gui.widgets.fanchart import FORM_HALFCIRCLE, BACKGROUND_SCHEME1
|
||||||
|
|
||||||
|
_ = glocale.translation.gettext
|
||||||
|
|
||||||
class FanChart2WayGramplet(FanChart2WayGrampsGUI, Gramplet):
|
class FanChart2WayGramplet(FanChart2WayGrampsGUI, Gramplet):
|
||||||
"""
|
"""
|
||||||
The Gramplet code that realizes the FanChartWidget.
|
The Gramplet code that realizes the FanChartWidget.
|
||||||
@@ -71,11 +61,13 @@ class FanChart2WayGramplet(FanChart2WayGrampsGUI, Gramplet):
|
|||||||
self.angle_algo = ANGLE_WEIGHT
|
self.angle_algo = ANGLE_WEIGHT
|
||||||
self.flipupsidedownname = True
|
self.flipupsidedownname = True
|
||||||
self.twolinename = True
|
self.twolinename = True
|
||||||
|
self.showid = False
|
||||||
self.childring = False
|
self.childring = False
|
||||||
self.background_gradient = True
|
self.background_gradient = True
|
||||||
#self.filter = filter
|
#self.filter = filter
|
||||||
|
|
||||||
self.set_fan(FanChart2WayWidget(self.dbstate, self.uistate, self.on_popup))
|
self.set_fan(FanChart2WayWidget(self.dbstate, self.uistate,
|
||||||
|
self.on_popup))
|
||||||
# Replace the standard textview with the fan chart widget:
|
# Replace the standard textview with the fan chart widget:
|
||||||
self.gui.get_container_widget().remove(self.gui.textview)
|
self.gui.get_container_widget().remove(self.gui.textview)
|
||||||
self.gui.get_container_widget().add_with_viewport(self.fan)
|
self.gui.get_container_widget().add_with_viewport(self.fan)
|
||||||
@@ -83,7 +75,9 @@ class FanChart2WayGramplet(FanChart2WayGrampsGUI, Gramplet):
|
|||||||
self.fan.show()
|
self.fan.show()
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
self.set_tooltip(_("Click to expand/contract person\nRight-click for options\nClick and drag in open area to rotate"))
|
self.set_tooltip(_("Click to expand/contract person\n"
|
||||||
|
"Right-click for options\n"
|
||||||
|
"Click and drag in open area to rotate"))
|
||||||
|
|
||||||
def active_changed(self, handle):
|
def active_changed(self, handle):
|
||||||
"""
|
"""
|
||||||
@@ -95,5 +89,6 @@ class FanChart2WayGramplet(FanChart2WayGrampsGUI, Gramplet):
|
|||||||
def on_childmenu_changed(self, obj, person_handle):
|
def on_childmenu_changed(self, obj, person_handle):
|
||||||
"""Callback for the pulldown menu selection, changing to the person
|
"""Callback for the pulldown menu selection, changing to the person
|
||||||
attached with menu item."""
|
attached with menu item."""
|
||||||
|
dummy_obj = obj
|
||||||
self.set_active('Person', person_handle)
|
self.set_active('Person', person_handle)
|
||||||
return True
|
return True
|
||||||
|
@@ -52,6 +52,7 @@ class FanChartDescGramplet(FanChartDescGrampsGUI, Gramplet):
|
|||||||
self.angle_algo = ANGLE_WEIGHT
|
self.angle_algo = ANGLE_WEIGHT
|
||||||
self.flipupsidedownname = True
|
self.flipupsidedownname = True
|
||||||
self.twolinename = True
|
self.twolinename = True
|
||||||
|
self.showid = False
|
||||||
self.set_fan(FanChartDescWidget(self.dbstate, self.uistate,
|
self.set_fan(FanChartDescWidget(self.dbstate, self.uistate,
|
||||||
self.on_popup))
|
self.on_popup))
|
||||||
# Replace the standard textview with the fan chart widget:
|
# Replace the standard textview with the fan chart widget:
|
||||||
@@ -75,5 +76,6 @@ class FanChartDescGramplet(FanChartDescGrampsGUI, Gramplet):
|
|||||||
def on_childmenu_changed(self, obj, person_handle):
|
def on_childmenu_changed(self, obj, person_handle):
|
||||||
"""Callback for the pulldown menu selection, changing to the person
|
"""Callback for the pulldown menu selection, changing to the person
|
||||||
attached with menu item."""
|
attached with menu item."""
|
||||||
|
dummy_obj = obj
|
||||||
self.set_active('Person', person_handle)
|
self.set_active('Person', person_handle)
|
||||||
return True
|
return True
|
||||||
|
@@ -56,6 +56,7 @@ class FanChartGramplet(FanChartGrampsGUI, Gramplet):
|
|||||||
self.generic_filter = None
|
self.generic_filter = None
|
||||||
self.alpha_filter = 0.2
|
self.alpha_filter = 0.2
|
||||||
self.form = FORM_HALFCIRCLE
|
self.form = FORM_HALFCIRCLE
|
||||||
|
self.showid = False
|
||||||
self.set_fan(FanChartWidget(self.dbstate, self.uistate, self.on_popup))
|
self.set_fan(FanChartWidget(self.dbstate, self.uistate, self.on_popup))
|
||||||
# Replace the standard textview with the fan chart widget:
|
# Replace the standard textview with the fan chart widget:
|
||||||
self.gui.get_container_widget().remove(self.gui.textview)
|
self.gui.get_container_widget().remove(self.gui.textview)
|
||||||
@@ -77,5 +78,6 @@ class FanChartGramplet(FanChartGrampsGUI, Gramplet):
|
|||||||
def on_childmenu_changed(self, obj, person_handle):
|
def on_childmenu_changed(self, obj, person_handle):
|
||||||
"""Callback for the pulldown menu selection, changing to the person
|
"""Callback for the pulldown menu selection, changing to the person
|
||||||
attached with menu item."""
|
attached with menu item."""
|
||||||
|
dummy_obj = obj
|
||||||
self.set_active('Person', person_handle)
|
self.set_active('Person', person_handle)
|
||||||
return True
|
return True
|
||||||
|
@@ -31,11 +31,9 @@
|
|||||||
# Python modules
|
# Python modules
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
from gi.repository import Gdk
|
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
import cairo
|
import cairo
|
||||||
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
||||||
_ = glocale.translation.gettext
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@@ -51,6 +49,7 @@ from gramps.plugins.view.fanchartview import FanChartView
|
|||||||
|
|
||||||
# the print settings to remember between print sessions
|
# the print settings to remember between print sessions
|
||||||
PRINT_SETTINGS = None
|
PRINT_SETTINGS = None
|
||||||
|
_ = glocale.translation.gettext
|
||||||
|
|
||||||
class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
|
class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
|
||||||
"""
|
"""
|
||||||
@@ -67,6 +66,7 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
|
|||||||
('interface.fanview-flipupsidedownname', True),
|
('interface.fanview-flipupsidedownname', True),
|
||||||
('interface.fanview-font', 'Sans'),
|
('interface.fanview-font', 'Sans'),
|
||||||
('interface.fanview-form', fanchart.FORM_CIRCLE),
|
('interface.fanview-form', fanchart.FORM_CIRCLE),
|
||||||
|
('interface.fanview-showid', False),
|
||||||
('interface.color-start-grad', '#ef2929'),
|
('interface.color-start-grad', '#ef2929'),
|
||||||
('interface.color-end-grad', '#3d37e9'),
|
('interface.color-end-grad', '#3d37e9'),
|
||||||
('interface.angle-algorithm', fanchart2way.ANGLE_WEIGHT),
|
('interface.angle-algorithm', fanchart2way.ANGLE_WEIGHT),
|
||||||
@@ -78,26 +78,29 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
|
|||||||
|
|
||||||
NavigationView.__init__(self, _('2-Way Fan Chart'),
|
NavigationView.__init__(self, _('2-Way Fan Chart'),
|
||||||
pdata, dbstate, uistate,
|
pdata, dbstate, uistate,
|
||||||
PersonBookmarks,
|
PersonBookmarks, nav_group)
|
||||||
nav_group)
|
fanchart2way.FanChart2WayGrampsGUI.__init__(self,
|
||||||
fanchart2way.FanChart2WayGrampsGUI.__init__(self, self.on_childmenu_changed)
|
self.on_childmenu_changed)
|
||||||
#set needed values
|
#set needed values
|
||||||
self.generations_asc = self._config.get('interface.fanview-maxgen-asc')
|
scg = self._config.get
|
||||||
self.generations_desc = self._config.get('interface.fanview-maxgen-desc')
|
self.generations_asc = scg('interface.fanview-maxgen-asc')
|
||||||
self.background = self._config.get('interface.fanview-background')
|
self.generations_desc = scg('interface.fanview-maxgen-desc')
|
||||||
self.background_gradient = self._config.get('interface.fanview-background-gradient')
|
self.background = scg('interface.fanview-background')
|
||||||
self.radialtext = self._config.get('interface.fanview-radialtext')
|
self.background_gradient = scg('interface.fanview-background-gradient')
|
||||||
self.twolinename = self._config.get('interface.fanview-twolinename')
|
self.radialtext = scg('interface.fanview-radialtext')
|
||||||
self.flipupsidedownname = self._config.get('interface.fanview-flipupsidedownname')
|
self.twolinename = scg('interface.fanview-twolinename')
|
||||||
self.fonttype = self._config.get('interface.fanview-font')
|
self.flipupsidedownname = scg('interface.fanview-flipupsidedownname')
|
||||||
|
self.fonttype = scg('interface.fanview-font')
|
||||||
|
|
||||||
self.grad_start = self._config.get('interface.color-start-grad')
|
self.grad_start = scg('interface.color-start-grad')
|
||||||
self.grad_end = self._config.get('interface.color-end-grad')
|
self.grad_end = scg('interface.color-end-grad')
|
||||||
self.form = fanchart.FORM_CIRCLE
|
self.form = fanchart.FORM_CIRCLE
|
||||||
self.angle_algo = self._config.get('interface.angle-algorithm')
|
self.showid = scg('interface.fanview-showid')
|
||||||
self.dupcolor = self._config.get('interface.duplicate-color')
|
self.angle_algo = scg('interface.angle-algorithm')
|
||||||
|
self.dupcolor = scg('interface.duplicate-color')
|
||||||
self.generic_filter = None
|
self.generic_filter = None
|
||||||
self.alpha_filter = 0.2
|
self.alpha_filter = 0.2
|
||||||
|
self.scrolledwindow = None
|
||||||
|
|
||||||
dbstate.connect('active-changed', self.active_changed)
|
dbstate.connect('active-changed', self.active_changed)
|
||||||
dbstate.connect('database-changed', self.change_db)
|
dbstate.connect('database-changed', self.change_db)
|
||||||
@@ -174,6 +177,7 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
|
|||||||
"""
|
"""
|
||||||
Method called when active person changes.
|
Method called when active person changes.
|
||||||
"""
|
"""
|
||||||
|
dummy_handle = handle
|
||||||
# Reset everything but rotation angle (leave it as is)
|
# Reset everything but rotation angle (leave it as is)
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
@@ -191,28 +195,43 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
|
|||||||
self._add_db_signal('family-rebuild', self.person_rebuild)
|
self._add_db_signal('family-rebuild', self.person_rebuild)
|
||||||
|
|
||||||
def change_db(self, db):
|
def change_db(self, db):
|
||||||
|
"""
|
||||||
|
We selected a new database
|
||||||
|
"""
|
||||||
self._change_db(db)
|
self._change_db(db)
|
||||||
if self.active:
|
if self.active:
|
||||||
self.bookmarks.redraw()
|
self.bookmarks.redraw()
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
|
"""
|
||||||
|
Redraw the fan chart
|
||||||
|
"""
|
||||||
self.main()
|
self.main()
|
||||||
|
|
||||||
def goto_handle(self, handle):
|
def goto_handle(self, handle):
|
||||||
|
"""
|
||||||
|
Draw the fan chart for the active person
|
||||||
|
"""
|
||||||
self.change_active(handle)
|
self.change_active(handle)
|
||||||
self.main()
|
self.main()
|
||||||
|
|
||||||
def get_active(self, object):
|
def get_active(self, obj):
|
||||||
"""overrule get_active, to support call as in Gramplets
|
"""overrule get_active, to support call as in Gramplets
|
||||||
"""
|
"""
|
||||||
|
dummy_obj = obj
|
||||||
return NavigationView.get_active(self)
|
return NavigationView.get_active(self)
|
||||||
|
|
||||||
def person_rebuild(self, *args):
|
def person_rebuild(self, *args):
|
||||||
|
"""
|
||||||
|
Redraw the fan chart for the person
|
||||||
|
"""
|
||||||
|
dummy_args = args
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def person_rebuild_bm(self, *args):
|
def person_rebuild_bm(self, *args):
|
||||||
"""Large change to person database"""
|
"""Large change to person database"""
|
||||||
|
dummy_args = args
|
||||||
self.person_rebuild()
|
self.person_rebuild()
|
||||||
if self.active:
|
if self.active:
|
||||||
self.bookmarks.redraw()
|
self.bookmarks.redraw()
|
||||||
@@ -221,6 +240,7 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
|
|||||||
"""
|
"""
|
||||||
Print or save the view that is currently shown
|
Print or save the view that is currently shown
|
||||||
"""
|
"""
|
||||||
|
dummy_obj = obj
|
||||||
widthpx = 2 * self.fan.halfdist()
|
widthpx = 2 * self.fan.halfdist()
|
||||||
heightpx = widthpx
|
heightpx = widthpx
|
||||||
|
|
||||||
@@ -231,6 +251,7 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
|
|||||||
def on_childmenu_changed(self, obj, person_handle):
|
def on_childmenu_changed(self, obj, person_handle):
|
||||||
"""Callback for the pulldown menu selection, changing to the person
|
"""Callback for the pulldown menu selection, changing to the person
|
||||||
attached with menu item."""
|
attached with menu item."""
|
||||||
|
dummy_obj = obj
|
||||||
self.change_active(person_handle)
|
self.change_active(person_handle)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -254,7 +275,6 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
|
|||||||
"""
|
"""
|
||||||
Function that builds the widget in the configuration dialog
|
Function that builds the widget in the configuration dialog
|
||||||
"""
|
"""
|
||||||
nrentry = 9
|
|
||||||
grid = Gtk.Grid()
|
grid = Gtk.Grid()
|
||||||
grid.set_border_width(12)
|
grid.set_border_width(12)
|
||||||
grid.set_column_spacing(6)
|
grid.set_column_spacing(6)
|
||||||
@@ -266,16 +286,15 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
|
|||||||
configdialog.add_spinner(grid, _("Max descendant generations"), 1,
|
configdialog.add_spinner(grid, _("Max descendant generations"), 1,
|
||||||
'interface.fanview-maxgen-desc', (1, 11),
|
'interface.fanview-maxgen-desc', (1, 11),
|
||||||
callback=self.cb_update_maxgen)
|
callback=self.cb_update_maxgen)
|
||||||
configdialog.add_combo(grid,
|
configdialog.add_combo(grid, _('Text Font'), 2,
|
||||||
_('Text Font'),
|
'interface.fanview-font',
|
||||||
2, 'interface.fanview-font',
|
self.allfonts, callback=self.cb_update_font,
|
||||||
self.allfonts, callback=self.cb_update_font, valueactive=True)
|
valueactive=True)
|
||||||
backgrvals = (
|
backgrvals = (
|
||||||
(fanchart.BACKGROUND_GENDER, _('Gender colors')),
|
(fanchart.BACKGROUND_GENDER, _('Gender colors')),
|
||||||
(fanchart.BACKGROUND_GRAD_GEN, _('Generation based gradient')),
|
(fanchart.BACKGROUND_GRAD_GEN, _('Generation based gradient')),
|
||||||
(fanchart.BACKGROUND_GRAD_AGE, _('Age (0-100) based gradient')),
|
(fanchart.BACKGROUND_GRAD_AGE, _('Age (0-100) based gradient')),
|
||||||
(fanchart.BACKGROUND_SINGLE_COLOR,
|
(fanchart.BACKGROUND_SINGLE_COLOR, _('Single main (filter) color')),
|
||||||
_('Single main (filter) color')),
|
|
||||||
(fanchart.BACKGROUND_GRAD_PERIOD, _('Time period based gradient')),
|
(fanchart.BACKGROUND_GRAD_PERIOD, _('Time period based gradient')),
|
||||||
(fanchart.BACKGROUND_WHITE, _('White')),
|
(fanchart.BACKGROUND_WHITE, _('White')),
|
||||||
(fanchart.BACKGROUND_SCHEME1, _('Color scheme classic report')),
|
(fanchart.BACKGROUND_SCHEME1, _('Color scheme classic report')),
|
||||||
@@ -283,17 +302,14 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
|
|||||||
)
|
)
|
||||||
curval = self._config.get('interface.fanview-background')
|
curval = self._config.get('interface.fanview-background')
|
||||||
nrval = 0
|
nrval = 0
|
||||||
for nr, val in backgrvals:
|
for nbr, dummy_val in backgrvals:
|
||||||
if curval == nr:
|
if curval == nbr:
|
||||||
break
|
break
|
||||||
nrval += 1
|
nrval += 1
|
||||||
configdialog.add_combo(grid,
|
configdialog.add_combo(grid, _('Background'), 3,
|
||||||
_('Background'),
|
'interface.fanview-background', backgrvals,
|
||||||
3, 'interface.fanview-background',
|
callback=self.cb_update_background,
|
||||||
backgrvals,
|
valueactive=False, setactive=nrval)
|
||||||
callback=self.cb_update_background, valueactive=False,
|
|
||||||
setactive=nrval
|
|
||||||
)
|
|
||||||
|
|
||||||
# show names one two line
|
# show names one two line
|
||||||
configdialog.add_checkbox(grid,
|
configdialog.add_checkbox(grid,
|
||||||
@@ -313,20 +329,23 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
|
|||||||
((fanchart2way.ANGLE_CHEQUI,
|
((fanchart2way.ANGLE_CHEQUI,
|
||||||
_('Homogeneous children distribution')),
|
_('Homogeneous children distribution')),
|
||||||
(fanchart2way.ANGLE_WEIGHT,
|
(fanchart2way.ANGLE_WEIGHT,
|
||||||
_('Size proportional to number of descendants')),
|
_('Size proportional to number'
|
||||||
|
' of descendants')),
|
||||||
),
|
),
|
||||||
callback=self.cb_update_anglealgo)
|
callback=self.cb_update_anglealgo)
|
||||||
|
|
||||||
# show names one two line
|
# show names one two line
|
||||||
configdialog.add_checkbox(grid,
|
configdialog.add_checkbox(grid, _('Show names on two lines'),
|
||||||
_('Show names on two lines'),
|
|
||||||
9, 'interface.fanview-twolinename')
|
9, 'interface.fanview-twolinename')
|
||||||
|
|
||||||
# Flip names
|
# Flip names
|
||||||
configdialog.add_checkbox(grid,
|
configdialog.add_checkbox(grid, _('Flip name on the left of the fan'),
|
||||||
_('Flip name on the left of the fan'),
|
|
||||||
10, 'interface.fanview-flipupsidedownname')
|
10, 'interface.fanview-flipupsidedownname')
|
||||||
|
|
||||||
|
# Show gramps id
|
||||||
|
configdialog.add_checkbox(grid, _('Show the gramps id'),
|
||||||
|
11, 'interface.fanview-showid')
|
||||||
|
|
||||||
return _('Layout'), grid
|
return _('Layout'), grid
|
||||||
|
|
||||||
def config_connect(self):
|
def config_connect(self):
|
||||||
@@ -347,11 +366,17 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
|
|||||||
self.cb_update_twolinename)
|
self.cb_update_twolinename)
|
||||||
self._config.connect('interface.fanview-background-gradient',
|
self._config.connect('interface.fanview-background-gradient',
|
||||||
self.cb_update_background_gradient)
|
self.cb_update_background_gradient)
|
||||||
|
self._config.connect('interface.fanview-showid',
|
||||||
|
self.cb_update_showid)
|
||||||
|
|
||||||
def cb_update_maxgen(self, spinbtn, constant):
|
def cb_update_maxgen(self, spinbtn, constant):
|
||||||
|
"""
|
||||||
|
The maximum generations in the fanchart
|
||||||
|
"""
|
||||||
self._config.set(constant, spinbtn.get_value_as_int())
|
self._config.set(constant, spinbtn.get_value_as_int())
|
||||||
self.generations_asc = int(self._config.get('interface.fanview-maxgen-asc'))
|
scg = self._config.get
|
||||||
self.generations_desc = int(self._config.get('interface.fanview-maxgen-desc'))
|
self.generations_asc = int(scg('interface.fanview-maxgen-asc'))
|
||||||
|
self.generations_desc = int(scg('interface.fanview-maxgen-desc'))
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def cb_update_twolinename(self, client, cnxn_id, entry, data):
|
def cb_update_twolinename(self, client, cnxn_id, entry, data):
|
||||||
@@ -361,7 +386,17 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
|
|||||||
self.twolinename = (entry == 'True')
|
self.twolinename = (entry == 'True')
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
def cb_update_showid(self, client, cnxn_id, entry, data):
|
||||||
|
"""
|
||||||
|
Called when the configuration menu changes the showid setting.
|
||||||
|
"""
|
||||||
|
self.showid = (entry == 'True')
|
||||||
|
self.update()
|
||||||
|
|
||||||
def cb_update_background(self, obj, constant):
|
def cb_update_background(self, obj, constant):
|
||||||
|
"""
|
||||||
|
The background selected
|
||||||
|
"""
|
||||||
entry = obj.get_active()
|
entry = obj.get_active()
|
||||||
Gtk.TreePath.new_from_string('%d' % entry)
|
Gtk.TreePath.new_from_string('%d' % entry)
|
||||||
val = int(obj.get_model().get_value(
|
val = int(obj.get_model().get_value(
|
||||||
@@ -378,12 +413,18 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
|
|||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def cb_update_form(self, obj, constant):
|
def cb_update_form(self, obj, constant):
|
||||||
|
"""
|
||||||
|
Update the fanchart form: CIRCLE, HALFCIRCLE or QUADRANT
|
||||||
|
"""
|
||||||
entry = obj.get_active()
|
entry = obj.get_active()
|
||||||
self._config.set(constant, entry)
|
self._config.set(constant, entry)
|
||||||
self.form = entry
|
self.form = entry
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def cb_update_anglealgo(self, obj, constant):
|
def cb_update_anglealgo(self, obj, constant):
|
||||||
|
"""
|
||||||
|
Update the angle algorythm : homogeneous children distribution or not
|
||||||
|
"""
|
||||||
entry = obj.get_active()
|
entry = obj.get_active()
|
||||||
self._config.set(constant, entry)
|
self._config.set(constant, entry)
|
||||||
self.angle_algo = entry
|
self.angle_algo = entry
|
||||||
@@ -400,12 +441,16 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
|
|||||||
|
|
||||||
def cb_update_flipupsidedownname(self, client, cnxn_id, entry, data):
|
def cb_update_flipupsidedownname(self, client, cnxn_id, entry, data):
|
||||||
"""
|
"""
|
||||||
Called when the configuration menu changes the flipupsidedownname setting.
|
Called when the configuration menu changes the
|
||||||
|
flipupsidedownname setting.
|
||||||
"""
|
"""
|
||||||
self.flipupsidedownname = (entry == 'True')
|
self.flipupsidedownname = (entry == 'True')
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def cb_update_font(self, obj, constant):
|
def cb_update_font(self, obj, constant):
|
||||||
|
"""
|
||||||
|
Update the choosed font
|
||||||
|
"""
|
||||||
entry = obj.get_active()
|
entry = obj.get_active()
|
||||||
self._config.set(constant, self.allfonts[entry][1])
|
self._config.set(constant, self.allfonts[entry][1])
|
||||||
self.fonttype = self.allfonts[entry][1]
|
self.fonttype = self.allfonts[entry][1]
|
||||||
@@ -440,6 +485,8 @@ class CairoPrintSave():
|
|||||||
self.heightpx = heightpx
|
self.heightpx = heightpx
|
||||||
self.drawfunc = drawfunc
|
self.drawfunc = drawfunc
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
self.preview = None
|
||||||
|
self.previewopr = None
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Create the physical output from the meta document.
|
"""Create the physical output from the meta document.
|
||||||
@@ -473,7 +520,8 @@ class CairoPrintSave():
|
|||||||
# run print dialog
|
# run print dialog
|
||||||
while True:
|
while True:
|
||||||
self.preview = None
|
self.preview = None
|
||||||
res = operation.run(Gtk.PrintOperationAction.PRINT_DIALOG, self.parent)
|
res = operation.run(Gtk.PrintOperationAction.PRINT_DIALOG,
|
||||||
|
self.parent)
|
||||||
if self.preview is None: # cancel or print
|
if self.preview is None: # cancel or print
|
||||||
break
|
break
|
||||||
# set up printing again; can't reuse PrintOperation?
|
# set up printing again; can't reuse PrintOperation?
|
||||||
@@ -493,20 +541,24 @@ class CairoPrintSave():
|
|||||||
def on_draw_page(self, operation, context, page_nr):
|
def on_draw_page(self, operation, context, page_nr):
|
||||||
"""Draw a page on a Cairo context.
|
"""Draw a page on a Cairo context.
|
||||||
"""
|
"""
|
||||||
cr = context.get_cairo_context()
|
dummy_operation = operation
|
||||||
|
dummy_page_nr = page_nr
|
||||||
|
ctx = context.get_cairo_context()
|
||||||
pxwidth = round(context.get_width())
|
pxwidth = round(context.get_width())
|
||||||
pxheight = round(context.get_height())
|
pxheight = round(context.get_height())
|
||||||
scale = min(pxwidth/self.widthpx, pxheight/self.heightpx)
|
scale = min(pxwidth/self.widthpx, pxheight/self.heightpx)
|
||||||
self.drawfunc(None, cr, scale=scale)
|
self.drawfunc(None, ctx, scale=scale)
|
||||||
|
|
||||||
def on_paginate(self, operation, context):
|
def on_paginate(self, operation, context):
|
||||||
"""Paginate the whole document in chunks.
|
"""Paginate the whole document in chunks.
|
||||||
We don't need this as there is only one page, however,
|
We don't need this as there is only one page, however,
|
||||||
we provide a dummy holder here, because on_preview crashes if no
|
we provide a dummy holder here, because on_preview crashes if no
|
||||||
default application is set with gir 3.3.2 (typically evince not installed)!
|
default application is set with gir 3.3.2
|
||||||
|
(typically evince not installed)!
|
||||||
It will provide the start of the preview dialog, which cannot be
|
It will provide the start of the preview dialog, which cannot be
|
||||||
started in on_preview
|
started in on_preview
|
||||||
"""
|
"""
|
||||||
|
dummy_context = context
|
||||||
finished = True
|
finished = True
|
||||||
# update page number
|
# update page number
|
||||||
operation.set_n_pages(1)
|
operation.set_n_pages(1)
|
||||||
@@ -520,8 +572,10 @@ class CairoPrintSave():
|
|||||||
def on_preview(self, operation, preview, context, parent):
|
def on_preview(self, operation, preview, context, parent):
|
||||||
"""Implement custom print preview functionality.
|
"""Implement custom print preview functionality.
|
||||||
We provide a dummy holder here, because on_preview crashes if no
|
We provide a dummy holder here, because on_preview crashes if no
|
||||||
default application is set with gir 3.3.2 (typically evince not installed)!
|
default application is set with gir 3.3.2
|
||||||
|
(typically evince not installed)!
|
||||||
"""
|
"""
|
||||||
|
dummy_preview = preview
|
||||||
dlg = Gtk.MessageDialog(parent,
|
dlg = Gtk.MessageDialog(parent,
|
||||||
flags=Gtk.DialogFlags.MODAL,
|
flags=Gtk.DialogFlags.MODAL,
|
||||||
type=Gtk.MessageType.WARNING,
|
type=Gtk.MessageType.WARNING,
|
||||||
@@ -543,11 +597,16 @@ class CairoPrintSave():
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
height = 0
|
height = 0
|
||||||
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
|
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
|
||||||
cr = cairo.Context(surface)
|
ctx = cairo.Context(surface)
|
||||||
context.set_cairo_context(cr, 72.0, 72.0)
|
context.set_cairo_context(ctx, 72.0, 72.0)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def previewdestroy(self, dlg, res):
|
def previewdestroy(self, dlg, res):
|
||||||
|
"""
|
||||||
|
Destroy the preview page
|
||||||
|
"""
|
||||||
|
dummy_dlg = dlg
|
||||||
|
dummy_res = res
|
||||||
self.preview.destroy()
|
self.preview.destroy()
|
||||||
self.previewopr.end_preview()
|
self.previewopr.end_preview()
|
||||||
|
@@ -30,11 +30,9 @@
|
|||||||
# Python modules
|
# Python modules
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
from gi.repository import Gdk
|
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
import cairo
|
import cairo
|
||||||
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
||||||
_ = glocale.translation.gettext
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@@ -50,6 +48,7 @@ from gramps.plugins.view.fanchartview import FanChartView
|
|||||||
|
|
||||||
# the print settings to remember between print sessions
|
# the print settings to remember between print sessions
|
||||||
PRINT_SETTINGS = None
|
PRINT_SETTINGS = None
|
||||||
|
_ = glocale.translation.gettext
|
||||||
|
|
||||||
class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
|
class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
|
||||||
"""
|
"""
|
||||||
@@ -67,7 +66,8 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
|
|||||||
('interface.color-start-grad', '#ef2929'),
|
('interface.color-start-grad', '#ef2929'),
|
||||||
('interface.color-end-grad', '#3d37e9'),
|
('interface.color-end-grad', '#3d37e9'),
|
||||||
('interface.angle-algorithm', fanchartdesc.ANGLE_WEIGHT),
|
('interface.angle-algorithm', fanchartdesc.ANGLE_WEIGHT),
|
||||||
('interface.duplicate-color', '#888a85')
|
('interface.duplicate-color', '#888a85'),
|
||||||
|
('interface.fanview-showid', False)
|
||||||
)
|
)
|
||||||
def __init__(self, pdata, dbstate, uistate, nav_group=0):
|
def __init__(self, pdata, dbstate, uistate, nav_group=0):
|
||||||
self.dbstate = dbstate
|
self.dbstate = dbstate
|
||||||
@@ -75,24 +75,27 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
|
|||||||
|
|
||||||
NavigationView.__init__(self, _('Descendant Fan Chart'),
|
NavigationView.__init__(self, _('Descendant Fan Chart'),
|
||||||
pdata, dbstate, uistate,
|
pdata, dbstate, uistate,
|
||||||
PersonBookmarks,
|
PersonBookmarks, nav_group)
|
||||||
nav_group)
|
fanchartdesc.FanChartDescGrampsGUI.__init__(self,
|
||||||
fanchartdesc.FanChartDescGrampsGUI.__init__(self, self.on_childmenu_changed)
|
self.on_childmenu_changed)
|
||||||
#set needed values
|
#set needed values
|
||||||
self.maxgen = self._config.get('interface.fanview-maxgen')
|
scg = self._config.get
|
||||||
self.background = self._config.get('interface.fanview-background')
|
self.maxgen = scg('interface.fanview-maxgen')
|
||||||
self.radialtext = self._config.get('interface.fanview-radialtext')
|
self.background = scg('interface.fanview-background')
|
||||||
self.twolinename = self._config.get('interface.fanview-twolinename')
|
self.radialtext = scg('interface.fanview-radialtext')
|
||||||
self.flipupsidedownname = self._config.get('interface.fanview-flipupsidedownname')
|
self.twolinename = scg('interface.fanview-twolinename')
|
||||||
self.fonttype = self._config.get('interface.fanview-font')
|
self.flipupsidedownname = scg('interface.fanview-flipupsidedownname')
|
||||||
|
self.fonttype = scg('interface.fanview-font')
|
||||||
|
|
||||||
self.grad_start = self._config.get('interface.color-start-grad')
|
self.grad_start = scg('interface.color-start-grad')
|
||||||
self.grad_end = self._config.get('interface.color-end-grad')
|
self.grad_end = scg('interface.color-end-grad')
|
||||||
self.form = self._config.get('interface.fanview-form')
|
self.form = scg('interface.fanview-form')
|
||||||
self.angle_algo = self._config.get('interface.angle-algorithm')
|
self.angle_algo = scg('interface.angle-algorithm')
|
||||||
self.dupcolor = self._config.get('interface.duplicate-color')
|
self.dupcolor = scg('interface.duplicate-color')
|
||||||
|
self.showid = scg('interface.fanview-showid')
|
||||||
self.generic_filter = None
|
self.generic_filter = None
|
||||||
self.alpha_filter = 0.2
|
self.alpha_filter = 0.2
|
||||||
|
self.scrolledwindow = None
|
||||||
|
|
||||||
dbstate.connect('active-changed', self.active_changed)
|
dbstate.connect('active-changed', self.active_changed)
|
||||||
dbstate.connect('database-changed', self.change_db)
|
dbstate.connect('database-changed', self.change_db)
|
||||||
@@ -170,6 +173,7 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
|
|||||||
Method called when active person changes.
|
Method called when active person changes.
|
||||||
"""
|
"""
|
||||||
# Reset everything but rotation angle (leave it as is)
|
# Reset everything but rotation angle (leave it as is)
|
||||||
|
dummy_handle = handle
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def _connect_db_signals(self):
|
def _connect_db_signals(self):
|
||||||
@@ -186,28 +190,43 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
|
|||||||
self._add_db_signal('family-rebuild', self.person_rebuild)
|
self._add_db_signal('family-rebuild', self.person_rebuild)
|
||||||
|
|
||||||
def change_db(self, db):
|
def change_db(self, db):
|
||||||
|
"""
|
||||||
|
We selected a new database
|
||||||
|
"""
|
||||||
self._change_db(db)
|
self._change_db(db)
|
||||||
if self.active:
|
if self.active:
|
||||||
self.bookmarks.redraw()
|
self.bookmarks.redraw()
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
|
"""
|
||||||
|
Redraw the fan chart
|
||||||
|
"""
|
||||||
self.main()
|
self.main()
|
||||||
|
|
||||||
def goto_handle(self, handle):
|
def goto_handle(self, handle):
|
||||||
|
"""
|
||||||
|
Draw the fan chart for the active person
|
||||||
|
"""
|
||||||
self.change_active(handle)
|
self.change_active(handle)
|
||||||
self.main()
|
self.main()
|
||||||
|
|
||||||
def get_active(self, object):
|
def get_active(self, obj):
|
||||||
"""overrule get_active, to support call as in Gramplets
|
"""overrule get_active, to support call as in Gramplets
|
||||||
"""
|
"""
|
||||||
|
dummy_obj = obj
|
||||||
return NavigationView.get_active(self)
|
return NavigationView.get_active(self)
|
||||||
|
|
||||||
def person_rebuild(self, *args):
|
def person_rebuild(self, *args):
|
||||||
|
"""
|
||||||
|
Redraw the fan chart for the person
|
||||||
|
"""
|
||||||
|
dummy_args = args
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def person_rebuild_bm(self, *args):
|
def person_rebuild_bm(self, *args):
|
||||||
"""Large change to person database"""
|
"""Large change to person database"""
|
||||||
|
dummy_args = args
|
||||||
self.person_rebuild()
|
self.person_rebuild()
|
||||||
if self.active:
|
if self.active:
|
||||||
self.bookmarks.redraw()
|
self.bookmarks.redraw()
|
||||||
@@ -216,6 +235,7 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
|
|||||||
"""
|
"""
|
||||||
Print or save the view that is currently shown
|
Print or save the view that is currently shown
|
||||||
"""
|
"""
|
||||||
|
dummy_obj = obj
|
||||||
widthpx = 2 * self.fan.halfdist()
|
widthpx = 2 * self.fan.halfdist()
|
||||||
heightpx = widthpx
|
heightpx = widthpx
|
||||||
if self.form == fanchart.FORM_HALFCIRCLE:
|
if self.form == fanchart.FORM_HALFCIRCLE:
|
||||||
@@ -231,6 +251,7 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
|
|||||||
def on_childmenu_changed(self, obj, person_handle):
|
def on_childmenu_changed(self, obj, person_handle):
|
||||||
"""Callback for the pulldown menu selection, changing to the person
|
"""Callback for the pulldown menu selection, changing to the person
|
||||||
attached with menu item."""
|
attached with menu item."""
|
||||||
|
dummy_obj = obj
|
||||||
self.change_active(person_handle)
|
self.change_active(person_handle)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -254,7 +275,6 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
|
|||||||
"""
|
"""
|
||||||
Function that builds the widget in the configuration dialog
|
Function that builds the widget in the configuration dialog
|
||||||
"""
|
"""
|
||||||
nrentry = 9
|
|
||||||
grid = Gtk.Grid()
|
grid = Gtk.Grid()
|
||||||
grid.set_border_width(12)
|
grid.set_border_width(12)
|
||||||
grid.set_column_spacing(6)
|
grid.set_column_spacing(6)
|
||||||
@@ -263,10 +283,10 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
|
|||||||
configdialog.add_spinner(grid, _("Max generations"), 0,
|
configdialog.add_spinner(grid, _("Max generations"), 0,
|
||||||
'interface.fanview-maxgen', (2, 16),
|
'interface.fanview-maxgen', (2, 16),
|
||||||
callback=self.cb_update_maxgen)
|
callback=self.cb_update_maxgen)
|
||||||
configdialog.add_combo(grid,
|
configdialog.add_combo(grid, _('Text Font'),
|
||||||
_('Text Font'),
|
|
||||||
1, 'interface.fanview-font',
|
1, 'interface.fanview-font',
|
||||||
self.allfonts, callback=self.cb_update_font, valueactive=True)
|
self.allfonts, callback=self.cb_update_font,
|
||||||
|
valueactive=True)
|
||||||
backgrvals = (
|
backgrvals = (
|
||||||
(fanchart.BACKGROUND_GENDER, _('Gender colors')),
|
(fanchart.BACKGROUND_GENDER, _('Gender colors')),
|
||||||
(fanchart.BACKGROUND_GRAD_GEN, _('Generation based gradient')),
|
(fanchart.BACKGROUND_GRAD_GEN, _('Generation based gradient')),
|
||||||
@@ -280,17 +300,14 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
|
|||||||
)
|
)
|
||||||
curval = self._config.get('interface.fanview-background')
|
curval = self._config.get('interface.fanview-background')
|
||||||
nrval = 0
|
nrval = 0
|
||||||
for nr, val in backgrvals:
|
for nbr, dummy_val in backgrvals:
|
||||||
if curval == nr:
|
if curval == nbr:
|
||||||
break
|
break
|
||||||
nrval += 1
|
nrval += 1
|
||||||
configdialog.add_combo(grid,
|
configdialog.add_combo(grid, _('Background'),
|
||||||
_('Background'),
|
|
||||||
2, 'interface.fanview-background',
|
2, 'interface.fanview-background',
|
||||||
backgrvals,
|
backgrvals, callback=self.cb_update_background,
|
||||||
callback=self.cb_update_background, valueactive=False,
|
valueactive=False, setactive=nrval)
|
||||||
setactive=nrval
|
|
||||||
)
|
|
||||||
#colors, stored as hex values
|
#colors, stored as hex values
|
||||||
configdialog.add_color(grid, _('Start gradient/Main color'), 3,
|
configdialog.add_color(grid, _('Start gradient/Main color'), 3,
|
||||||
'interface.color-start-grad', col=1)
|
'interface.color-start-grad', col=1)
|
||||||
@@ -311,20 +328,23 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
|
|||||||
((fanchartdesc.ANGLE_CHEQUI,
|
((fanchartdesc.ANGLE_CHEQUI,
|
||||||
_('Homogeneous children distribution')),
|
_('Homogeneous children distribution')),
|
||||||
(fanchartdesc.ANGLE_WEIGHT,
|
(fanchartdesc.ANGLE_WEIGHT,
|
||||||
_('Size proportional to number of descendants')),
|
_('Size proportional to number'
|
||||||
|
' of descendants')),
|
||||||
),
|
),
|
||||||
callback=self.cb_update_anglealgo)
|
callback=self.cb_update_anglealgo)
|
||||||
|
|
||||||
# show names one two line
|
# show names one two line
|
||||||
configdialog.add_checkbox(grid,
|
configdialog.add_checkbox(grid, _('Show names on two lines'),
|
||||||
_('Show names on two lines'),
|
|
||||||
8, 'interface.fanview-twolinename')
|
8, 'interface.fanview-twolinename')
|
||||||
|
|
||||||
# Flip names
|
# Flip names
|
||||||
configdialog.add_checkbox(grid,
|
configdialog.add_checkbox(grid, _('Flip name on the left of the fan'),
|
||||||
_('Flip name on the left of the fan'),
|
|
||||||
9, 'interface.fanview-flipupsidedownname')
|
9, 'interface.fanview-flipupsidedownname')
|
||||||
|
|
||||||
|
# show gramps_id
|
||||||
|
configdialog.add_checkbox(grid, _('Show gramps id'),
|
||||||
|
10, 'interface.fanview-showid')
|
||||||
|
|
||||||
return _('Layout'), grid
|
return _('Layout'), grid
|
||||||
|
|
||||||
def config_connect(self):
|
def config_connect(self):
|
||||||
@@ -343,8 +363,13 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
|
|||||||
self.cb_update_flipupsidedownname)
|
self.cb_update_flipupsidedownname)
|
||||||
self._config.connect('interface.fanview-twolinename',
|
self._config.connect('interface.fanview-twolinename',
|
||||||
self.cb_update_twolinename)
|
self.cb_update_twolinename)
|
||||||
|
self._config.connect('interface.fanview-showid',
|
||||||
|
self.cb_update_showid)
|
||||||
|
|
||||||
def cb_update_maxgen(self, spinbtn, constant):
|
def cb_update_maxgen(self, spinbtn, constant):
|
||||||
|
"""
|
||||||
|
The maximum generations in the fanchart
|
||||||
|
"""
|
||||||
self.maxgen = spinbtn.get_value_as_int()
|
self.maxgen = spinbtn.get_value_as_int()
|
||||||
self._config.set(constant, self.maxgen)
|
self._config.set(constant, self.maxgen)
|
||||||
self.update()
|
self.update()
|
||||||
@@ -357,6 +382,9 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
|
|||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def cb_update_background(self, obj, constant):
|
def cb_update_background(self, obj, constant):
|
||||||
|
"""
|
||||||
|
Change the background
|
||||||
|
"""
|
||||||
entry = obj.get_active()
|
entry = obj.get_active()
|
||||||
Gtk.TreePath.new_from_string('%d' % entry)
|
Gtk.TreePath.new_from_string('%d' % entry)
|
||||||
val = int(obj.get_model().get_value(
|
val = int(obj.get_model().get_value(
|
||||||
@@ -366,12 +394,18 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
|
|||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def cb_update_form(self, obj, constant):
|
def cb_update_form(self, obj, constant):
|
||||||
|
"""
|
||||||
|
Update the fanchart form: CIRCLE, HALFCIRCLE or QUADRANT
|
||||||
|
"""
|
||||||
entry = obj.get_active()
|
entry = obj.get_active()
|
||||||
self._config.set(constant, entry)
|
self._config.set(constant, entry)
|
||||||
self.form = entry
|
self.form = entry
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def cb_update_anglealgo(self, obj, constant):
|
def cb_update_anglealgo(self, obj, constant):
|
||||||
|
"""
|
||||||
|
Update the angle algorythm : homogeneous children distribution or not
|
||||||
|
"""
|
||||||
entry = obj.get_active()
|
entry = obj.get_active()
|
||||||
self._config.set(constant, entry)
|
self._config.set(constant, entry)
|
||||||
self.angle_algo = entry
|
self.angle_algo = entry
|
||||||
@@ -388,12 +422,23 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
|
|||||||
|
|
||||||
def cb_update_flipupsidedownname(self, client, cnxn_id, entry, data):
|
def cb_update_flipupsidedownname(self, client, cnxn_id, entry, data):
|
||||||
"""
|
"""
|
||||||
Called when the configuration menu changes the flipupsidedownname setting.
|
Called when the configuration menu changes the
|
||||||
|
flipupsidedownname setting.
|
||||||
"""
|
"""
|
||||||
self.flipupsidedownname = (entry == 'True')
|
self.flipupsidedownname = (entry == 'True')
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
def cb_update_showid(self, client, cnxn_id, entry, data):
|
||||||
|
"""
|
||||||
|
Called when the configuration menu changes the showid setting.
|
||||||
|
"""
|
||||||
|
self.showid = (entry == 'True')
|
||||||
|
self.update()
|
||||||
|
|
||||||
def cb_update_font(self, obj, constant):
|
def cb_update_font(self, obj, constant):
|
||||||
|
"""
|
||||||
|
Change the font
|
||||||
|
"""
|
||||||
entry = obj.get_active()
|
entry = obj.get_active()
|
||||||
self._config.set(constant, self.allfonts[entry][1])
|
self._config.set(constant, self.allfonts[entry][1])
|
||||||
self.fonttype = self.allfonts[entry][1]
|
self.fonttype = self.allfonts[entry][1]
|
||||||
@@ -428,6 +473,8 @@ class CairoPrintSave:
|
|||||||
self.heightpx = heightpx
|
self.heightpx = heightpx
|
||||||
self.drawfunc = drawfunc
|
self.drawfunc = drawfunc
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
self.preview = None
|
||||||
|
self.previewopr = None
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Create the physical output from the meta document.
|
"""Create the physical output from the meta document.
|
||||||
@@ -461,7 +508,8 @@ class CairoPrintSave:
|
|||||||
# run print dialog
|
# run print dialog
|
||||||
while True:
|
while True:
|
||||||
self.preview = None
|
self.preview = None
|
||||||
res = operation.run(Gtk.PrintOperationAction.PRINT_DIALOG, self.parent)
|
res = operation.run(Gtk.PrintOperationAction.PRINT_DIALOG,
|
||||||
|
self.parent)
|
||||||
if self.preview is None: # cancel or print
|
if self.preview is None: # cancel or print
|
||||||
break
|
break
|
||||||
# set up printing again; can't reuse PrintOperation?
|
# set up printing again; can't reuse PrintOperation?
|
||||||
@@ -481,20 +529,24 @@ class CairoPrintSave:
|
|||||||
def on_draw_page(self, operation, context, page_nr):
|
def on_draw_page(self, operation, context, page_nr):
|
||||||
"""Draw a page on a Cairo context.
|
"""Draw a page on a Cairo context.
|
||||||
"""
|
"""
|
||||||
cr = context.get_cairo_context()
|
dummy_operation = operation
|
||||||
|
dummy_page_nr = page_nr
|
||||||
|
ctx = context.get_cairo_context()
|
||||||
pxwidth = round(context.get_width())
|
pxwidth = round(context.get_width())
|
||||||
pxheight = round(context.get_height())
|
pxheight = round(context.get_height())
|
||||||
scale = min(pxwidth/self.widthpx, pxheight/self.heightpx)
|
scale = min(pxwidth/self.widthpx, pxheight/self.heightpx)
|
||||||
self.drawfunc(None, cr, scale=scale)
|
self.drawfunc(None, ctx, scale=scale)
|
||||||
|
|
||||||
def on_paginate(self, operation, context):
|
def on_paginate(self, operation, context):
|
||||||
"""Paginate the whole document in chunks.
|
"""Paginate the whole document in chunks.
|
||||||
We don't need this as there is only one page, however,
|
We don't need this as there is only one page, however,
|
||||||
we provide a dummy holder here, because on_preview crashes if no
|
we provide a dummy holder here, because on_preview crashes if no
|
||||||
default application is set with gir 3.3.2 (typically evince not installed)!
|
default application is set with gir 3.3.2
|
||||||
|
(typically evince not installed)!
|
||||||
It will provide the start of the preview dialog, which cannot be
|
It will provide the start of the preview dialog, which cannot be
|
||||||
started in on_preview
|
started in on_preview
|
||||||
"""
|
"""
|
||||||
|
dummy_context = context
|
||||||
finished = True
|
finished = True
|
||||||
# update page number
|
# update page number
|
||||||
operation.set_n_pages(1)
|
operation.set_n_pages(1)
|
||||||
@@ -508,8 +560,10 @@ class CairoPrintSave:
|
|||||||
def on_preview(self, operation, preview, context, parent):
|
def on_preview(self, operation, preview, context, parent):
|
||||||
"""Implement custom print preview functionality.
|
"""Implement custom print preview functionality.
|
||||||
We provide a dummy holder here, because on_preview crashes if no
|
We provide a dummy holder here, because on_preview crashes if no
|
||||||
default application is set with gir 3.3.2 (typically evince not installed)!
|
default application is set with gir 3.3.2
|
||||||
|
(typically evince not installed)!
|
||||||
"""
|
"""
|
||||||
|
dummy_preview = preview
|
||||||
dlg = Gtk.MessageDialog(parent,
|
dlg = Gtk.MessageDialog(parent,
|
||||||
flags=Gtk.DialogFlags.MODAL,
|
flags=Gtk.DialogFlags.MODAL,
|
||||||
type=Gtk.MessageType.WARNING,
|
type=Gtk.MessageType.WARNING,
|
||||||
@@ -531,11 +585,16 @@ class CairoPrintSave:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
height = 0
|
height = 0
|
||||||
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
|
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
|
||||||
cr = cairo.Context(surface)
|
ctx = cairo.Context(surface)
|
||||||
context.set_cairo_context(cr, 72.0, 72.0)
|
context.set_cairo_context(ctx, 72.0, 72.0)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def previewdestroy(self, dlg, res):
|
def previewdestroy(self, dlg, res):
|
||||||
|
"""
|
||||||
|
Destroy the preview page
|
||||||
|
"""
|
||||||
|
dummy_dlg = dlg
|
||||||
|
dummy_res = res
|
||||||
self.preview.destroy()
|
self.preview.destroy()
|
||||||
self.previewopr.end_preview()
|
self.previewopr.end_preview()
|
||||||
|
@@ -30,11 +30,9 @@
|
|||||||
# Python modules
|
# Python modules
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
from gi.repository import Gdk
|
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
import cairo
|
import cairo
|
||||||
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
||||||
_ = glocale.translation.sgettext
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
@@ -48,6 +46,7 @@ from gramps.gui.utils import SystemFonts
|
|||||||
|
|
||||||
# the print settings to remember between print sessions
|
# the print settings to remember between print sessions
|
||||||
PRINT_SETTINGS = None
|
PRINT_SETTINGS = None
|
||||||
|
_ = glocale.translation.sgettext
|
||||||
|
|
||||||
class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
||||||
"""
|
"""
|
||||||
@@ -63,6 +62,7 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
|||||||
('interface.fanview-flipupsidedownname', True),
|
('interface.fanview-flipupsidedownname', True),
|
||||||
('interface.fanview-font', 'Sans'),
|
('interface.fanview-font', 'Sans'),
|
||||||
('interface.fanview-form', fanchart.FORM_CIRCLE),
|
('interface.fanview-form', fanchart.FORM_CIRCLE),
|
||||||
|
('interface.fanview-showid', False),
|
||||||
('interface.color-start-grad', '#ef2929'),
|
('interface.color-start-grad', '#ef2929'),
|
||||||
('interface.color-end-grad', '#3d37e9'),
|
('interface.color-end-grad', '#3d37e9'),
|
||||||
)
|
)
|
||||||
@@ -72,23 +72,25 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
|||||||
|
|
||||||
NavigationView.__init__(self, _('Fan Chart'),
|
NavigationView.__init__(self, _('Fan Chart'),
|
||||||
pdata, dbstate, uistate,
|
pdata, dbstate, uistate,
|
||||||
PersonBookmarks,
|
PersonBookmarks, nav_group)
|
||||||
nav_group)
|
|
||||||
fanchart.FanChartGrampsGUI.__init__(self, self.on_childmenu_changed)
|
fanchart.FanChartGrampsGUI.__init__(self, self.on_childmenu_changed)
|
||||||
#set needed values
|
#set needed values
|
||||||
self.maxgen = self._config.get('interface.fanview-maxgen')
|
scg = self._config.get
|
||||||
self.background = self._config.get('interface.fanview-background')
|
self.maxgen = scg('interface.fanview-maxgen')
|
||||||
self.childring = self._config.get('interface.fanview-childrenring')
|
self.background = scg('interface.fanview-background')
|
||||||
self.radialtext = self._config.get('interface.fanview-radialtext')
|
self.childring = scg('interface.fanview-childrenring')
|
||||||
self.twolinename = self._config.get('interface.fanview-twolinename')
|
self.radialtext = scg('interface.fanview-radialtext')
|
||||||
self.flipupsidedownname = self._config.get('interface.fanview-flipupsidedownname')
|
self.twolinename = scg('interface.fanview-twolinename')
|
||||||
self.fonttype = self._config.get('interface.fanview-font')
|
self.flipupsidedownname = scg('interface.fanview-flipupsidedownname')
|
||||||
|
self.fonttype = scg('interface.fanview-font')
|
||||||
|
|
||||||
self.grad_start = self._config.get('interface.color-start-grad')
|
self.grad_start = scg('interface.color-start-grad')
|
||||||
self.grad_end = self._config.get('interface.color-end-grad')
|
self.grad_end = scg('interface.color-end-grad')
|
||||||
self.form = self._config.get('interface.fanview-form')
|
self.form = scg('interface.fanview-form')
|
||||||
|
self.showid = scg('interface.fanview-showid')
|
||||||
self.generic_filter = None
|
self.generic_filter = None
|
||||||
self.alpha_filter = 0.2
|
self.alpha_filter = 0.2
|
||||||
|
self.scrolledwindow = None
|
||||||
|
|
||||||
dbstate.connect('active-changed', self.active_changed)
|
dbstate.connect('active-changed', self.active_changed)
|
||||||
dbstate.connect('database-changed', self.change_db)
|
dbstate.connect('database-changed', self.change_db)
|
||||||
@@ -119,7 +121,8 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def build_widget(self):
|
def build_widget(self):
|
||||||
self.set_fan(fanchart.FanChartWidget(self.dbstate, self.uistate, self.on_popup))
|
self.set_fan(fanchart.FanChartWidget(self.dbstate, self.uistate,
|
||||||
|
self.on_popup))
|
||||||
self.scrolledwindow = Gtk.ScrolledWindow(hadjustment=None,
|
self.scrolledwindow = Gtk.ScrolledWindow(hadjustment=None,
|
||||||
vadjustment=None)
|
vadjustment=None)
|
||||||
self.scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC,
|
self.scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC,
|
||||||
@@ -266,6 +269,7 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
|||||||
"""
|
"""
|
||||||
Method called when active person changes.
|
Method called when active person changes.
|
||||||
"""
|
"""
|
||||||
|
dummy_handle = handle
|
||||||
# Reset everything but rotation angle (leave it as is)
|
# Reset everything but rotation angle (leave it as is)
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
@@ -283,28 +287,43 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
|||||||
self._add_db_signal('family-rebuild', self.person_rebuild)
|
self._add_db_signal('family-rebuild', self.person_rebuild)
|
||||||
|
|
||||||
def change_db(self, db):
|
def change_db(self, db):
|
||||||
|
"""
|
||||||
|
We selected a new database
|
||||||
|
"""
|
||||||
self._change_db(db)
|
self._change_db(db)
|
||||||
if self.active:
|
if self.active:
|
||||||
self.bookmarks.redraw()
|
self.bookmarks.redraw()
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
|
"""
|
||||||
|
Redraw the fan chart
|
||||||
|
"""
|
||||||
self.main()
|
self.main()
|
||||||
|
|
||||||
def goto_handle(self, handle):
|
def goto_handle(self, handle):
|
||||||
|
"""
|
||||||
|
Draw the fan chart for the active person
|
||||||
|
"""
|
||||||
self.change_active(handle)
|
self.change_active(handle)
|
||||||
self.main()
|
self.main()
|
||||||
|
|
||||||
def get_active(self, object):
|
def get_active(self, obj):
|
||||||
"""overrule get_active, to support call as in Gramplets
|
"""overrule get_active, to support call as in Gramplets
|
||||||
"""
|
"""
|
||||||
|
dummy_obj = obj
|
||||||
return NavigationView.get_active(self)
|
return NavigationView.get_active(self)
|
||||||
|
|
||||||
def person_rebuild(self, *args):
|
def person_rebuild(self, *args):
|
||||||
|
"""
|
||||||
|
Redraw the fan chart for the person
|
||||||
|
"""
|
||||||
|
dummy_args = args
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def person_rebuild_bm(self, *args):
|
def person_rebuild_bm(self, *args):
|
||||||
"""Large change to person database"""
|
"""Large change to person database"""
|
||||||
|
dummy_args = args
|
||||||
self.person_rebuild()
|
self.person_rebuild()
|
||||||
if self.active:
|
if self.active:
|
||||||
self.bookmarks.redraw()
|
self.bookmarks.redraw()
|
||||||
@@ -313,6 +332,7 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
|||||||
"""
|
"""
|
||||||
Print or save the view that is currently shown
|
Print or save the view that is currently shown
|
||||||
"""
|
"""
|
||||||
|
dummy_obj = obj
|
||||||
widthpx = 2 * self.fan.halfdist()
|
widthpx = 2 * self.fan.halfdist()
|
||||||
heightpx = widthpx
|
heightpx = widthpx
|
||||||
if self.form == fanchart.FORM_HALFCIRCLE:
|
if self.form == fanchart.FORM_HALFCIRCLE:
|
||||||
@@ -328,6 +348,7 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
|||||||
def on_childmenu_changed(self, obj, person_handle):
|
def on_childmenu_changed(self, obj, person_handle):
|
||||||
"""Callback for the pulldown menu selection, changing to the person
|
"""Callback for the pulldown menu selection, changing to the person
|
||||||
attached with menu item."""
|
attached with menu item."""
|
||||||
|
dummy_obj = obj
|
||||||
self.change_active(person_handle)
|
self.change_active(person_handle)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -351,7 +372,7 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
|||||||
"""
|
"""
|
||||||
Function that builds the widget in the configuration dialog
|
Function that builds the widget in the configuration dialog
|
||||||
"""
|
"""
|
||||||
nrentry = 9
|
nrentry = 10
|
||||||
grid = Gtk.Grid()
|
grid = Gtk.Grid()
|
||||||
grid.set_border_width(12)
|
grid.set_border_width(12)
|
||||||
grid.set_column_spacing(6)
|
grid.set_column_spacing(6)
|
||||||
@@ -360,16 +381,15 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
|||||||
configdialog.add_spinner(grid, _("Max generations"), 0,
|
configdialog.add_spinner(grid, _("Max generations"), 0,
|
||||||
'interface.fanview-maxgen', (1, 16),
|
'interface.fanview-maxgen', (1, 16),
|
||||||
callback=self.cb_update_maxgen)
|
callback=self.cb_update_maxgen)
|
||||||
configdialog.add_combo(grid,
|
configdialog.add_combo(grid, _('Text Font'),
|
||||||
_('Text Font'),
|
|
||||||
1, 'interface.fanview-font',
|
1, 'interface.fanview-font',
|
||||||
self.allfonts, callback=self.cb_update_font, valueactive=True)
|
self.allfonts, callback=self.cb_update_font,
|
||||||
|
valueactive=True)
|
||||||
backgrvals = (
|
backgrvals = (
|
||||||
(fanchart.BACKGROUND_GENDER, _('Gender colors')),
|
(fanchart.BACKGROUND_GENDER, _('Gender colors')),
|
||||||
(fanchart.BACKGROUND_GRAD_GEN, _('Generation based gradient')),
|
(fanchart.BACKGROUND_GRAD_GEN, _('Generation based gradient')),
|
||||||
(fanchart.BACKGROUND_GRAD_AGE, _('Age (0-100) based gradient')),
|
(fanchart.BACKGROUND_GRAD_AGE, _('Age (0-100) based gradient')),
|
||||||
(fanchart.BACKGROUND_SINGLE_COLOR,
|
(fanchart.BACKGROUND_SINGLE_COLOR, _('Single main (filter) color')),
|
||||||
_('Single main (filter) color')),
|
|
||||||
(fanchart.BACKGROUND_GRAD_PERIOD, _('Time period based gradient')),
|
(fanchart.BACKGROUND_GRAD_PERIOD, _('Time period based gradient')),
|
||||||
(fanchart.BACKGROUND_WHITE, _('White')),
|
(fanchart.BACKGROUND_WHITE, _('White')),
|
||||||
(fanchart.BACKGROUND_SCHEME1, _('Color scheme classic report')),
|
(fanchart.BACKGROUND_SCHEME1, _('Color scheme classic report')),
|
||||||
@@ -377,16 +397,14 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
|||||||
)
|
)
|
||||||
curval = self._config.get('interface.fanview-background')
|
curval = self._config.get('interface.fanview-background')
|
||||||
nrval = 0
|
nrval = 0
|
||||||
for nr, val in backgrvals:
|
for nbr, dummy_val in backgrvals:
|
||||||
if curval == nr:
|
if curval == nbr:
|
||||||
break
|
break
|
||||||
nrval += 1
|
nrval += 1
|
||||||
configdialog.add_combo(grid,
|
configdialog.add_combo(grid, _('Background'),
|
||||||
_('Background'),
|
2, 'interface.fanview-background', backgrvals,
|
||||||
2, 'interface.fanview-background',
|
callback=self.cb_update_background,
|
||||||
backgrvals,
|
valueactive=False, setactive=nrval)
|
||||||
callback=self.cb_update_background, valueactive=False, setactive=nrval
|
|
||||||
)
|
|
||||||
#colors, stored as hex values
|
#colors, stored as hex values
|
||||||
configdialog.add_color(grid, _('Start gradient/Main color'), 3,
|
configdialog.add_color(grid, _('Start gradient/Main color'), 3,
|
||||||
'interface.color-start-grad', col=1)
|
'interface.color-start-grad', col=1)
|
||||||
@@ -400,19 +418,20 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
|||||||
callback=self.cb_update_form)
|
callback=self.cb_update_form)
|
||||||
|
|
||||||
# show names one two line
|
# show names one two line
|
||||||
configdialog.add_checkbox(grid,
|
configdialog.add_checkbox(grid, _('Show names on two lines'),
|
||||||
_('Show names on two lines'),
|
|
||||||
6, 'interface.fanview-twolinename')
|
6, 'interface.fanview-twolinename')
|
||||||
|
|
||||||
# Flip names
|
# Flip names
|
||||||
configdialog.add_checkbox(grid,
|
configdialog.add_checkbox(grid, _('Flip name on the left of the fan'),
|
||||||
_('Flip name on the left of the fan'),
|
|
||||||
7, 'interface.fanview-flipupsidedownname')
|
7, 'interface.fanview-flipupsidedownname')
|
||||||
|
|
||||||
# options users should not change:
|
# options users should not change:
|
||||||
configdialog.add_checkbox(grid,
|
configdialog.add_checkbox(grid, _('Show children ring'),
|
||||||
_('Show children ring'),
|
nrentry-2, 'interface.fanview-childrenring')
|
||||||
nrentry-1, 'interface.fanview-childrenring')
|
|
||||||
|
# Show the gramps_id
|
||||||
|
configdialog.add_checkbox(grid, _('Show gramps id'),
|
||||||
|
nrentry-1, 'interface.fanview-showid')
|
||||||
# options we don't show on the dialog
|
# options we don't show on the dialog
|
||||||
##configdialog.add_checkbox(table,
|
##configdialog.add_checkbox(table,
|
||||||
## _('Allow radial text'),
|
## _('Allow radial text'),
|
||||||
@@ -434,17 +453,25 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
|||||||
self.cb_update_flipupsidedownname)
|
self.cb_update_flipupsidedownname)
|
||||||
self._config.connect('interface.fanview-radialtext',
|
self._config.connect('interface.fanview-radialtext',
|
||||||
self.cb_update_radialtext)
|
self.cb_update_radialtext)
|
||||||
|
self._config.connect('interface.fanview-showid',
|
||||||
|
self.cb_update_showid)
|
||||||
self._config.connect('interface.color-start-grad',
|
self._config.connect('interface.color-start-grad',
|
||||||
self.cb_update_color)
|
self.cb_update_color)
|
||||||
self._config.connect('interface.color-end-grad',
|
self._config.connect('interface.color-end-grad',
|
||||||
self.cb_update_color)
|
self.cb_update_color)
|
||||||
|
|
||||||
def cb_update_maxgen(self, spinbtn, constant):
|
def cb_update_maxgen(self, spinbtn, constant):
|
||||||
|
"""
|
||||||
|
The maximum generations in the fanchart
|
||||||
|
"""
|
||||||
self.maxgen = spinbtn.get_value_as_int()
|
self.maxgen = spinbtn.get_value_as_int()
|
||||||
self._config.set(constant, self.maxgen)
|
self._config.set(constant, self.maxgen)
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def cb_update_background(self, obj, constant):
|
def cb_update_background(self, obj, constant):
|
||||||
|
"""
|
||||||
|
Change the background
|
||||||
|
"""
|
||||||
entry = obj.get_active()
|
entry = obj.get_active()
|
||||||
Gtk.TreePath.new_from_string('%d' % entry)
|
Gtk.TreePath.new_from_string('%d' % entry)
|
||||||
val = int(obj.get_model().get_value(
|
val = int(obj.get_model().get_value(
|
||||||
@@ -454,6 +481,9 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
|||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def cb_update_form(self, obj, constant):
|
def cb_update_form(self, obj, constant):
|
||||||
|
"""
|
||||||
|
Update the fanchart form: CIRCLE, HALFCIRCLE or QUADRANT
|
||||||
|
"""
|
||||||
entry = obj.get_active()
|
entry = obj.get_active()
|
||||||
self._config.set(constant, entry)
|
self._config.set(constant, entry)
|
||||||
self.form = entry
|
self.form = entry
|
||||||
@@ -463,20 +493,21 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
|||||||
"""
|
"""
|
||||||
Called when the configuration menu changes the childrenring setting.
|
Called when the configuration menu changes the childrenring setting.
|
||||||
"""
|
"""
|
||||||
if entry == 'True':
|
self.childring = (entry == 'True')
|
||||||
self.childring = True
|
|
||||||
else:
|
|
||||||
self.childring = False
|
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def cb_update_radialtext(self, client, cnxn_id, entry, data):
|
def cb_update_radialtext(self, client, cnxn_id, entry, data):
|
||||||
"""
|
"""
|
||||||
Called when the configuration menu changes the childrenring setting.
|
Called when the configuration menu changes the childrenring setting.
|
||||||
"""
|
"""
|
||||||
if entry == 'True':
|
self.radialtext = (entry == 'True')
|
||||||
self.radialtext = True
|
self.update()
|
||||||
else:
|
|
||||||
self.radialtext = False
|
def cb_update_showid(self, client, cnxn_id, entry, data):
|
||||||
|
"""
|
||||||
|
Called when the configuration menu changes the showid setting.
|
||||||
|
"""
|
||||||
|
self.showid = (entry == 'True')
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def cb_update_color(self, client, cnxn_id, entry, data):
|
def cb_update_color(self, client, cnxn_id, entry, data):
|
||||||
@@ -496,12 +527,16 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
|
|||||||
|
|
||||||
def cb_update_flipupsidedownname(self, client, cnxn_id, entry, data):
|
def cb_update_flipupsidedownname(self, client, cnxn_id, entry, data):
|
||||||
"""
|
"""
|
||||||
Called when the configuration menu changes the flipupsidedownname setting.
|
Called when the configuration menu changes the
|
||||||
|
flipupsidedownname setting.
|
||||||
"""
|
"""
|
||||||
self.flipupsidedownname = (entry == 'True')
|
self.flipupsidedownname = (entry == 'True')
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def cb_update_font(self, obj, constant):
|
def cb_update_font(self, obj, constant):
|
||||||
|
"""
|
||||||
|
Change the font
|
||||||
|
"""
|
||||||
entry = obj.get_active()
|
entry = obj.get_active()
|
||||||
self._config.set(constant, self.allfonts[entry][1])
|
self._config.set(constant, self.allfonts[entry][1])
|
||||||
self.fonttype = self.allfonts[entry][1]
|
self.fonttype = self.allfonts[entry][1]
|
||||||
@@ -536,6 +571,8 @@ class CairoPrintSave:
|
|||||||
self.heightpx = heightpx
|
self.heightpx = heightpx
|
||||||
self.drawfunc = drawfunc
|
self.drawfunc = drawfunc
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
self.preview = None
|
||||||
|
self.previewopr = None
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Create the physical output from the meta document.
|
"""Create the physical output from the meta document.
|
||||||
@@ -569,7 +606,8 @@ class CairoPrintSave:
|
|||||||
# run print dialog
|
# run print dialog
|
||||||
while True:
|
while True:
|
||||||
self.preview = None
|
self.preview = None
|
||||||
res = operation.run(Gtk.PrintOperationAction.PRINT_DIALOG, self.parent)
|
res = operation.run(Gtk.PrintOperationAction.PRINT_DIALOG,
|
||||||
|
self.parent)
|
||||||
if self.preview is None: # cancel or print
|
if self.preview is None: # cancel or print
|
||||||
break
|
break
|
||||||
# set up printing again; can't reuse PrintOperation?
|
# set up printing again; can't reuse PrintOperation?
|
||||||
@@ -589,20 +627,24 @@ class CairoPrintSave:
|
|||||||
def on_draw_page(self, operation, context, page_nr):
|
def on_draw_page(self, operation, context, page_nr):
|
||||||
"""Draw a page on a Cairo context.
|
"""Draw a page on a Cairo context.
|
||||||
"""
|
"""
|
||||||
cr = context.get_cairo_context()
|
dummy_operation = operation
|
||||||
|
dummy_page_nr = page_nr
|
||||||
|
ctx = context.get_cairo_context()
|
||||||
pxwidth = round(context.get_width())
|
pxwidth = round(context.get_width())
|
||||||
pxheight = round(context.get_height())
|
pxheight = round(context.get_height())
|
||||||
scale = min(pxwidth/self.widthpx, pxheight/self.heightpx)
|
scale = min(pxwidth/self.widthpx, pxheight/self.heightpx)
|
||||||
self.drawfunc(None, cr, scale=scale)
|
self.drawfunc(None, ctx, scale=scale)
|
||||||
|
|
||||||
def on_paginate(self, operation, context):
|
def on_paginate(self, operation, context):
|
||||||
"""Paginate the whole document in chunks.
|
"""Paginate the whole document in chunks.
|
||||||
We don't need this as there is only one page, however,
|
We don't need this as there is only one page, however,
|
||||||
we provide a dummy holder here, because on_preview crashes if no
|
we provide a dummy holder here, because on_preview crashes if no
|
||||||
default application is set with gir 3.3.2 (typically evince not installed)!
|
default application is set with gir 3.3.2
|
||||||
|
(typically evince not installed)!
|
||||||
It will provide the start of the preview dialog, which cannot be
|
It will provide the start of the preview dialog, which cannot be
|
||||||
started in on_preview
|
started in on_preview
|
||||||
"""
|
"""
|
||||||
|
dummy_context = context
|
||||||
finished = True
|
finished = True
|
||||||
# update page number
|
# update page number
|
||||||
operation.set_n_pages(1)
|
operation.set_n_pages(1)
|
||||||
@@ -616,8 +658,10 @@ class CairoPrintSave:
|
|||||||
def on_preview(self, operation, preview, context, parent):
|
def on_preview(self, operation, preview, context, parent):
|
||||||
"""Implement custom print preview functionality.
|
"""Implement custom print preview functionality.
|
||||||
We provide a dummy holder here, because on_preview crashes if no
|
We provide a dummy holder here, because on_preview crashes if no
|
||||||
default application is set with gir 3.3.2 (typically evince not installed)!
|
default application is set with gir 3.3.2
|
||||||
|
(typically evince not installed)!
|
||||||
"""
|
"""
|
||||||
|
dummy_preview = preview
|
||||||
dlg = Gtk.MessageDialog(parent,
|
dlg = Gtk.MessageDialog(parent,
|
||||||
flags=Gtk.DialogFlags.MODAL,
|
flags=Gtk.DialogFlags.MODAL,
|
||||||
type=Gtk.MessageType.WARNING,
|
type=Gtk.MessageType.WARNING,
|
||||||
@@ -639,11 +683,16 @@ class CairoPrintSave:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
height = 0
|
height = 0
|
||||||
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
|
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
|
||||||
cr = cairo.Context(surface)
|
ctx = cairo.Context(surface)
|
||||||
context.set_cairo_context(cr, 72.0, 72.0)
|
context.set_cairo_context(ctx, 72.0, 72.0)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def previewdestroy(self, dlg, res):
|
def previewdestroy(self, dlg, res):
|
||||||
|
"""
|
||||||
|
Destroy the preview page
|
||||||
|
"""
|
||||||
|
dummy_dlg = dlg
|
||||||
|
dummy_res = res
|
||||||
self.preview.destroy()
|
self.preview.destroy()
|
||||||
self.previewopr.end_preview()
|
self.previewopr.end_preview()
|
||||||
|
Reference in New Issue
Block a user