# # Python GUI - Fonts - Gtk # from __future__ import division import sys import pango, gtk from gtk import gdk from GUI import export from GUI.GFonts import Font as GFont class Font(GFont): #_gdk_font = None _pango_font = None _pango_metrics = None _pango_layout = None # def _from_gdk_font(cls, gdk_font): # font = cls.__new__(cls) # font._gdk_font = gdk_font # return font # # _from_gdk_font = classmethod(_from_gdk_font) def _from_pango_description(cls, pango_description): font = cls.__new__(cls) font._pango_description = pango_description return font _from_pango_description = classmethod(_from_pango_description) def __init__(self, family, size = 12, style = []): if 'italic' in style: pango_style = pango.STYLE_ITALIC else: pango_style = pango.STYLE_NORMAL if 'bold' in style: pango_weight = pango.WEIGHT_BOLD else: pango_weight = pango.WEIGHT_NORMAL jigger = _find_size_correction_factor(family, pango_style, pango_weight) pfd = pango.FontDescription() pfd.set_family(family) pfd.set_size(int(round(jigger * size * pango.SCALE))) pfd.set_style(pango_style) pfd.set_weight(pango_weight) self._pango_description = pfd def get_family(self): return self._pango_description.get_family() def get_size(self): return self._pango_description.get_size() / pango.SCALE def get_style(self): style = [] pfd = self._pango_description if pfd.get_weight() > pango.WEIGHT_NORMAL: style.append('bold') if pfd.get_style() <> pango.STYLE_NORMAL: style.append('italic') return style def get_ascent(self): self._get_pango_metrics() result = self._ascent return result def get_descent(self): self._get_pango_metrics() return self._descent def get_height(self): self._get_pango_metrics() return self._ascent + self._descent def get_line_height(self): return self.get_height() def _get_pango_metrics(self): #print "Font._get_pango_metrics: enter" ### pfm = self._pango_metrics if not pfm: pf = self._get_pango_font() pfm = pf.get_metrics() self._pango_metrics = pfm self._ascent = pfm.get_ascent() / pango.SCALE self._descent = pfm.get_descent() / pango.SCALE return pfm def _get_pango_font(self): pf = self._pango_font if not pf: pf = _pango_context.load_font(self._pango_description) if not pf: raise ValueError("Unable to load Pango font for %s" % self) self._pango_font = pf return pf def width(self, s, start = 0, end = sys.maxint): layout = self._get_pango_layout(s[start:end], True) return layout.get_pixel_size()[0] def text_size(self, text): layout = self._get_pango_layout(text, False) return layout.get_pixel_size() #w, h = layout.get_size() #u = pango.SCALE #return (w / u, h / u) def x_to_pos(self, s, x): layout = self._get_pango_layout(s, True) return pango_layout.xy_to_index(x, 0) def _get_pango_layout(self, text, single_paragraph_mode): layout = self._pango_layout if not layout: layout = pango.Layout(_pango_context) layout.set_font_description(self._pango_description) self._pango_layout = layout layout.set_single_paragraph_mode(single_paragraph_mode) layout.set_text(text) return layout _pango_context = gtk.Label().create_pango_context() _jigger_cache = {} def _find_size_correction_factor(family, pango_style, pango_weight): # Unlike the rest of the world, Pango seems to consider the point # size of a font to only include the ascent. So we first ask for # a 1-point font, find the ratio of its ascent to its descent, # and use that to adjust the size requested by the user. key = (family, pango_style, pango_weight) result = _jigger_cache.get(key) if result is None: pd = pango.FontDescription() pd.set_family(family) pd.set_size(pango.SCALE) pd.set_style(pango_style) pd.set_weight(pango_weight) pf = _pango_context.load_font(pd) pm = pf.get_metrics() a = pm.get_ascent() d = pm.get_descent() result = a / (a + d) #print "Jigger factor for font:", family, pango_style, pango_weight ### #print "ascent =", a, "descent =", d, "factor =", result ### _jigger_cache[key] = result return result export(Font)