Mercurial > cpython-lru_cache-weakref
annotate Lib/stdwin/formatter.py @ 5817:48b94de85bf3 legacy-trunk
Extensive changes by AMK.
| author | Guido van Rossum <guido@python.org> |
|---|---|
| date | Thu, 17 Jul 1997 16:29:42 +0000 |
| parents | 560ec7030817 |
| children |
| rev | line source |
|---|---|
| 247 | 1 # A class to help applications that do fancy text formatting. |
| 2 # You create an instance each time you must redraw the window. | |
| 3 # Set the initial left, top and right coordinates; | |
| 4 # then feed it words, font changes and vertical movements. | |
| 5 # | |
| 6 # This class should eventually be extended to support much fancier | |
| 7 # formatting, along the lines of TeX; for now, a very simple model | |
| 8 # is sufficient. | |
| 9 # | |
| 524 | 10 class formatter: |
| 247 | 11 # |
| 12 # Initialize a formatter instance. | |
| 13 # Pass the window's drawing object, and left, top, right | |
| 14 # coordinates of the drawing space as arguments. | |
| 15 # | |
|
1435
560ec7030817
* Mass change: get rid of all init() methods, in favor of __init__()
Guido van Rossum <guido@python.org>
parents:
1110
diff
changeset
|
16 def __init__(self, d, left, top, right): |
| 247 | 17 self.d = d # Drawing object |
| 18 self.left = left # Left margin | |
| 19 self.right = right # Right margin | |
| 20 self.v = top # Top of current line | |
| 21 self.center = 0 | |
| 22 self.justify = 1 | |
| 357 | 23 self.setfont('') # Default font |
| 247 | 24 self._reset() # Prepare for new line |
| 25 # | |
| 26 # Reset for start of fresh line. | |
| 27 # | |
| 28 def _reset(self): | |
| 29 self.boxes = [] # Boxes and glue still to be output | |
| 30 self.sum_width = 0 # Total width of boxes | |
| 31 self.sum_space = 0 # Total space between boxes | |
| 32 self.sum_stretch = 0 # Total stretch for space between boxes | |
| 33 self.max_ascent = 0 # Max ascent of current line | |
| 34 self.max_descent = 0 # Max descent of current line | |
| 35 self.avail_width = self.right - self.left | |
| 36 self.hang_indent = 0 | |
| 37 # | |
| 38 # Set the current font, and compute some values from it. | |
| 39 # | |
| 40 def setfont(self, font): | |
| 41 self.font = font | |
| 42 self.d.setfont(font) | |
| 43 self.font_space = self.d.textwidth(' ') | |
| 44 self.font_ascent = self.d.baseline() | |
| 45 self.font_descent = self.d.lineheight() - self.font_ascent | |
| 46 # | |
| 47 # Add a word to the list of boxes; first flush if line is full. | |
| 48 # Space and stretch factors are expressed in fractions | |
| 49 # of the current font's space width. | |
| 50 # (Two variations: one without, one with explicit stretch factor.) | |
| 51 # | |
|
1110
1d06b1499eb9
* Got entirely rid of path.py.
Guido van Rossum <guido@python.org>
parents:
559
diff
changeset
|
52 def addword(self, word, spacefactor): |
| 247 | 53 self.addwordstretch(word, spacefactor, spacefactor) |
| 54 # | |
|
1110
1d06b1499eb9
* Got entirely rid of path.py.
Guido van Rossum <guido@python.org>
parents:
559
diff
changeset
|
55 def addwordstretch(self, word, spacefactor, stretchfactor): |
| 247 | 56 width = self.d.textwidth(word) |
| 57 if width > self.avail_width: | |
| 58 self._flush(1) | |
| 59 space = int(float(self.font_space) * float(spacefactor)) | |
| 60 stretch = int(float(self.font_space) * float(stretchfactor)) | |
| 61 box = (self.font, word, width, space, stretch) | |
| 62 self.boxes.append(box) | |
| 63 self.sum_width = self.sum_width + width | |
| 64 self.sum_space = self.sum_space + space | |
| 65 self.sum_stretch = self.sum_stretch + stretch | |
| 66 self.max_ascent = max(self.font_ascent, self.max_ascent) | |
| 67 self.max_descent = max(self.font_descent, self.max_descent) | |
| 68 self.avail_width = self.avail_width - width - space | |
| 69 # | |
| 70 # Flush current line and start a new one. | |
| 71 # Flushing twice is harmless (i.e. does not introduce a blank line). | |
| 72 # (Two versions: the internal one has a parameter for justification.) | |
| 73 # | |
| 74 def flush(self): | |
| 75 self._flush(0) | |
| 76 # | |
| 77 def _flush(self, justify): | |
| 78 if not self.boxes: | |
| 79 return | |
| 80 # | |
| 81 # Compute amount of stretch needed. | |
| 82 # | |
| 83 if justify and self.justify or self.center: | |
| 84 # | |
| 85 # Compute extra space to fill; | |
| 86 # this is avail_width plus glue from last box. | |
| 87 # Also compute available stretch. | |
| 88 # | |
| 89 last_box = self.boxes[len(self.boxes)-1] | |
| 90 font, word, width, space, stretch = last_box | |
| 91 tot_extra = self.avail_width + space | |
| 92 tot_stretch = self.sum_stretch - stretch | |
| 93 else: | |
| 94 tot_extra = tot_stretch = 0 | |
| 95 # | |
| 96 # Output the boxes. | |
| 97 # | |
| 98 baseline = self.v + self.max_ascent | |
| 99 h = self.left + self.hang_indent | |
| 100 if self.center: | |
| 101 h = h + tot_extra / 2 | |
| 102 tot_extra = tot_stretch = 0 | |
| 103 for font, word, width, space, stretch in self.boxes: | |
| 104 self.d.setfont(font) | |
| 105 v = baseline - self.d.baseline() | |
| 106 self.d.text((h, v), word) | |
| 107 h = h + width + space | |
| 108 if tot_extra > 0 and tot_stretch > 0: | |
| 109 extra = stretch * tot_extra / tot_stretch | |
| 110 h = h + extra | |
| 111 tot_extra = tot_extra - extra | |
| 112 tot_stretch = tot_stretch - stretch | |
| 113 # | |
| 114 # Prepare for next line. | |
| 115 # | |
| 116 self.v = baseline + self.max_descent | |
| 117 self.d.setfont(self.font) | |
| 118 self._reset() | |
| 119 # | |
| 120 # Add vertical space; first flush. | |
| 121 # Vertical space is expressed in fractions of the current | |
| 122 # font's line height. | |
| 123 # | |
| 357 | 124 def vspace(self, lines): |
| 125 self.vspacepixels(int(lines * self.d.lineheight())) | |
| 126 # | |
| 127 # Add vertical space given in pixels. | |
| 128 # | |
| 129 def vspacepixels(self, dv): | |
| 247 | 130 self.flush() |
| 357 | 131 self.v = self.v + dv |
| 247 | 132 # |
| 133 # Set temporary (hanging) indent, for paragraph start. | |
| 134 # First flush. | |
| 135 # | |
| 136 def tempindent(self, space): | |
| 137 self.flush() | |
| 138 hang = int(float(self.font_space) * float(space)) | |
| 139 self.hang_indent = hang | |
| 140 self.avail_width = self.avail_width - hang | |
| 141 # | |
| 142 # Add (permanent) left indentation. First flush. | |
| 143 # | |
| 144 def addleftindent(self, space): | |
| 145 self.flush() | |
| 146 self.left = self.left \ | |
| 147 + int(float(self.font_space) * float(space)) | |
| 148 self._reset() | |
| 149 # | |
| 150 | |
| 151 | |
| 152 # Test procedure | |
| 153 # | |
| 154 def test(): | |
| 357 | 155 import stdwin, stdwinq |
| 247 | 156 from stdwinevents import * |
| 157 try: | |
| 158 import mac | |
| 159 # Mac font assignments: | |
| 160 font1 = 'times', '', 12 | |
| 161 font2 = 'times', 'b', 14 | |
| 524 | 162 except ImportError: |
| 247 | 163 # X11R4 font assignments |
| 164 font1 = '*times-medium-r-*-120-*' | |
| 165 font2 = '*times-bold-r-*-140-*' | |
| 166 words = \ | |
| 167 ['The','quick','brown','fox','jumps','over','the','lazy','dog.'] | |
| 168 words = words * 2 | |
| 169 stage = 0 | |
| 170 stages = [(0,0,'ragged'), (1,0,'justified'), (0,1,'centered')] | |
| 171 justify, center, title = stages[stage] | |
| 172 stdwin.setdefwinsize(300,200) | |
| 173 w = stdwin.open(title) | |
| 174 winsize = w.getwinsize() | |
| 175 while 1: | |
| 357 | 176 type, window, detail = stdwinq.getevent() |
| 559 | 177 if type == WE_CLOSE: |
| 247 | 178 break |
| 559 | 179 elif type == WE_SIZE: |
| 247 | 180 newsize = w.getwinsize() |
| 181 if newsize <> winsize: | |
| 182 w.change((0,0), winsize) | |
| 183 winsize = newsize | |
| 184 w.change((0,0), winsize) | |
| 559 | 185 elif type == WE_MOUSE_DOWN: |
| 247 | 186 stage = (stage + 1) % len(stages) |
| 187 justify, center, title = stages[stage] | |
| 188 w.settitle(title) | |
| 189 w.change((0, 0), (1000, 1000)) | |
| 559 | 190 elif type == WE_DRAW: |
| 247 | 191 width, height = winsize |
|
1435
560ec7030817
* Mass change: get rid of all init() methods, in favor of __init__()
Guido van Rossum <guido@python.org>
parents:
1110
diff
changeset
|
192 f = formatter(w.begindrawing(), 0, 0, width) |
| 247 | 193 f.center = center |
| 194 f.justify = justify | |
| 195 if not center: | |
| 196 f.tempindent(5) | |
| 197 for font in font1, font2, font1: | |
| 198 f.setfont(font) | |
| 199 for word in words: | |
| 559 | 200 space = 1 + (word[-1:] == '.') |
| 247 | 201 f.addword(word, space) |
| 202 if center and space > 1: | |
| 203 f.flush() | |
| 204 f.flush() | |
| 205 height = f.v | |
| 206 del f | |
| 207 w.setdocsize(0, height) |
