blob: 425224ab3798ee8c3c706b079eedff4c49a724fa [file] [log] [blame]
Jack Jansen111fdcf1996-04-16 14:34:26 +00001# A minimal text editor.
Jack Jansene7b900d1996-04-11 15:41:39 +00002#
Jack Jansen111fdcf1996-04-16 14:34:26 +00003# To be done:
4# - Update viewrect after resize
5# - Handle horizontal scrollbar correctly
6# - Functionality: find, etc.
Jack Jansene7b900d1996-04-11 15:41:39 +00007
8from Menu import DrawMenuBar
9from FrameWork import *
10import Win
11import Qd
12import TE
Jack Jansen111fdcf1996-04-16 14:34:26 +000013import Scrap
Jack Jansene7b900d1996-04-11 15:41:39 +000014import os
15import macfs
16
Jack Jansen111fdcf1996-04-16 14:34:26 +000017class TEWindow(ScrolledWindow):
Jack Jansene7b900d1996-04-11 15:41:39 +000018 def open(self, path, name, data):
19 self.path = path
20 self.name = name
21 r = (40, 40, 400, 300)
22 w = Win.NewWindow(r, name, 1, 0, -1, 1, 0x55555555)
23 self.wid = w
24 r2 = (0, 0, 345, 245)
25 Qd.SetPort(w)
26 Qd.TextFont(4)
27 Qd.TextSize(9)
28 self.ted = TE.TENew(r2, r2)
29 self.ted.TEAutoView(1)
30 self.ted.TESetText(data)
31 w.DrawGrowIcon()
Jack Jansen111fdcf1996-04-16 14:34:26 +000032 self.scrollbars()
Jack Jansene7b900d1996-04-11 15:41:39 +000033 self.changed = 0
34 self.do_postopen()
Jack Jansen111fdcf1996-04-16 14:34:26 +000035 self.do_activate(1, None)
Jack Jansene7b900d1996-04-11 15:41:39 +000036
37 def do_idle(self):
38 self.ted.TEIdle()
39
Jack Jansen111fdcf1996-04-16 14:34:26 +000040 def getscrollbarvalues(self):
41 dr = self.ted.destRect
42 vr = self.ted.viewRect
43 height = self.ted.nLines * self.ted.lineHeight
44 vx = self.scalebarvalue(dr[0], dr[2]-dr[0], vr[0], vr[2])
45 vy = self.scalebarvalue(dr[1], dr[1]+height, vr[1], vr[3])
46 print dr, vr, height, vx, vy
47 return vx, vy
48
49 def scrollbar_callback(self, which, what, value):
50 if which == 'y':
51 if what == 'set':
52 height = self.ted.nLines * self.ted.lineHeight
53 cur = self.getscrollbarvalues()[1]
54 delta = (cur-value)*height/32767
55 if what == '-':
56 delta = self.ted.lineHeight
57 elif what == '--':
58 delta = (self.ted.viewRect[3]-self.ted.lineHeight)
59 if delta <= 0:
60 delta = self.ted.lineHeight
61 elif what == '+':
62 delta = -self.ted.lineHeight
63 elif what == '++':
64 delta = -(self.ted.viewRect[3]-self.ted.lineHeight)
65 if delta >= 0:
66 delta = -self.ted.lineHeight
67 self.ted.TEPinScroll(0, delta)
68 print 'SCROLL Y', delta
69 else:
70 if what == 'set':
71 return # XXXX
72 if what == '-':
73 delta = self.ted.viewRect[2]/10
74 elif what == '--':
75 delta = self.ted.viewRect[2]/2
76 elif what == '+':
77 delta = +self.ted.viewRect[2]/10
78 elif what == '++':
79 delta = +self.ted.viewRect[2]/2
80 self.ted.TEPinScroll(delta, 0)
81
82
Jack Jansene7b900d1996-04-11 15:41:39 +000083 def do_activate(self, onoff, evt):
Jack Jansen111fdcf1996-04-16 14:34:26 +000084 print "ACTIVATE", onoff
85 ScrolledWindow.do_activate(self, onoff, evt)
Jack Jansene7b900d1996-04-11 15:41:39 +000086 if onoff:
87 self.ted.TEActivate()
88 self.parent.active = self
89 self.parent.updatemenubar()
90 else:
91 self.ted.TEDeactivate()
92
93 def do_update(self, wid, event):
94 Qd.EraseRect(wid.GetWindowPort().portRect)
95 self.ted.TEUpdate(wid.GetWindowPort().portRect)
Jack Jansen111fdcf1996-04-16 14:34:26 +000096 self.updatescrollbars()
Jack Jansene7b900d1996-04-11 15:41:39 +000097
98 def do_contentclick(self, local, modifiers, evt):
99 shifted = (modifiers & 0x200)
100 self.ted.TEClick(local, shifted)
Jack Jansen111fdcf1996-04-16 14:34:26 +0000101 self.updatescrollbars()
Jack Jansene7b900d1996-04-11 15:41:39 +0000102 self.parent.updatemenubar()
103
104 def do_char(self, ch, event):
Jack Jansen111fdcf1996-04-16 14:34:26 +0000105 self.ted.TESelView()
Jack Jansene7b900d1996-04-11 15:41:39 +0000106 self.ted.TEKey(ord(ch))
107 self.changed = 1
Jack Jansen111fdcf1996-04-16 14:34:26 +0000108 self.updatescrollbars()
Jack Jansene7b900d1996-04-11 15:41:39 +0000109 self.parent.updatemenubar()
110
111 def close(self):
112 if self.changed:
113 save = EasyDialogs.AskYesNoCancel('Save window "%s" before closing?'%self.name, 1)
114 if save > 0:
115 self.menu_save()
116 elif save < 0:
117 return
118 if self.parent.active == self:
119 self.parent.active = None
120 self.parent.updatemenubar()
121 del self.ted
122 self.do_postclose()
123
124 def menu_save(self):
125 if not self.path:
126 self.menu_save_as()
127 return # Will call us recursively
128 print 'Saving to ', self.path
129 dhandle = self.ted.TEGetText()
130 data = dhandle.data
131 fp = open(self.path, 'wb') # NOTE: wb, because data has CR for end-of-line
132 fp.write(data)
133 if data[-1] <> '\r': fp.write('\r')
134 fp.close()
135 self.changed = 0
136
137 def menu_save_as(self):
138 fss, ok = macfs.StandardPutFile('Save as:')
139 if not ok: return
140 self.path = fss.as_pathname()
141 self.name = os.path.split(self.path)[-1]
142 self.wid.SetWTitle(self.name)
143 self.menu_save()
144
145 def menu_cut(self):
Jack Jansen111fdcf1996-04-16 14:34:26 +0000146 self.ted.TESelView()
Jack Jansene7b900d1996-04-11 15:41:39 +0000147 self.ted.TECut()
Jack Jansen111fdcf1996-04-16 14:34:26 +0000148 Scrap.ZeroScrap()
149 TE.TEToScrap()
150 self.updatescrollbars()
Jack Jansene7b900d1996-04-11 15:41:39 +0000151 self.parent.updatemenubar()
Jack Jansen111fdcf1996-04-16 14:34:26 +0000152 self.changed = 1
Jack Jansene7b900d1996-04-11 15:41:39 +0000153
154 def menu_copy(self):
155 self.ted.TECopy()
Jack Jansen111fdcf1996-04-16 14:34:26 +0000156 Scrap.ZeroScrap()
157 TE.TEToScrap()
158 self.updatescrollbars()
159 self.parent.updatemenubar()
Jack Jansene7b900d1996-04-11 15:41:39 +0000160
161 def menu_paste(self):
Jack Jansen111fdcf1996-04-16 14:34:26 +0000162 print 'SCRAP', Scrap.InfoScrap(), `Scrap.InfoScrap()[1].data`
163 TE.TEFromScrap()
164 self.ted.TESelView()
Jack Jansene7b900d1996-04-11 15:41:39 +0000165 self.ted.TEPaste()
Jack Jansen111fdcf1996-04-16 14:34:26 +0000166 self.updatescrollbars()
Jack Jansene7b900d1996-04-11 15:41:39 +0000167 self.parent.updatemenubar()
Jack Jansen111fdcf1996-04-16 14:34:26 +0000168 self.changed = 1
Jack Jansene7b900d1996-04-11 15:41:39 +0000169
170 def menu_clear(self):
Jack Jansen111fdcf1996-04-16 14:34:26 +0000171 self.ted.TESelView()
Jack Jansene7b900d1996-04-11 15:41:39 +0000172 self.ted.TEDelete()
Jack Jansen111fdcf1996-04-16 14:34:26 +0000173 self.updatescrollbars()
Jack Jansene7b900d1996-04-11 15:41:39 +0000174 self.parent.updatemenubar()
Jack Jansen111fdcf1996-04-16 14:34:26 +0000175 self.changed = 1
Jack Jansene7b900d1996-04-11 15:41:39 +0000176
177 def have_selection(self):
Jack Jansen111fdcf1996-04-16 14:34:26 +0000178 return (self.ted.selStart < self.ted.selEnd)
Jack Jansene7b900d1996-04-11 15:41:39 +0000179
180class Ped(Application):
181 def __init__(self):
182 Application.__init__(self)
183 self.num = 0
184 self.active = None
185 self.updatemenubar()
186
187 def makeusermenus(self):
188 self.filemenu = m = Menu(self.menubar, "File")
189 self.newitem = MenuItem(m, "New window", "N", self.open)
190 self.openitem = MenuItem(m, "Open...", "O", self.openfile)
191 self.closeitem = MenuItem(m, "Close", "W", self.closewin)
192 m.addseparator()
193 self.saveitem = MenuItem(m, "Save", "S", self.save)
194 self.saveasitem = MenuItem(m, "Save as...", "", self.saveas)
195 m.addseparator()
196 self.quititem = MenuItem(m, "Quit", "Q", self.quit)
197
198 self.editmenu = m = Menu(self.menubar, "Edit")
199 self.undoitem = MenuItem(m, "Undo", "Z", self.undo)
200 self.cutitem = MenuItem(m, "Cut", "X", self.cut)
201 self.copyitem = MenuItem(m, "Copy", "C", self.copy)
202 self.pasteitem = MenuItem(m, "Paste", "V", self.paste)
203 self.clearitem = MenuItem(m, "Clear", "", self.clear)
204
205 # Not yet implemented:
206 self.undoitem.enable(0)
207
208 # Groups of items enabled together:
209 self.windowgroup = [self.closeitem, self.saveitem, self.saveasitem, self.editmenu]
210 self.focusgroup = [self.cutitem, self.copyitem, self.clearitem]
211 self.windowgroup_on = -1
212 self.focusgroup_on = -1
Jack Jansen111fdcf1996-04-16 14:34:26 +0000213 self.pastegroup_on = -1
Jack Jansene7b900d1996-04-11 15:41:39 +0000214
215 def updatemenubar(self):
216 changed = 0
217 on = (self.active <> None)
218 if on <> self.windowgroup_on:
219 for m in self.windowgroup:
220 m.enable(on)
221 self.windowgroup_on = on
222 changed = 1
223 if on:
Jack Jansen111fdcf1996-04-16 14:34:26 +0000224 # only if we have an edit menu
Jack Jansene7b900d1996-04-11 15:41:39 +0000225 on = self.active.have_selection()
Jack Jansen111fdcf1996-04-16 14:34:26 +0000226 if on <> self.focusgroup_on:
227 for m in self.focusgroup:
228 m.enable(on)
229 self.focusgroup_on = on
230 changed = 1
231 on = (Scrap.InfoScrap()[0] <> 0)
232 if on <> self.pastegroup_on:
233 self.pasteitem.enable(on)
234 self.pastegroup_on = on
235 changed = 1
Jack Jansene7b900d1996-04-11 15:41:39 +0000236 if changed:
237 DrawMenuBar()
238
239 #
240 # Apple menu
241 #
242
243 def do_about(self, id, item, window, event):
244 EasyDialogs.Message("A simple single-font text editor")
245
246 #
247 # File menu
248 #
249
250 def open(self, *args):
251 self._open(0)
252
253 def openfile(self, *args):
254 self._open(1)
255
256 def _open(self, askfile):
257 if askfile:
258 fss, ok = macfs.StandardGetFile('TEXT')
259 if not ok:
260 return
261 path = fss.as_pathname()
262 name = os.path.split(path)[-1]
263 try:
264 fp = open(path, 'rb') # NOTE binary, we need cr as end-of-line
265 data = fp.read()
266 fp.close()
267 except IOError, arg:
268 EasyDialogs.Message("IOERROR: "+`arg`)
269 return
270 else:
271 path = None
272 name = "Untitled %d"%self.num
273 data = ''
274 w = TEWindow(self)
275 w.open(path, name, data)
276 self.num = self.num + 1
277
278 def closewin(self, *args):
279 if self.active:
280 self.active.close()
281 else:
282 EasyDialogs.Message("No active window?")
283
284 def save(self, *args):
285 if self.active:
286 self.active.menu_save()
287 else:
288 EasyDialogs.Message("No active window?")
289
290 def saveas(self, *args):
291 if self.active:
292 self.active.menu_save_as()
293 else:
294 EasyDialogs.Message("No active window?")
295
296
297 def quit(self, *args):
298 for w in self._windows.values():
299 w.close()
300 if self._windows:
301 return
302 raise self
303
304 #
305 # Edit menu
306 #
307
308 def undo(self, *args):
309 pass
310
311 def cut(self, *args):
312 if self.active:
313 self.active.menu_cut()
314 else:
315 EasyDialogs.Message("No active window?")
316
317 def copy(self, *args):
318 if self.active:
319 self.active.menu_copy()
320 else:
321 EasyDialogs.Message("No active window?")
322
323 def paste(self, *args):
324 if self.active:
325 self.active.menu_paste()
326 else:
327 EasyDialogs.Message("No active window?")
328
329 def clear(self, *args):
330 if self.active:
331 self.active.menu_clear()
332 else:
333 EasyDialogs.Message("No active window?")
334
335 #
336 # Other stuff
337 #
338
339 def idle(self, *args):
340 for l in self._windows.values():
341 l.do_idle()
342
343def main():
344 App = Ped()
345 App.mainloop()
346
347if __name__ == '__main__':
348 main()
349