Fix Fan charts for scrolling/resizing of window; bad rendering (#572)

Fixes #10381
This commit is contained in:
Paul Culley 2018-03-09 19:53:34 -06:00 committed by Sam Manzi
parent babe13f811
commit ae11eceef7
6 changed files with 96 additions and 40 deletions

View File

@ -120,6 +120,7 @@ class FanChartBaseWidget(Gtk.DrawingArea):
self.dbstate = dbstate
self.uistate = uistate
self.translating = False
self.surface = None
self.goto = None
self.on_popup = callback_popup
self.last_x, self.last_y = None, None
@ -248,7 +249,15 @@ class FanChartBaseWidget(Gtk.DrawingArea):
"""
callback to draw the fanchart
"""
raise NotImplementedError
if self.surface:
cr.set_source_surface(self.surface, 0, 0)
cr.paint()
def prt_draw(self, widget, cr, scale=1.0):
"""
method to allow direct drawing to cairo context for printing
"""
self.draw(cr=cr, scale=scale)
def people_generator(self):
"""
@ -749,7 +758,7 @@ class FanChartBaseWidget(Gtk.DrawingArea):
return lambda x, y: \
(rho(y) * math.cos(phi(x)), rho(y) * math.sin(phi(x)))
def draw_gradient_legend(self, cr, widget, halfdist):
def draw_gradient_legend(self, cr, halfdist):
gradwidth = 10
gradheight = 10
starth = 15
@ -924,6 +933,7 @@ class FanChartBaseWidget(Gtk.DrawingArea):
diff_angle = (end_angle - start_angle) % (math.pi * 2.0)
self.rotate_value -= math.degrees(diff_angle)
self.last_x, self.last_y = event.x, event.y
self.draw()
self.queue_draw()
return True
@ -954,8 +964,12 @@ class FanChartBaseWidget(Gtk.DrawingArea):
return True
if self.translating:
self.translating = False
else:
self.center_delta_xy = -1, 0
self.center_xy = self.center_xy_from_delta()
self.last_x, self.last_y = None, None
self.draw()
self.queue_draw()
return True
@ -1207,27 +1221,39 @@ class FanChartWidget(FanChartBaseWidget):
(person, parents, child, userdata) = childdata
yield (person, userdata)
def on_draw(self, widget, cr, scale=1.):
def draw(self, cr=None, scale=1.0):
"""
The main method to do the drawing.
If widget is given, we assume we draw in GTK3 and use the allocation.
To draw raw on the cairo context cr, set widget=None.
If cr is given, we assume we draw draw raw on the cairo context cr
To draw in GTK3 and use the allocation, set cr=None.
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
drawing context when the Gtk 'draw' signal arrives.
"""
# first do size request of what we will need
halfdist = self.halfdist()
if widget:
if not cr: # Display
if self.form == FORM_CIRCLE:
self.set_size_request(2 * halfdist, 2 * halfdist)
size_w = size_h = 2 * halfdist
elif self.form == FORM_HALFCIRCLE:
self.set_size_request(2 * halfdist, halfdist + self.CENTER + PAD_PX)
size_w = 2 * halfdist
size_h = halfdist + self.CENTER + PAD_PX
elif self.form == FORM_QUADRANT:
self.set_size_request(halfdist + self.CENTER + PAD_PX, halfdist + self.CENTER + PAD_PX)
size_w = size_h = halfdist + self.CENTER + PAD_PX
cr.scale(scale, scale)
if widget:
size_w_a = self.get_allocated_width()
size_h_a = self.get_allocated_height()
self.set_size_request(max(size_w, size_w_a), max(size_h, size_h_a))
size_w = self.get_allocated_width()
size_h = self.get_allocated_height()
self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
size_w, size_h)
cr = cairo.Context(self.surface)
self.center_xy = self.center_xy_from_delta()
cr.translate(*self.center_xy)
else:
else: # printing
self.center_xy = halfdist, halfdist
cr.scale(scale, scale)
cr.translate(halfdist, halfdist)
cr.save()
@ -1262,7 +1288,7 @@ class FanChartWidget(FanChartBaseWidget):
if child and self.childring:
self.draw_childring(cr)
if self.background in [BACKGROUND_GRAD_AGE, BACKGROUND_GRAD_PERIOD]:
self.draw_gradient_legend(cr, widget, halfdist)
self.draw_gradient_legend(cr, halfdist)
def draw_childring(self, cr):
cr.move_to(TRANSLATE_PX + CHILDRING_WIDTH, 0)
@ -1460,6 +1486,7 @@ class FanChartWidget(FanChartBaseWidget):
# no drag occured, expand or collapse the section
self.toggle_cell_state(self._mouse_click_cell_address)
self._mouse_click = False
self.draw()
self.queue_draw()
class FanChartGrampsGUI:
@ -1494,6 +1521,7 @@ class FanChartGrampsGUI:
self.grad_start, self.grad_end,
self.generic_filter, self.alpha_filter, self.form)
self.fan.reset()
self.fan.draw()
self.fan.queue_draw()
def on_popup(self, obj, event, person_handle, family_handle=None):

View File

@ -359,23 +359,33 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
cr.fill()
cr.restore()
def on_draw(self, widget, cr, scale=1.):
def draw(self, cr=None, scale=1.0):
"""
The main method to do the drawing.
If widget is given, we assume we draw in GTK3 and use the allocation.
To draw raw on the cairo context cr, set widget=None.
If cr is given, we assume we draw draw raw on the cairo context cr
To draw in GTK3 and use the allocation, set cr=None.
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
drawing context when the Gtk 'draw' signal arrives.
"""
# first do size request of what we will need
halfdist = self.halfdist()
if widget:
self.set_size_request(2 * halfdist, 2 * halfdist)
if not cr: # Display
size_w = size_h = 2 * halfdist
cr.scale(scale, scale)
if widget:
size_w_a = self.get_allocated_width()
size_h_a = self.get_allocated_height()
self.set_size_request(max(size_w, size_w_a), max(size_h, size_h_a))
size_w = self.get_allocated_width()
size_h = self.get_allocated_height()
self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
size_w, size_h)
cr = cairo.Context(self.surface)
self.center_xy = self.center_xy_from_delta()
cr.translate(*self.center_xy)
else:
else: # printing
self.center_xy = halfdist, halfdist
cr.scale(scale, scale)
cr.translate(halfdist, halfdist)
cr.save()
@ -444,7 +454,7 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
cr.restore()
if self.background in [BACKGROUND_GRAD_AGE, BACKGROUND_GRAD_PERIOD]:
self.draw_gradient_legend(cr, widget, halfdist)
self.draw_gradient_legend(cr, halfdist)
def cell_address_under_cursor(self, curx, cury):
"""
@ -542,6 +552,7 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
# no drag occured, expand or collapse the section
self.toggle_cell_state(self._mouse_click_cell_address)
self._mouse_click = False
self.draw()
self.queue_draw()
def expand_parents(self, generation, selected, current):
@ -624,4 +635,5 @@ class FanChart2WayGrampsGUI(FanChartGrampsGUI):
self.generic_filter, self.alpha_filter,
self.angle_algo, self.dupcolor)
self.fan.reset()
self.fan.draw()
self.fan.queue_draw()

