]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Initial revision
authorGuido van Rossum <guido@python.org>
Tue, 14 May 1991 12:25:35 +0000 (12:25 +0000)
committerGuido van Rossum <guido@python.org>
Tue, 14 May 1991 12:25:35 +0000 (12:25 +0000)
Lib/lib-stdwin/formatter.py [new file with mode: 0644]
Lib/stdwin/formatter.py [new file with mode: 0755]

diff --git a/Lib/lib-stdwin/formatter.py b/Lib/lib-stdwin/formatter.py
new file mode 100644 (file)
index 0000000..9bfbe6b
--- /dev/null
@@ -0,0 +1,204 @@
+# A class to help applications that do fancy text formatting.
+# You create an instance each time you must redraw the window.
+# Set the initial left, top and right coordinates;
+# then feed it words, font changes and vertical movements.
+#
+# This class should eventually be extended to support much fancier
+# formatting, along the lines of TeX; for now, a very simple model
+# is sufficient.
+#
+class formatter():
+       #
+       # Initialize a formatter instance.
+       # Pass the window's drawing object, and left, top, right
+       # coordinates of the drawing space as arguments.
+       #
+       def init(self, (d, left, top, right)):
+               self.d = d              # Drawing object
+               self.left = left        # Left margin
+               self.right = right      # Right margin
+               self.v = top            # Top of current line
+               self.center = 0
+               self.justify = 1
+               self.setfont('')        # Current font
+               self._reset()           # Prepare for new line
+               return self
+       #
+       # Reset for start of fresh line.
+       #
+       def _reset(self):
+               self.boxes = []         # Boxes and glue still to be output
+               self.sum_width = 0      # Total width of boxes
+               self.sum_space = 0      # Total space between boxes
+               self.sum_stretch = 0    # Total stretch for space between boxes
+               self.max_ascent = 0     # Max ascent of current line
+               self.max_descent = 0    # Max descent of current line
+               self.avail_width = self.right - self.left
+               self.hang_indent = 0
+       #
+       # Set the current font, and compute some values from it.
+       #
+       def setfont(self, font):
+               self.font = font
+               self.d.setfont(font)
+               self.font_space = self.d.textwidth(' ')
+               self.font_ascent = self.d.baseline()
+               self.font_descent = self.d.lineheight() - self.font_ascent
+       #
+       # Add a word to the list of boxes; first flush if line is full.
+       # Space and stretch factors are expressed in fractions
+       # of the current font's space width.
+       # (Two variations: one without, one with explicit stretch factor.)
+       #
+       def addword(self, (word, spacefactor)):
+               self.addwordstretch(word, spacefactor, spacefactor)
+       #
+       def addwordstretch(self, (word, spacefactor, stretchfactor)):
+               width = self.d.textwidth(word)
+               if width > self.avail_width:
+                       self._flush(1)
+               space = int(float(self.font_space) * float(spacefactor))
+               stretch = int(float(self.font_space) * float(stretchfactor))
+               box = (self.font, word, width, space, stretch)
+               self.boxes.append(box)
+               self.sum_width = self.sum_width + width
+               self.sum_space = self.sum_space + space
+               self.sum_stretch = self.sum_stretch + stretch
+               self.max_ascent = max(self.font_ascent, self.max_ascent)
+               self.max_descent = max(self.font_descent, self.max_descent)
+               self.avail_width = self.avail_width - width - space
+       #
+       # Flush current line and start a new one.
+       # Flushing twice is harmless (i.e. does not introduce a blank line).
+       # (Two versions: the internal one has a parameter for justification.)
+       #
+       def flush(self):
+               self._flush(0)
+       #
+       def _flush(self, justify):
+               if not self.boxes:
+                       return
+               #
+               # Compute amount of stretch needed.
+               #
+               if justify and self.justify or self.center:
+                       #
+                       # Compute extra space to fill;
+                       # this is avail_width plus glue from last box.
+                       # Also compute available stretch.
+                       #
+                       last_box = self.boxes[len(self.boxes)-1]
+                       font, word, width, space, stretch = last_box
+                       tot_extra = self.avail_width + space
+                       tot_stretch = self.sum_stretch - stretch
+               else:
+                       tot_extra = tot_stretch = 0
+               #
+               # Output the boxes.
+               #
+               baseline = self.v + self.max_ascent
+               h = self.left + self.hang_indent
+               if self.center:
+                       h = h + tot_extra / 2
+                       tot_extra = tot_stretch = 0
+               for font, word, width, space, stretch in self.boxes:
+                       self.d.setfont(font)
+                       v = baseline - self.d.baseline()
+                       self.d.text((h, v), word)
+                       h = h + width + space
+                       if tot_extra > 0 and tot_stretch > 0:
+                               extra = stretch * tot_extra / tot_stretch
+                               h = h + extra
+                               tot_extra = tot_extra - extra
+                               tot_stretch = tot_stretch - stretch
+               #
+               # Prepare for next line.
+               #
+               self.v = baseline + self.max_descent
+               self.d.setfont(self.font)
+               self._reset()
+       #
+       # Add vertical space; first flush.
+       # Vertical space is expressed in fractions of the current
+       # font's line height.
+       #
+       def vspace(self, dy):
+               self.flush()
+               dy = int(float(dy) * float(self.d.lineheight()))
+               self.v = self.v + dy
+       #
+       # Set temporary (hanging) indent, for paragraph start.
+       # First flush.
+       #
+       def tempindent(self, space):
+               self.flush()
+               hang = int(float(self.font_space) * float(space))
+               self.hang_indent = hang
+               self.avail_width = self.avail_width - hang
+       #
+       # Add (permanent) left indentation.  First flush.
+       #
+       def addleftindent(self, space):
+               self.flush()
+               self.left = self.left \
+                       + int(float(self.font_space) * float(space))
+               self._reset()
+       #
+
+
+# Test procedure
+#
+def test():
+       import stdwin
+       from stdwinevents import *
+       try:
+               import mac
+               # Mac font assignments:
+               font1 = 'times', '', 12
+               font2 = 'times', 'b', 14
+       except NameError:
+               # X11R4 font assignments
+               font1 = '*times-medium-r-*-120-*'
+               font2 = '*times-bold-r-*-140-*'
+       words = \
+           ['The','quick','brown','fox','jumps','over','the','lazy','dog.']
+       words = words * 2
+       stage = 0
+       stages = [(0,0,'ragged'), (1,0,'justified'), (0,1,'centered')]
+       justify, center, title = stages[stage]
+       stdwin.setdefwinsize(300,200)
+       w = stdwin.open(title)
+       winsize = w.getwinsize()
+       while 1:
+               type, window, detail = stdwin.getevent()
+               if type = WE_CLOSE:
+                       break
+               elif type = WE_SIZE:
+                       newsize = w.getwinsize()
+                       if newsize <> winsize:
+                               w.change((0,0), winsize)
+                               winsize = newsize
+                               w.change((0,0), winsize)
+               elif type = WE_MOUSE_DOWN:
+                       stage = (stage + 1) % len(stages)
+                       justify, center, title = stages[stage]
+                       w.settitle(title)
+                       w.change((0, 0), (1000, 1000))
+               elif type = WE_DRAW:
+                       width, height = winsize
+                       f = formatter().init(w.begindrawing(), 0, 0, width)
+                       f.center = center
+                       f.justify = justify
+                       if not center:
+                               f.tempindent(5)
+                       for font in font1, font2, font1:
+                               f.setfont(font)
+                               for word in words:
+                                       space = 1 + (word[-1:] = '.')
+                                       f.addword(word, space)
+                                       if center and space > 1:
+                                               f.flush()
+                       f.flush()
+                       height = f.v
+                       del f
+                       w.setdocsize(0, height)
diff --git a/Lib/stdwin/formatter.py b/Lib/stdwin/formatter.py
new file mode 100755 (executable)
index 0000000..9bfbe6b
--- /dev/null
@@ -0,0 +1,204 @@
+# A class to help applications that do fancy text formatting.
+# You create an instance each time you must redraw the window.
+# Set the initial left, top and right coordinates;
+# then feed it words, font changes and vertical movements.
+#
+# This class should eventually be extended to support much fancier
+# formatting, along the lines of TeX; for now, a very simple model
+# is sufficient.
+#
+class formatter():
+       #
+       # Initialize a formatter instance.
+       # Pass the window's drawing object, and left, top, right
+       # coordinates of the drawing space as arguments.
+       #
+       def init(self, (d, left, top, right)):
+               self.d = d              # Drawing object
+               self.left = left        # Left margin
+               self.right = right      # Right margin
+               self.v = top            # Top of current line
+               self.center = 0
+               self.justify = 1
+               self.setfont('')        # Current font
+               self._reset()           # Prepare for new line
+               return self
+       #
+       # Reset for start of fresh line.
+       #
+       def _reset(self):
+               self.boxes = []         # Boxes and glue still to be output
+               self.sum_width = 0      # Total width of boxes
+               self.sum_space = 0      # Total space between boxes
+               self.sum_stretch = 0    # Total stretch for space between boxes
+               self.max_ascent = 0     # Max ascent of current line
+               self.max_descent = 0    # Max descent of current line
+               self.avail_width = self.right - self.left
+               self.hang_indent = 0
+       #
+       # Set the current font, and compute some values from it.
+       #
+       def setfont(self, font):
+               self.font = font
+               self.d.setfont(font)
+               self.font_space = self.d.textwidth(' ')
+               self.font_ascent = self.d.baseline()
+               self.font_descent = self.d.lineheight() - self.font_ascent
+       #
+       # Add a word to the list of boxes; first flush if line is full.
+       # Space and stretch factors are expressed in fractions
+       # of the current font's space width.
+       # (Two variations: one without, one with explicit stretch factor.)
+       #
+       def addword(self, (word, spacefactor)):
+               self.addwordstretch(word, spacefactor, spacefactor)
+       #
+       def addwordstretch(self, (word, spacefactor, stretchfactor)):
+               width = self.d.textwidth(word)
+               if width > self.avail_width:
+                       self._flush(1)
+               space = int(float(self.font_space) * float(spacefactor))
+               stretch = int(float(self.font_space) * float(stretchfactor))
+               box = (self.font, word, width, space, stretch)
+               self.boxes.append(box)
+               self.sum_width = self.sum_width + width
+               self.sum_space = self.sum_space + space
+               self.sum_stretch = self.sum_stretch + stretch
+               self.max_ascent = max(self.font_ascent, self.max_ascent)
+               self.max_descent = max(self.font_descent, self.max_descent)
+               self.avail_width = self.avail_width - width - space
+       #
+       # Flush current line and start a new one.
+       # Flushing twice is harmless (i.e. does not introduce a blank line).
+       # (Two versions: the internal one has a parameter for justification.)
+       #
+       def flush(self):
+               self._flush(0)
+       #
+       def _flush(self, justify):
+               if not self.boxes:
+                       return
+               #
+               # Compute amount of stretch needed.
+               #
+               if justify and self.justify or self.center:
+                       #
+                       # Compute extra space to fill;
+                       # this is avail_width plus glue from last box.
+                       # Also compute available stretch.
+                       #
+                       last_box = self.boxes[len(self.boxes)-1]
+                       font, word, width, space, stretch = last_box
+                       tot_extra = self.avail_width + space
+                       tot_stretch = self.sum_stretch - stretch
+               else:
+                       tot_extra = tot_stretch = 0
+               #
+               # Output the boxes.
+               #
+               baseline = self.v + self.max_ascent
+               h = self.left + self.hang_indent
+               if self.center:
+                       h = h + tot_extra / 2
+                       tot_extra = tot_stretch = 0
+               for font, word, width, space, stretch in self.boxes:
+                       self.d.setfont(font)
+                       v = baseline - self.d.baseline()
+                       self.d.text((h, v), word)
+                       h = h + width + space
+                       if tot_extra > 0 and tot_stretch > 0:
+                               extra = stretch * tot_extra / tot_stretch
+                               h = h + extra
+                               tot_extra = tot_extra - extra
+                               tot_stretch = tot_stretch - stretch
+               #
+               # Prepare for next line.
+               #
+               self.v = baseline + self.max_descent
+               self.d.setfont(self.font)
+               self._reset()
+       #
+       # Add vertical space; first flush.
+       # Vertical space is expressed in fractions of the current
+       # font's line height.
+       #
+       def vspace(self, dy):
+               self.flush()
+               dy = int(float(dy) * float(self.d.lineheight()))
+               self.v = self.v + dy
+       #
+       # Set temporary (hanging) indent, for paragraph start.
+       # First flush.
+       #
+       def tempindent(self, space):
+               self.flush()
+               hang = int(float(self.font_space) * float(space))
+               self.hang_indent = hang
+               self.avail_width = self.avail_width - hang
+       #
+       # Add (permanent) left indentation.  First flush.
+       #
+       def addleftindent(self, space):
+               self.flush()
+               self.left = self.left \
+                       + int(float(self.font_space) * float(space))
+               self._reset()
+       #
+
+
+# Test procedure
+#
+def test():
+       import stdwin
+       from stdwinevents import *
+       try:
+               import mac
+               # Mac font assignments:
+               font1 = 'times', '', 12
+               font2 = 'times', 'b', 14
+       except NameError:
+               # X11R4 font assignments
+               font1 = '*times-medium-r-*-120-*'
+               font2 = '*times-bold-r-*-140-*'
+       words = \
+           ['The','quick','brown','fox','jumps','over','the','lazy','dog.']
+       words = words * 2
+       stage = 0
+       stages = [(0,0,'ragged'), (1,0,'justified'), (0,1,'centered')]
+       justify, center, title = stages[stage]
+       stdwin.setdefwinsize(300,200)
+       w = stdwin.open(title)
+       winsize = w.getwinsize()
+       while 1:
+               type, window, detail = stdwin.getevent()
+               if type = WE_CLOSE:
+                       break
+               elif type = WE_SIZE:
+                       newsize = w.getwinsize()
+                       if newsize <> winsize:
+                               w.change((0,0), winsize)
+                               winsize = newsize
+                               w.change((0,0), winsize)
+               elif type = WE_MOUSE_DOWN:
+                       stage = (stage + 1) % len(stages)
+                       justify, center, title = stages[stage]
+                       w.settitle(title)
+                       w.change((0, 0), (1000, 1000))
+               elif type = WE_DRAW:
+                       width, height = winsize
+                       f = formatter().init(w.begindrawing(), 0, 0, width)
+                       f.center = center
+                       f.justify = justify
+                       if not center:
+                               f.tempindent(5)
+                       for font in font1, font2, font1:
+                               f.setfont(font)
+                               for word in words:
+                                       space = 1 + (word[-1:] = '.')
+                                       f.addword(word, space)
+                                       if center and space > 1:
+                                               f.flush()
+                       f.flush()
+                       height = f.v
+                       del f
+                       w.setdocsize(0, height)