Quick update to the README file. For intros and books we now point to
[python/dscho.git] / Mac / Demo / textedit / ped.py
blob5c2d0f6013d07998b35280d9253549ff0e73bbe0
1 # A minimal text editor.
3 # To be done:
4 # - Update viewrect after resize
5 # - Handle horizontal scrollbar correctly
6 # - Functionality: find, etc.
8 from Menu import DrawMenuBar
9 from FrameWork import *
10 import Win
11 import Qd
12 import TE
13 import Scrap
14 import os
15 import macfs
17 class TEWindow(ScrolledWindow):
18 def open(self, path, name, data):
19 self.path = path
20 self.name = name
21 r = windowbounds(400, 400)
22 w = Win.NewWindow(r, name, 1, 0, -1, 1, 0x55555555)
23 self.wid = w
24 x0, y0, x1, y1 = self.wid.GetWindowPort().portRect
25 x0 = x0 + 4
26 y0 = y0 + 4
27 x1 = x1 - 20
28 y1 = y1 - 20
29 vr = dr = x0, y0, x1, y1
30 ##vr = 4, 0, r[2]-r[0]-15, r[3]-r[1]-15
31 ##dr = (0, 0, vr[2], 0)
32 Qd.SetPort(w)
33 Qd.TextFont(4)
34 Qd.TextSize(9)
35 self.ted = TE.TENew(dr, vr)
36 self.ted.TEAutoView(1)
37 self.ted.TESetText(data)
38 w.DrawGrowIcon()
39 self.scrollbars()
40 self.changed = 0
41 self.do_postopen()
42 self.do_activate(1, None)
44 def do_idle(self):
45 self.ted.TEIdle()
47 def getscrollbarvalues(self):
48 dr = self.ted.destRect
49 vr = self.ted.viewRect
50 height = self.ted.nLines * self.ted.lineHeight
51 vx = self.scalebarvalue(dr[0], dr[2]-dr[0], vr[0], vr[2])
52 vy = self.scalebarvalue(dr[1], dr[1]+height, vr[1], vr[3])
53 print dr, vr, height, vx, vy
54 return None, vy
56 def scrollbar_callback(self, which, what, value):
57 if which == 'y':
58 if what == 'set':
59 height = self.ted.nLines * self.ted.lineHeight
60 cur = self.getscrollbarvalues()[1]
61 delta = (cur-value)*height/32767
62 if what == '-':
63 delta = self.ted.lineHeight
64 elif what == '--':
65 delta = (self.ted.viewRect[3]-self.ted.lineHeight)
66 if delta <= 0:
67 delta = self.ted.lineHeight
68 elif what == '+':
69 delta = -self.ted.lineHeight
70 elif what == '++':
71 delta = -(self.ted.viewRect[3]-self.ted.lineHeight)
72 if delta >= 0:
73 delta = -self.ted.lineHeight
74 self.ted.TEPinScroll(0, delta)
75 print 'SCROLL Y', delta
76 else:
77 pass # No horizontal scrolling
79 def do_activate(self, onoff, evt):
80 print "ACTIVATE", onoff
81 ScrolledWindow.do_activate(self, onoff, evt)
82 if onoff:
83 self.ted.TEActivate()
84 self.parent.active = self
85 self.parent.updatemenubar()
86 else:
87 self.ted.TEDeactivate()
89 def do_update(self, wid, event):
90 Qd.EraseRect(wid.GetWindowPort().portRect)
91 self.ted.TEUpdate(wid.GetWindowPort().portRect)
92 self.updatescrollbars()
94 def do_contentclick(self, local, modifiers, evt):
95 shifted = (modifiers & 0x200)
96 self.ted.TEClick(local, shifted)
97 self.updatescrollbars()
98 self.parent.updatemenubar()
100 def do_char(self, ch, event):
101 self.ted.TESelView()
102 self.ted.TEKey(ord(ch))
103 self.changed = 1
104 self.updatescrollbars()
105 self.parent.updatemenubar()
107 def close(self):
108 if self.changed:
109 save = EasyDialogs.AskYesNoCancel('Save window "%s" before closing?'%self.name, 1)
110 if save > 0:
111 self.menu_save()
112 elif save < 0:
113 return
114 if self.parent.active == self:
115 self.parent.active = None
116 self.parent.updatemenubar()
117 del self.ted
118 self.do_postclose()
120 def menu_save(self):
121 if not self.path:
122 self.menu_save_as()
123 return # Will call us recursively
124 print 'Saving to ', self.path
125 dhandle = self.ted.TEGetText()
126 data = dhandle.data
127 fp = open(self.path, 'wb') # NOTE: wb, because data has CR for end-of-line
128 fp.write(data)
129 if data[-1] <> '\r': fp.write('\r')
130 fp.close()
131 self.changed = 0
133 def menu_save_as(self):
134 fss, ok = macfs.StandardPutFile('Save as:')
135 if not ok: return
136 self.path = fss.as_pathname()
137 self.name = os.path.split(self.path)[-1]
138 self.wid.SetWTitle(self.name)
139 self.menu_save()
141 def menu_cut(self):
142 self.ted.TESelView()
143 self.ted.TECut()
144 Scrap.ZeroScrap()
145 TE.TEToScrap()
146 self.updatescrollbars()
147 self.parent.updatemenubar()
148 self.changed = 1
150 def menu_copy(self):
151 self.ted.TECopy()
152 Scrap.ZeroScrap()
153 TE.TEToScrap()
154 self.updatescrollbars()
155 self.parent.updatemenubar()
157 def menu_paste(self):
158 print 'SCRAP', Scrap.InfoScrap(), `Scrap.InfoScrap()[1].data`
159 TE.TEFromScrap()
160 self.ted.TESelView()
161 self.ted.TEPaste()
162 self.updatescrollbars()
163 self.parent.updatemenubar()
164 self.changed = 1
166 def menu_clear(self):
167 self.ted.TESelView()
168 self.ted.TEDelete()
169 self.updatescrollbars()
170 self.parent.updatemenubar()
171 self.changed = 1
173 def have_selection(self):
174 return (self.ted.selStart < self.ted.selEnd)
176 class Ped(Application):
177 def __init__(self):
178 Application.__init__(self)
179 self.num = 0
180 self.active = None
181 self.updatemenubar()
183 def makeusermenus(self):
184 self.filemenu = m = Menu(self.menubar, "File")
185 self.newitem = MenuItem(m, "New window", "N", self.open)
186 self.openitem = MenuItem(m, "Open...", "O", self.openfile)
187 self.closeitem = MenuItem(m, "Close", "W", self.closewin)
188 m.addseparator()
189 self.saveitem = MenuItem(m, "Save", "S", self.save)
190 self.saveasitem = MenuItem(m, "Save as...", "", self.saveas)
191 m.addseparator()
192 self.quititem = MenuItem(m, "Quit", "Q", self.quit)
194 self.editmenu = m = Menu(self.menubar, "Edit")
195 self.undoitem = MenuItem(m, "Undo", "Z", self.undo)
196 self.cutitem = MenuItem(m, "Cut", "X", self.cut)
197 self.copyitem = MenuItem(m, "Copy", "C", self.copy)
198 self.pasteitem = MenuItem(m, "Paste", "V", self.paste)
199 self.clearitem = MenuItem(m, "Clear", "", self.clear)
201 # Not yet implemented:
202 self.undoitem.enable(0)
204 # Groups of items enabled together:
205 self.windowgroup = [self.closeitem, self.saveitem, self.saveasitem, self.editmenu]
206 self.focusgroup = [self.cutitem, self.copyitem, self.clearitem]
207 self.windowgroup_on = -1
208 self.focusgroup_on = -1
209 self.pastegroup_on = -1
211 def updatemenubar(self):
212 changed = 0
213 on = (self.active <> None)
214 if on <> self.windowgroup_on:
215 for m in self.windowgroup:
216 m.enable(on)
217 self.windowgroup_on = on
218 changed = 1
219 if on:
220 # only if we have an edit menu
221 on = self.active.have_selection()
222 if on <> self.focusgroup_on:
223 for m in self.focusgroup:
224 m.enable(on)
225 self.focusgroup_on = on
226 changed = 1
227 on = (Scrap.InfoScrap()[0] <> 0)
228 if on <> self.pastegroup_on:
229 self.pasteitem.enable(on)
230 self.pastegroup_on = on
231 changed = 1
232 if changed:
233 DrawMenuBar()
236 # Apple menu
239 def do_about(self, id, item, window, event):
240 EasyDialogs.Message("A simple single-font text editor")
243 # File menu
246 def open(self, *args):
247 self._open(0)
249 def openfile(self, *args):
250 self._open(1)
252 def _open(self, askfile):
253 if askfile:
254 fss, ok = macfs.StandardGetFile('TEXT')
255 if not ok:
256 return
257 path = fss.as_pathname()
258 name = os.path.split(path)[-1]
259 try:
260 fp = open(path, 'rb') # NOTE binary, we need cr as end-of-line
261 data = fp.read()
262 fp.close()
263 except IOError, arg:
264 EasyDialogs.Message("IOERROR: "+`arg`)
265 return
266 else:
267 path = None
268 name = "Untitled %d"%self.num
269 data = ''
270 w = TEWindow(self)
271 w.open(path, name, data)
272 self.num = self.num + 1
274 def closewin(self, *args):
275 if self.active:
276 self.active.close()
277 else:
278 EasyDialogs.Message("No active window?")
280 def save(self, *args):
281 if self.active:
282 self.active.menu_save()
283 else:
284 EasyDialogs.Message("No active window?")
286 def saveas(self, *args):
287 if self.active:
288 self.active.menu_save_as()
289 else:
290 EasyDialogs.Message("No active window?")
293 def quit(self, *args):
294 for w in self._windows.values():
295 w.close()
296 if self._windows:
297 return
298 self._quit()
301 # Edit menu
304 def undo(self, *args):
305 pass
307 def cut(self, *args):
308 if self.active:
309 self.active.menu_cut()
310 else:
311 EasyDialogs.Message("No active window?")
313 def copy(self, *args):
314 if self.active:
315 self.active.menu_copy()
316 else:
317 EasyDialogs.Message("No active window?")
319 def paste(self, *args):
320 if self.active:
321 self.active.menu_paste()
322 else:
323 EasyDialogs.Message("No active window?")
325 def clear(self, *args):
326 if self.active:
327 self.active.menu_clear()
328 else:
329 EasyDialogs.Message("No active window?")
332 # Other stuff
335 def idle(self, *args):
336 if self.active:
337 self.active.do_idle()
339 def main():
340 App = Ped()
341 App.mainloop()
343 if __name__ == '__main__':
344 main()