View File

@ -404,29 +404,40 @@ class FanChartDescWidget(FanChartBaseWidget):
parent, userdata = parentdata
yield (parent, userdata)
def on_draw(self, widget, cr, scale=1.):
def draw(self, cr=None, scale=1.0):
"""
The main method to do the drawing.
If widget is given, we assume we draw in GTK3 and use the allocation.
To draw raw on the cairo context cr, set widget=None.
If cr is given, we assume we draw draw raw on the cairo context cr
To draw in GTK3 and use the allocation, set cr=None.
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
drawing context when the Gtk 'draw' signal arrives.
"""
# first do size request of what we will need
halfdist = self.halfdist()
if widget:
if not cr: # Display
if self.form == FORM_CIRCLE:
self.set_size_request(2 * halfdist, 2 * halfdist)
size_w = size_h = 2 * halfdist
elif self.form == FORM_HALFCIRCLE:
self.set_size_request(2 * halfdist, halfdist + self.CENTER
+ PAD_PX)
size_w = 2 * halfdist
size_h = halfdist + self.CENTER + PAD_PX
elif self.form == FORM_QUADRANT:
self.set_size_request(halfdist + self.CENTER + PAD_PX,
halfdist + self.CENTER + PAD_PX)
size_w = size_h = halfdist + self.CENTER + PAD_PX
cr.scale(scale, scale)
# when printing, we need not recalculate
if widget:
size_w_a = self.get_allocated_width()
size_h_a = self.get_allocated_height()
self.set_size_request(max(size_w, size_w_a), max(size_h, size_h_a))
size_w = self.get_allocated_width()
size_h = self.get_allocated_height()
self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
size_w, size_h)
cr = cairo.Context(self.surface)
self.center_xy = self.center_xy_from_delta()
cr.translate(*self.center_xy)
cr.translate(*self.center_xy)
else: # printing
self.center_xy = halfdist, halfdist
cr.scale(scale, scale)
cr.translate(halfdist, halfdist)
cr.save()
# Draw center person:
@ -477,7 +488,7 @@ class FanChartDescWidget(FanChartBaseWidget):
cr.restore()
if self.background in [BACKGROUND_GRAD_AGE, BACKGROUND_GRAD_PERIOD]:
self.draw_gradient_legend(cr, widget, halfdist)
self.draw_gradient_legend(cr, halfdist)
def cell_address_under_cursor(self, curx, cury):
"""
@ -595,6 +606,7 @@ class FanChartDescWidget(FanChartBaseWidget):
self.toggle_cell_state(self._mouse_click_cell_address)
self._compute_angles(*self.rootangle_rad)
self._mouse_click = False
self.draw()
self.queue_draw()
def toggle_cell_state(self, cell_address):
@ -647,4 +659,5 @@ class FanChartDescGrampsGUI(FanChartGrampsGUI):
self.generic_filter, self.alpha_filter, self.form,
self.angle_algo, self.dupcolor)
self.fan.reset()
self.fan.draw()
self.fan.queue_draw()

View File

@ -256,7 +256,8 @@ class FanChart2WayView(fanchart2way.FanChart2WayGrampsGUI, NavigationView):
widthpx = 2 * self.fan.halfdist()
heightpx = widthpx
prt = CairoPrintSave(widthpx, heightpx, self.fan.on_draw, self.uistate.window)
prt = CairoPrintSave(widthpx, heightpx, self.fan.prt_draw,
self.uistate.window)
prt.run()
def on_childmenu_changed(self, obj, person_handle):

View File

@ -256,7 +256,8 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
heightpx = heightpx / 2 + self.fan.CENTER + fanchart.PAD_PX
widthpx = heightpx
prt = CairoPrintSave(widthpx, heightpx, self.fan.on_draw, self.uistate.window)
prt = CairoPrintSave(widthpx, heightpx, self.fan.prt_draw,
self.uistate.window)
prt.run()
def on_childmenu_changed(self, obj, person_handle):

View File

@ -252,7 +252,8 @@ class FanChartView(fanchart.FanChartGrampsGUI, NavigationView):
heightpx = heightpx / 2 + self.fan.CENTER + fanchart.PAD_PX
widthpx = heightpx
prt = CairoPrintSave(widthpx, heightpx, self.fan.on_draw, self.uistate.window)
prt = CairoPrintSave(widthpx, heightpx, self.fan.prt_draw,
self.uistate.window)
prt.run()
def on_childmenu_changed(self, obj, person_handle):