Copied/merged from the 2.2 branch.
Changes needed to build with new event system git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@9374 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
249
wxPython/wxPython/lib/fancytext.py
Normal file
249
wxPython/wxPython/lib/fancytext.py
Normal file
@@ -0,0 +1,249 @@
|
||||
"""wxFancyText -- methods for rendering XML specified text
|
||||
|
||||
This module has four main methods:
|
||||
|
||||
def getExtent(str, dc=None, enclose=1):
|
||||
def renderToBitmap(str, background=None, enclose=1)
|
||||
def renderToDC(str, dc, x, y, enclose=1)
|
||||
|
||||
In all cases, 'str' is an XML string. The tags in the string can
|
||||
currently specify the font, subscripts, superscripts, and the angle
|
||||
sign. The allowable properties of font are size, family, style, weght,
|
||||
encoding, and color. See the example on the bottom for a better idea
|
||||
of how this works.
|
||||
|
||||
Note that start and end tags for the string are provided if enclose is
|
||||
true, so for instance, renderToBitmap("X<sub>1</sub>") will work.
|
||||
|
||||
"""
|
||||
# Copyright 2001 Timothy Hochberg
|
||||
# Use as you see fit. No warantees, I cannot be held responsible, etc.
|
||||
|
||||
|
||||
|
||||
# TODO: Make a wxFancyTextCtrl class that derives from wxControl.
|
||||
# Add support for line breaks
|
||||
# etc.
|
||||
# - Robin
|
||||
|
||||
|
||||
|
||||
from wxPython.wx import *
|
||||
import xml.parsers.expat, copy
|
||||
|
||||
_families = {"default" : wxDEFAULT, "decorative" : wxDECORATIVE, "roman" : wxROMAN,
|
||||
"swiss" : wxSWISS, "modern" : wxMODERN}
|
||||
_styles = {"normal" : wxNORMAL, "slant" : wxSLANT, "italic" : wxITALIC}
|
||||
_weights = {"normal" : wxNORMAL, "light" : wxLIGHT, "bold" : wxBOLD}
|
||||
|
||||
# The next three classes: Renderer, SizeRenderer and DCRenderer are
|
||||
# what you will need to override to extend the XML language. All of
|
||||
# the font stuff as well as the subscript and superscript stuff are in
|
||||
# Renderer.
|
||||
|
||||
class Renderer:
|
||||
|
||||
defaultSize = wxNORMAL_FONT.GetPointSize()
|
||||
defaultFamily = wxDEFAULT
|
||||
defaultStyle = wxNORMAL
|
||||
defaultWeight = wxNORMAL
|
||||
defaultEncoding = wxFont_GetDefaultEncoding()
|
||||
defaultColor = "black"
|
||||
|
||||
def __init__(self, dc=None):
|
||||
if dc == None:
|
||||
dc = wxMemoryDC()
|
||||
self.dc = dc
|
||||
self.offsets = [0]
|
||||
self.fonts = [{}]
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
method = "start_" + name
|
||||
if not hasattr(self, method):
|
||||
raise ValueError("XML tag '%s' not supported" % name)
|
||||
getattr(self, method)(attrs)
|
||||
|
||||
def endElement(self, name):
|
||||
method = "end_" + name
|
||||
if not hasattr(self, method):
|
||||
raise ValueError("XML tag '%s' not supported" % name)
|
||||
getattr(self, method)()
|
||||
|
||||
def start_wxFancyString(self, attrs):
|
||||
pass
|
||||
|
||||
def end_wxFancyString(self):
|
||||
pass
|
||||
|
||||
def start_font(self, attrs):
|
||||
for key, value in attrs.items():
|
||||
if key == "size":
|
||||
value = int(value)
|
||||
elif key == "family":
|
||||
value = _families[value]
|
||||
elif key == "style":
|
||||
value = _styles[value]
|
||||
elif key == "weight":
|
||||
value = _weights[value]
|
||||
elif key == "encoding":
|
||||
pass
|
||||
elif key == "color":
|
||||
pass
|
||||
else:
|
||||
raise ValueError("unknown font attribute '%s'" % key)
|
||||
attrs[key] = value
|
||||
font = copy.copy(self.fonts[-1])
|
||||
font.update(attrs)
|
||||
self.fonts.append(font)
|
||||
|
||||
def end_font(self):
|
||||
self.fonts.pop()
|
||||
|
||||
def start_sub(self, attrs):
|
||||
if attrs.keys():
|
||||
raise ValueError("<sub> does not take attributes")
|
||||
font = self.getCurrentFont()
|
||||
self.offsets.append(self.offsets[-1] + self.dc.GetFullTextExtent("M", font)[1]*0.5)
|
||||
self.start_font({"size" : font.GetPointSize() * 0.8})
|
||||
|
||||
def end_sub(self):
|
||||
self.fonts.pop()
|
||||
self.offsets.pop()
|
||||
|
||||
def start_sup(self, attrs):
|
||||
if attrs.keys():
|
||||
raise ValueError("<sup> does not take attributes")
|
||||
font = self.getCurrentFont()
|
||||
self.offsets.append(self.offsets[-1] - self.dc.GetFullTextExtent("M", font)[1]*0.3)
|
||||
self.start_font({"size" : font.GetPointSize() * 0.8})
|
||||
|
||||
def end_sup(self):
|
||||
self.fonts.pop()
|
||||
self.offsets.pop()
|
||||
|
||||
def getCurrentFont(self):
|
||||
font = self.fonts[-1]
|
||||
return wxFont(font.get("size", self.defaultSize),
|
||||
font.get("family", self.defaultFamily),
|
||||
font.get("style", self.defaultStyle),
|
||||
font.get("weight", self.defaultWeight),
|
||||
encoding = font.get("encoding", self.defaultEncoding))
|
||||
|
||||
def getCurrentColor(self):
|
||||
font = self.fonts[-1]
|
||||
return wxNamedColour(font.get("color", self.defaultColor))
|
||||
|
||||
|
||||
class SizeRenderer(Renderer):
|
||||
|
||||
def __init__(self, dc=None):
|
||||
Renderer.__init__(self, dc)
|
||||
self.width = self.height = 0
|
||||
self.minY = self.maxY = 0
|
||||
|
||||
def characterData(self, data):
|
||||
self.dc.SetFont(self.getCurrentFont())
|
||||
width, height = self.dc.GetTextExtent(data)
|
||||
self.width = self.width + width
|
||||
self.minY = min(self.minY, self.offsets[-1])
|
||||
self.maxY = max(self.maxY, self.offsets[-1] + height)
|
||||
self.height = self.maxY - self.minY
|
||||
|
||||
def start_angle(self, attrs):
|
||||
self.characterData("M")
|
||||
|
||||
def end_angle(self):
|
||||
pass
|
||||
|
||||
class DCRenderer(Renderer):
|
||||
|
||||
def __init__(self, dc=None, x=0, y=0):
|
||||
Renderer.__init__(self, dc)
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
def characterData(self, data):
|
||||
self.dc.SetFont(self.getCurrentFont())
|
||||
self.dc.SetTextForeground(self.getCurrentColor())
|
||||
width, height = self.dc.GetTextExtent(data)
|
||||
self.dc.DrawText(data, self.x, self.y + self.offsets[-1])
|
||||
self.x = self.x + width
|
||||
|
||||
def start_angle(self, attrs):
|
||||
self.dc.SetFont(self.getCurrentFont())
|
||||
self.dc.SetPen(wxPen(self.getCurrentColor(), 1))
|
||||
width, height, descent, leading = self.dc.GetFullTextExtent("M")
|
||||
y = self.y + self.offsets[-1] + height - descent
|
||||
self.dc.DrawLine(self.x, y, self.x+width, y)
|
||||
self.dc.DrawLine(self.x, y, self.x+width, y-width)
|
||||
self.x = self.x + width
|
||||
|
||||
def end_angle(self):
|
||||
pass
|
||||
|
||||
# This is a rendering function that is primarily used internally,
|
||||
# although it could be used externally if one had overridden the
|
||||
# Renderer classes.
|
||||
|
||||
def renderToRenderer(str, renderer, enclose=1):
|
||||
if enclose:
|
||||
str = '<?xml version="1.0"?><wxFancyString>%s</wxFancyString>' % str
|
||||
p = xml.parsers.expat.ParserCreate()
|
||||
p.returns_unicode = 0
|
||||
p.StartElementHandler = renderer.startElement
|
||||
p.EndElementHandler = renderer.endElement
|
||||
p.CharacterDataHandler = renderer.characterData
|
||||
p.Parse(str, 1)
|
||||
|
||||
|
||||
def getExtent(str, dc=None, enclose=1):
|
||||
"Return the extent of str"
|
||||
renderer = SizeRenderer(dc)
|
||||
renderToRenderer(str, renderer, enclose)
|
||||
return wxSize(renderer.width, renderer.height)
|
||||
|
||||
# This should probably only be used internally....
|
||||
|
||||
def getFullExtent(str, dc=None, enclose=1):
|
||||
renderer = SizeRenderer(dc)
|
||||
renderToRenderer(str, renderer, enclose)
|
||||
return renderer.width, renderer.height, -renderer.minY
|
||||
|
||||
def renderToBitmap(str, background=None, enclose=1):
|
||||
"Return str rendered on a minumum size bitmap"
|
||||
dc = wxMemoryDC()
|
||||
width, height, dy = getFullExtent(str, dc)
|
||||
bmp = wxEmptyBitmap(width, height)
|
||||
dc.SelectObject(bmp)
|
||||
if background is not None:
|
||||
dc.SetBackground(background)
|
||||
dc.Clear()
|
||||
renderer = DCRenderer(dc, y=dy)
|
||||
dc.BeginDrawing()
|
||||
renderToRenderer(str, renderer, enclose)
|
||||
dc.EndDrawing()
|
||||
dc.SelectObject(wxNullBitmap)
|
||||
return bmp
|
||||
|
||||
def renderToDC(str, dc, x, y, enclose=1):
|
||||
"Render str onto a wxDC at (x,y)"
|
||||
width, height, dy = getFullExtent(str, dc)
|
||||
renderer = DCRenderer(dc, x, y+dy)
|
||||
renderToRenderer(str, renderer, enclose)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
str = ('<font style="italic" family="swiss" color="red" weight="bold" >some |<sup>23</sup> <angle/>text<sub>with <angle/> subscript</sub> </font> some other text'
|
||||
'<font family="swiss" color="green" size="40">big green text</font>')
|
||||
ID_EXIT = 102
|
||||
class myApp(wxApp):
|
||||
def OnInit(self):
|
||||
return 1
|
||||
app = myApp()
|
||||
frame = wxFrame(NULL, -1, "wxFancyText demo", wxDefaultPosition)
|
||||
frame.SetClientSize(getExtent(str))
|
||||
bmp = renderToBitmap(str, wxCYAN_BRUSH)
|
||||
sb = wxStaticBitmap(frame, -1, bmp)
|
||||
EVT_MENU(frame, ID_EXIT, frame.Destroy)
|
||||
frame.Show(1)
|
||||
app.MainLoop()
|
Reference in New Issue
Block a user