# Text formatting abstractions
# Note -- this module is obsolete, it's too slow anyway
# A formatter back-end object has one method that is called by the formatter:
# addpara(p), where p is a paragraph object. For example:
# Formatter back-end to do nothing at all with the paragraphs
def bgn_anchor(self
, id):
def end_anchor(self
, id):
# Formatter back-end to collect the paragraphs in a list
class SavingBackEnd(NullBackEnd
):
def hitcheck(self
, h
, v
):
if p
.top
<= v
<= p
.bottom
:
for id in p
.hitcheck(h
, v
):
text
= text
+ (p
.extract())
def extractpart(self
, long1
, long2
):
if long1
> long2
: long1
, long2
= long2
, long1
ptext
= self
.paralist
[para1
].extract()
text
= text
+ ptext
[pos1
:]
ptext
= self
.paralist
[para2
].extract()
return text
+ ptext
[pos1
:pos2
]
def whereis(self
, d
, h
, v
):
for i
in range(len(self
.paralist
)):
result
= p
.whereis(d
, h
, v
)
def roundtowords(self
, long1
, long2
):
text
= self
.paralist
[i
].extract()
while offset
> 0 and text
[offset
-1] != ' ': offset
= offset
-1
text
= self
.paralist
[i
].extract()
while offset
< n
-1 and text
[offset
] != ' ': offset
= offset
+1
def roundtoparagraphs(self
, long1
, long2
):
long2
= long2
[0], len(self
.paralist
[long2
[0]].extract())
# Formatter back-end to send the text directly to the drawing object
class WritingBackEnd(NullBackEnd
):
def __init__(self
, d
, width
):
self
.lineno
= p
.render(self
.d
, 0, self
.lineno
, self
.width
)
# A formatter receives a stream of formatting instructions and assembles
# these into a stream of paragraphs on to a back-end. The assembly is
# parametrized by a text measurement object, which must match the output
# operations of the back-end. The back-end is responsible for splitting
# paragraphs up in lines of a given maximum width. (This is done because
# in a windowing environment, when the window size changes, there is no
# need to redo the assembly into paragraphs, but the splitting into lines
# must be done taking the new window size into account.)
# Formatter base class. Initialize it with a text measurement object,
# which is used for text measurements, and a back-end object,
# which receives the completed paragraphs. The formatting methods are:
# setjust(type) where type is 'l', 'c', 'r', or 'lr'
def __init__(self
, d
, b
):
# Drawing object used for text measurements
# BackEnd object receiving completed paragraphs
# Parameters of the formatting model
# Parameters derived from the current font
self
.space
= d
.textwidth(' ')
self
.line
= d
.lineheight()
self
.ascent
= d
.baseline()
self
.descent
= self
.line
- self
.ascent
# Parameter derived from the default font
self
.n_space
= self
.space
# Current paragraph being built
# Font to set on the next word
self
.font
= self
.nextfont
= font
self
.space
= d
.textwidth(' ')
self
.line
= d
.lineheight()
self
.ascent
= d
.baseline()
self
.descent
= self
.line
- self
.ascent
def setleftindent(self
, nspaces
):
self
.leftindent
= int(self
.n_space
* nspaces
)
hang
= self
.leftindent
- self
.para
.indent_left
if hang
> 0 and self
.para
.getlength() <= hang
:
self
.para
.makehangingtag(hang
)
def setrightindent(self
, nspaces
):
self
.rightindent
= int(self
.n_space
* nspaces
)
self
.para
.indent_right
= self
.rightindent
self
.para
.just
= self
.just
self
.b
.addpara(self
.para
)
if self
.font
is not None:
self
.d
.setfont(self
.font
)
def vspace(self
, nlines
):
self
.para
= self
.newpara()
tuple = None, '', 0, 0, 0, int(nlines
*self
.line
), 0
self
.para
.words
.append(tuple)
self
.blanklines
= self
.blanklines
+ nlines
def needvspace(self
, nlines
):
self
.flush() # Just to be sure
if nlines
> self
.blanklines
:
self
.vspace(nlines
- self
.blanklines
)
def addword(self
, text
, space
):
if self
.nospace
and not text
:
self
.para
= self
.newpara()
self
.para
.indent_left
= self
.leftindent
self
.para
.just
= self
.just
self
.nextfont
= self
.font
space
= int(space
* self
.space
)
self
.para
.words
.append((self
.nextfont
, text
,
self
.d
.textwidth(text
), space
, space
,
self
.ascent
, self
.descent
))
def bgn_anchor(self
, id):
def end_anchor(self
, id):
# Measuring object for measuring text as viewed on a tty
def textwidth(self
, text
):
# Drawing object for writing plain ASCII text to a file
self
.lineno
, self
.colno
= 0, 0
def text(self
, (h
, v
), str):
raise ValueError, 'can\'t write \\n'
self
.colno
, self
.lineno
= 0, self
.lineno
+ 1
# XXX This should never happen...
self
.fp
.write('\033[A') # ANSI up arrow
self
.lineno
= self
.lineno
- 1
self
.fp
.write(' ' * (h
- self
.colno
))
self
.fp
.write('\b' * (self
.colno
- h
))
self
.colno
= h
+ len(str)
# Formatting class to do nothing at all with the data
class NullFormatter(BaseFormatter
):
BaseFormatter
.__init
__(self
, d
, b
)
# Formatting class to write directly to a file
class WritingFormatter(BaseFormatter
):
def __init__(self
, fp
, width
):
b
= WritingBackEnd(dw
, width
)
BaseFormatter
.__init
__(self
, dm
, b
)
# Suppress multiple blank lines
def needvspace(self
, nlines
):
BaseFormatter
.needvspace(self
, min(1, nlines
))
# A "FunnyFormatter" writes ASCII text with a twist: *bold words*,
# _italic text_ and _underlined words_, and `quoted text'.
# It assumes that the fonts are 'r', 'i', 'b', 'u', 'q': (roman,
# italic, bold, underline, quote).
# Moreover, if the font is in upper case, the text is converted to
class FunnyFormatter(WritingFormatter
):
if self
.para
: finalize(self
.para
)
WritingFormatter
.flush(self
)
# Surrounds *bold words* and _italic text_ in a paragraph with
# appropriate markers, fixing the size (assuming these characters'
{'b':'*', 'i':'_', 'u':'_', 'q':'`', 'B':'*', 'I':'_', 'U':'_', 'Q':'`'}
{'b':'*', 'i':'_', 'u':'_', 'q':'\'', 'B':'*', 'I':'_', 'U':'_', 'Q':'\''}
para
.words
.append(('r', '', 0, 0, 0, 0)) # temporary, deleted at end
for i
in range(len(para
.words
)):
fo
, te
, wi
= para
.words
[i
][:3]
if fo
is not None: curfont
= fo
if closechar
.has_key(oldfont
):
while j
> 0 and para
.words
[j
][1] == '': j
= j
-1
fo1
, te1
, wi1
= para
.words
[j
][:3]
para
.words
[j
] = (fo1
, te1
, wi1
) + \
if openchar
.has_key(curfont
) and te
:
para
.words
[i
] = (fo
, te
, wi
) + \
if curfont
in string
.uppercase
:
para
.words
[i
] = (fo
, te
, wi
) + para
.words
[i
][3:]
# Formatter back-end to draw the text in a window.
# This has an option to draw while the paragraphs are being added,
# to minimize the delay before the user sees anything.
# This manages the entire "document" of the window.
class StdwinBackEnd(SavingBackEnd
):
def __init__(self
, window
, drawnow
):
self
.width
= window
.getwinsize()[0]
self
.d
= window
.begindrawing()
SavingBackEnd
.__init
__(self
)
self
.window
.setdocsize(0, self
.height
)
p
.render(self
.d
, 0, self
.height
, self
.width
)
p
.bottom
= self
.height
+ p
.height
self
.window
.change((0, 0), (self
.width
, self
.height
))
self
.width
= self
.window
.getwinsize()[0]
p
.bottom
= self
.height
+ p
.height
self
.window
.change((0, 0), (self
.width
, self
.height
))
self
.window
.setdocsize(0, self
.height
)
d
= self
.window
.begindrawing()
(left
, top
), (right
, bottom
) = area
if top
< p
.bottom
and p
.top
< bottom
:
v
= p
.render(d
, p
.left
, p
.top
, p
.right
)
self
.invert(d
, self
.selection
)
def setselection(self
, new
):
if new
!= self
.selection
:
d
= self
.window
.begindrawing()
self
.invert(d
, self
.selection
)
def extractselection(self
):
return self
.extractpart(a
, b
)
def invert(self
, d
, region
):
if long1
> long2
: long1
, long2
= long2
, long1
self
.paralist
[para1
].invert(d
, pos1
, None)
self
.paralist
[para2
].invert(d
, pos1
, pos2
)
if type(prog
) is type(''):
prog
= re
.compile(string
.lower(prog
))
iold
= self
.selection
[0][0]
for i
in range(len(self
.paralist
)):
if i
== iold
or i
< iold
and hit
:
text
= string
.lower(p
.extract())
match
= prog
.search(text
)
self
.window
.show((p
.left
, p
.top
), (p
.right
, p
.bottom
))
def showanchor(self
, id):
for i
in range(len(self
.paralist
)):
long2
= i
, len(p
.extract())
(p
.left
, p
.top
), (p
.right
, p
.bottom
))
def setfont(self
, fontkey
):
fontkey
= 'Times-Roman 12'
fontkey
= fontkey
+ ' 12'
if fontkey
== self
.fontkey
:
if self
.fontcache
.has_key(fontkey
):
handle
= self
.fontcache
[fontkey
]
i
= string
.index(fontkey
, ' ')
name
, sizestr
= fontkey
[:i
], fontkey
[i
:]
key
= name
+ ' ' + `size`
# NB key may differ from fontkey!
if self
.fontcache
.has_key(key
):
handle
= self
.fontcache
[key
]
if self
.fontcache
.has_key(key1
):
handle
= self
.fontcache
[key1
]
handle
= fm
.findfont(name
)
self
.fontcache
[key1
] = handle
handle
= handle
.scalefont(size
)
self
.fontcache
[fontkey
] = \
self
.fontcache
[key
] = handle
if self
.fonthandle
!= handle
:
self
.fontinfo
= handle
.getfontinfo()
class GLMeasurer(GLFontCache
):
def textwidth(self
, text
):
return self
.fonthandle
.getstrwidth(text
)
return self
.fontinfo
[6] - self
.fontinfo
[3]
class GLWriter(GLFontCache
):
# (1) Use gl.ortho2 to use X pixel coordinates!
def text(self
, (h
, v
), text
):
gl
.cmov2i(h
, v
+ self
.fontinfo
[6] - self
.fontinfo
[3])
def setfont(self
, fontkey
):
oldhandle
= self
.fonthandle
GLFontCache
.setfont(fontkey
)
if self
.fonthandle
!= oldhandle
:
class GLMeasurerWriter(GLMeasurer
, GLWriter
):
class GLBackEnd(SavingBackEnd
):
self
.width
= gl
.getsize()[1]
self
.d
= GLMeasurerWriter()
SavingBackEnd
.__init
__(self
)
self
.height
= p
.render(self
.d
, 0, self
.height
, self
.width
)
v
= p
.render(d
, 0, v
, width
)