4571: RTL support in fanchart: cleanup older code

Use math.degrees() / math.radians() where able

Follow-up to CR by Benny:
    Removed redundant forced conversion to float, the
    	from future import division
    handles that already. See PEP-238 for details.

draw_text:
Remove manual layout wrapping, use pango Layout logic.
Refactored wrap_truncate_layout from draw_arc_text,
and it's now reused in draw_text, here with CHAR
wrapping mode as opposed to WORD in draw_arc_text.
This replaces the (Unicode-wrong) implementation of
manual char-by-char code with text truncation.

svn: r22569
This commit is contained in:
Vassilii Khachaturov 2013-06-23 11:12:13 +00:00
parent 32172f1168
commit 8af57bcf07

View File

@ -555,6 +555,22 @@ class FanChartBaseWidget(Gtk.DrawingArea):
cr.set_source_rgba(r/255., g/255., b/255., a) cr.set_source_rgba(r/255., g/255., b/255., a)
cr.fill() cr.fill()
def wrap_truncate_layout(self, layout, font, width_pixels):
"""Uses the layout to wrap and truncate its text to given width
Returns: (w,h) as returned by layout.get_pixel_size()
"""
layout.set_font_description(font)
layout.set_width(Pango.SCALE * width_pixels)
# NOTE: one may not truncate the text to just the 1st line's text,
# because the truncation can create invalid Unicode.
if layout.get_line_count() > 1:
layout.set_text(layout.get_text(), layout.get_line(0).length)
return layout.get_pixel_size()
def draw_text(self, cr, text, radius, start, stop, def draw_text(self, cr, text, radius, start, stop,
height=PIXELS_PER_GENERATION, radial=False, height=PIXELS_PER_GENERATION, radial=False,
fontcolor=(0, 0, 0), bold=False): fontcolor=(0, 0, 0), bold=False):
@ -568,29 +584,31 @@ class FanChartBaseWidget(Gtk.DrawingArea):
font.set_size(fontsize * Pango.SCALE) font.set_size(fontsize * Pango.SCALE)
if bold: if bold:
font.set_weight(Pango.Weight.BOLD) font.set_weight(Pango.Weight.BOLD)
cr.set_source_rgb(fontcolor[0], fontcolor[1], fontcolor[2]) cr.set_source_rgb(*fontcolor)
if radial and self.radialtext: if radial and self.radialtext:
cr.save() cr.save()
layout = self.create_pango_layout(text) layout = self.create_pango_layout(text)
layout.set_font_description(font) layout.set_font_description(font)
w, h = layout.get_size() layout.set_wrap(Pango.WrapMode.CHAR)
w = w / Pango.SCALE + 5 # 5 pixel padding
h = h / Pango.SCALE + 4 # 4 pixel padding # NOTE: for radial text, the sector radius height is the text width
w, h = self.wrap_truncate_layout(layout, font, height - 2*PAD_TEXT)
w = w + 5 # 5 pixel padding
h = h + 4 # 4 pixel padding
#first we check if height is ok #first we check if height is ok
degneedheight = h / radius * (180 / math.pi) degneedheight = math.degrees(h / radius)
degavailheight = stop-start degavailheight = stop-start
degoffsetheight = 0 degoffsetheight = 0
if degneedheight > degavailheight: if degneedheight > degavailheight:
#reduce height #reduce height
fontsize = degavailheight / degneedheight * fontsize / 2 fontsize = degavailheight / degneedheight * fontsize / 2
font.set_size(fontsize * Pango.SCALE) font.set_size(fontsize * Pango.SCALE)
layout = self.create_pango_layout(text) w, h = self.wrap_truncate_layout(layout, font, height - 2*PAD_TEXT)
layout.set_font_description(font) w = w + 5 # 5 pixel padding
w, h = layout.get_size() h = h + 4 # 4 pixel padding
w = w / Pango.SCALE + 5 # 5 pixel padding
h = h / Pango.SCALE + 4 # 4 pixel padding
#first we check if height is ok #first we check if height is ok
degneedheight = h / radius * (180 / math.pi) degneedheight = math.degrees(h / radius)
degavailheight = stop-start degavailheight = stop-start
if degneedheight > degavailheight: if degneedheight > degavailheight:
#we could not fix it, no text #we could not fix it, no text
@ -598,35 +616,13 @@ class FanChartBaseWidget(Gtk.DrawingArea):
if text: if text:
#spread rest #spread rest
degoffsetheight = (degavailheight - degneedheight) / 2 degoffsetheight = (degavailheight - degneedheight) / 2
txlen = len(text)
if w > height - PAD_TEXT:
txlen = int(w/height * txlen)
cont = True
while cont:
# FIXME this can make an invalid Unicode truncation
# if it comes in between CTL text. Should use the approach
# similar to draw_arc_text() and use layout wrapping logic
# instead, and then reset to proper length.
layout = self.create_pango_layout(text[:txlen])
layout.set_font_description(font)
w, h = layout.get_size()
w = w / Pango.SCALE + 2*PAD_TEXT # padding before/after
h = h / Pango.SCALE + 4 # padding in height text
if w > height:
if txlen <= 1:
cont = False
txlen = 0
else:
txlen -= 1
else:
cont = False
# offset for cairo-font system is 90 # offset for cairo-font system is 90
rotval = self.rotate_value % 360 - 90 rotval = self.rotate_value % 360 - 90
if (start + rotval) % 360 > 179: if (start + rotval) % 360 > 179:
pos = start + degoffsetheight + 90 - 90 pos = start + degoffsetheight + 90 - 90
else: else:
pos = stop - degoffsetheight + 180 pos = stop - degoffsetheight + 180
cr.rotate(pos * math.pi / 180) cr.rotate(math.radians(pos))
layout.context_changed() layout.context_changed()
if (start + rotval) % 360 > 179: if (start + rotval) % 360 > 179:
cr.move_to(radius + PAD_TEXT, 0) cr.move_to(radius + PAD_TEXT, 0)
@ -647,7 +643,7 @@ class FanChartBaseWidget(Gtk.DrawingArea):
""" """
# 1. determine the spread of text we can draw, in radians # 1. determine the spread of text we can draw, in radians
degpadding = PAD_TEXT / radius * (180 / math.pi) # degrees for padding degpadding = math.degrees(PAD_TEXT / radius)
# offset for cairo-font system is 90, padding used is 5: # offset for cairo-font system is 90, padding used is 5:
pos = start + 90 + degpadding/2 pos = start + 90 + degpadding/2
cr.save() cr.save()
@ -656,29 +652,22 @@ class FanChartBaseWidget(Gtk.DrawingArea):
cr.move_to(0, -radius) cr.move_to(0, -radius)
rad_spread = math.radians(stop - start - degpadding) rad_spread = math.radians(stop - start - degpadding)
# 2. use Pango.Layout to set up the text for us, and do # 2. Use Pango.Layout to set up the text for us, and do
# the hard work in CTL text handling and line wrapping. # the hard work in CTL text handling and line wrapping.
layout = self.create_pango_layout(text) # Clip to the top line only so the text looks nice
layout.set_font_description(font)
layout.set_width(Pango.SCALE * radius * rad_spread)
layout.set_wrap(Pango.WrapMode.WORD)
# 3. clip to the top line only so the text looks nice
# all around the circle at the same radius. # all around the circle at the same radius.
# NOTE: one may not truncate the text var here, layout = self.create_pango_layout(text)
# because the truncation can create invalid Unicode. layout.set_wrap(Pango.WrapMode.WORD)
if layout.get_line_count() > 1: w, h = self.wrap_truncate_layout(layout, font, radius * rad_spread)
layout.set_text(text, layout.get_line(0).length)
# 4. Use the layout to provide us the metrics of the text box # 3. Use the layout to provide us the metrics of the text box
PangoCairo.layout_path(cr, layout) PangoCairo.layout_path(cr, layout)
w, h = layout.get_pixel_size()
#le = layout.get_line(0).get_pixel_extents()[0] #le = layout.get_line(0).get_pixel_extents()[0]
pe = cr.path_extents() pe = cr.path_extents()
arc_used_ratio = w / (radius * rad_spread) arc_used_ratio = w / (radius * rad_spread)
rad_mid = math.radians(pos) + rad_spread/2 rad_mid = math.radians(pos) + rad_spread/2
# 5. The moment of truth: map the text box onto the sector, and render! # 4. The moment of truth: map the text box onto the sector, and render!
warpPath(cr, \ warpPath(cr, \
self.create_map_rect_to_sector(radius, pe, \ self.create_map_rect_to_sector(radius, pe, \
arc_used_ratio, rad_mid - rad_spread/2, rad_mid + rad_spread/2)) arc_used_ratio, rad_mid - rad_spread/2, rad_mid + rad_spread/2))
@ -701,8 +690,8 @@ class FanChartBaseWidget(Gtk.DrawingArea):
x0, y0, w, h = rect[0], rect[1], rect[2]-rect[0], rect[3]-rect[1] x0, y0, w, h = rect[0], rect[1], rect[2]-rect[0], rect[3]-rect[1]
radiusin = radius - h/2.0 radiusin = radius - h/2
radiusout = radius + h/2.0 radiusout = radius + h/2
drho = h drho = h
dphi = (stop_rad - start_rad) dphi = (stop_rad - start_rad)
@ -938,7 +927,7 @@ class FanChartBaseWidget(Gtk.DrawingArea):
end_angle = math.pi + (math.pi + end_angle) end_angle = math.pi + (math.pi + end_angle)
# now look at change in angle: # now look at change in angle:
diff_angle = (end_angle - start_angle) % (math.pi * 2.0) diff_angle = (end_angle - start_angle) % (math.pi * 2.0)
self.rotate_value -= diff_angle * 180.0/ math.pi self.rotate_value -= math.degrees(diff_angle)
self.last_x, self.last_y = event.x, event.y self.last_x, self.last_y = event.x, event.y
self.queue_draw() self.queue_draw()
return True return True
@ -1270,7 +1259,7 @@ class FanChartWidget(FanChartBaseWidget):
cr.translate(self.center_x, self.center_y) cr.translate(self.center_x, self.center_y)
cr.save() cr.save()
cr.rotate(self.rotate_value * math.pi/180) cr.rotate(math.radians(self.rotate_value))
for generation in range(self.generations - 1, 0, -1): for generation in range(self.generations - 1, 0, -1):
for p in range(len(self.data[generation])): for p in range(len(self.data[generation])):
(text, person, parents, child, userdata) = self.data[generation][p] (text, person, parents, child, userdata) = self.data[generation][p]
@ -1327,8 +1316,8 @@ class FanChartWidget(FanChartBaseWidget):
position in the chart position in the chart
""" """
cr.save() cr.save()
start_rad = start * math.pi/180 start_rad = math.radians(start)
stop_rad = stop * math.pi/180 stop_rad = math.radians(stop)
r, g, b, a = self.background_box(person, generation, userdata) r, g, b, a = self.background_box(person, generation, userdata)
radius = generation * PIXELS_PER_GENERATION + self.CENTER radius = generation * PIXELS_PER_GENERATION + self.CENTER
# If max generation, and they have parents: # If max generation, and they have parents:
@ -1382,7 +1371,7 @@ class FanChartWidget(FanChartBaseWidget):
radial = False radial = False
radstart = radius - PIXELS_PER_GENERATION/2 radstart = radius - PIXELS_PER_GENERATION/2
if self.radialtext: ## and generation >= 6: if self.radialtext: ## and generation >= 6:
spacepolartext = radstart * (stop-start)*math.pi/180 spacepolartext = radstart * math.radians(stop-start)
if spacepolartext < PIXELS_PER_GENERATION * 1.1: if spacepolartext < PIXELS_PER_GENERATION * 1.1:
# more space to print it radial # more space to print it radial
radial = True radial = True