blob: 524b92ad328d611af65615d283f5bdb5da9e5234 [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
Jack Jansen5a6fdcd2001-08-25 12:15:04 +00008from Carbon.Menu import DrawMenuBar
Jack Jansene7b900d1996-04-11 15:41:39 +00009from FrameWork import *
Jack Jansen5a6fdcd2001-08-25 12:15:04 +000010from Carbon import Win
11from Carbon import Qd
12from Carbon import TE
13from Carbon import 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
Jack Jansen84445071996-04-19 15:54:47 +000021 r = windowbounds(400, 400)
Jack Jansencbed91b2001-08-03 13:31:36 +000022 w = Win.NewWindow(r, name, 1, 0, -1, 1, 0)
Jack Jansene7b900d1996-04-11 15:41:39 +000023 self.wid = w
Jack Jansenee8662f1996-08-19 10:58:37 +000024 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)
Jack Jansene7b900d1996-04-11 15:41:39 +000032 Qd.SetPort(w)
33 Qd.TextFont(4)
34 Qd.TextSize(9)
Jack Jansen84445071996-04-19 15:54:47 +000035 self.ted = TE.TENew(dr, vr)
Jack Jansene7b900d1996-04-11 15:41:39 +000036 self.ted.TEAutoView(1)
37 self.ted.TESetText(data)
38 w.DrawGrowIcon()
Jack Jansen111fdcf1996-04-16 14:34:26 +000039 self.scrollbars()
Jack Jansene7b900d1996-04-11 15:41:39 +000040 self.changed = 0
41 self.do_postopen()
Jack Jansen111fdcf1996-04-16 14:34:26 +000042 self.do_activate(1, None)
Jack Jansene7b900d1996-04-11 15:41:39 +000043
44 def do_idle(self):
45 self.ted.TEIdle()
46
Jack Jansen111fdcf1996-04-16 14:34:26 +000047 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
Jack Jansen84445071996-04-19 15:54:47 +000054 return None, vy
Jack Jansen111fdcf1996-04-16 14:34:26 +000055
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:
Jack Jansen84445071996-04-19 15:54:47 +000077 pass # No horizontal scrolling
Jack Jansen111fdcf1996-04-16 14:34:26 +000078
Jack Jansene7b900d1996-04-11 15:41:39 +000079 def do_activate(self, onoff, evt):
Jack Jansen111fdcf1996-04-16 14:34:26 +000080 print "ACTIVATE", onoff
81 ScrolledWindow.do_activate(self, onoff, evt)
Jack Jansene7b900d1996-04-11 15:41:39 +000082 if onoff:
83 self.ted.TEActivate()
84 self.parent.active = self
85 self.parent.updatemenubar()
86 else:
87 self.ted.TEDeactivate()
88
89 def do_update(self, wid, event):
90 Qd.EraseRect(wid.GetWindowPort().portRect)
91 self.ted.TEUpdate(wid.GetWindowPort().portRect)
Jack Jansen111fdcf1996-04-16 14:34:26 +000092 self.updatescrollbars()
Jack Jansene7b900d1996-04-11 15:41:39 +000093
94 def do_contentclick(self, local, modifiers, evt):
95 shifted = (modifiers & 0x200)
96 self.ted.TEClick(local, shifted)
Jack Jansen111fdcf1996-04-16 14:34:26 +000097 self.updatescrollbars()
Jack Jansene7b900d1996-04-11 15:41:39 +000098 self.parent.updatemenubar()
99
100 def do_char(self, ch, event):
Jack Jansen111fdcf1996-04-16 14:34:26 +0000101 self.ted.TESelView()
Jack Jansene7b900d1996-04-11 15:41:39 +0000102 self.ted.TEKey(ord(ch))
103 self.changed = 1
Jack Jansen111fdcf1996-04-16 14:34:26 +0000104 self.updatescrollbars()
Jack Jansene7b900d1996-04-11 15:41:39 +0000105 self.parent.updatemenubar()
106
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()
119
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
132
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()
140
141 def menu_cut(self):
Jack Jansen111fdcf1996-04-16 14:34:26 +0000142 self.ted.TESelView()
Jack Jansene7b900d1996-04-11 15:41:39 +0000143 self.ted.TECut()
Jack Jansen111fdcf1996-04-16 14:34:26 +0000144 Scrap.ZeroScrap()
145 TE.TEToScrap()
146 self.updatescrollbars()
Jack Jansene7b900d1996-04-11 15:41:39 +0000147 self.parent.updatemenubar()
Jack Jansen111fdcf1996-04-16 14:34:26 +0000148 self.changed = 1
Jack Jansene7b900d1996-04-11 15:41:39 +0000149
150 def menu_copy(self):
151 self.ted.TECopy()
Jack Jansen111fdcf1996-04-16 14:34:26 +0000152 Scrap.ZeroScrap()
153 TE.TEToScrap()
154 self.updatescrollbars()
155 self.parent.updatemenubar()
Jack Jansene7b900d1996-04-11 15:41:39 +0000156
157 def menu_paste(self):
Jack Jansen111fdcf1996-04-16 14:34:26 +0000158 TE.TEFromScrap()
159 self.ted.TESelView()
Jack Jansene7b900d1996-04-11 15:41:39 +0000160 self.ted.TEPaste()
Jack Jansen111fdcf1996-04-16 14:34:26 +0000161 self.updatescrollbars()
Jack Jansene7b900d1996-04-11 15:41:39 +0000162 self.parent.updatemenubar()
Jack Jansen111fdcf1996-04-16 14:34:26 +0000163 self.changed = 1
Jack Jansene7b900d1996-04-11 15:41:39 +0000164
165 def menu_clear(self):
Jack Jansen111fdcf1996-04-16 14:34:26 +0000166 self.ted.TESelView()
Jack Jansene7b900d1996-04-11 15:41:39 +0000167 self.ted.TEDelete()
Jack Jansen111fdcf1996-04-16 14:34:26 +0000168 self.updatescrollbars()
Jack Jansene7b900d1996-04-11 15:41:39 +0000169 self.parent.updatemenubar()
Jack Jansen111fdcf1996-04-16 14:34:26 +0000170 self.changed = 1
Jack Jansene7b900d1996-04-11 15:41:39 +0000171
172 def have_selection(self):
Jack Jansen111fdcf1996-04-16 14:34:26 +0000173 return (self.ted.selStart < self.ted.selEnd)
Jack Jansene7b900d1996-04-11 15:41:39 +0000174
175class Ped(Application):
176 def __init__(self):
177 Application.__init__(self)
178 self.num = 0
179 self.active = None
180 self.updatemenubar()
181
182 def makeusermenus(self):
183 self.filemenu = m = Menu(self.menubar, "File")
184 self.newitem = MenuItem(m, "New window", "N", self.open)
185 self.openitem = MenuItem(m, "Open...", "O", self.openfile)
186 self.closeitem = MenuItem(m, "Close", "W", self.closewin)
187 m.addseparator()
188 self.saveitem = MenuItem(m, "Save", "S", self.save)
189 self.saveasitem = MenuItem(m, "Save as...", "", self.saveas)
190 m.addseparator()
191 self.quititem = MenuItem(m, "Quit", "Q", self.quit)
192
193 self.editmenu = m = Menu(self.menubar, "Edit")
194 self.undoitem = MenuItem(m, "Undo", "Z", self.undo)
195 self.cutitem = MenuItem(m, "Cut", "X", self.cut)
196 self.copyitem = MenuItem(m, "Copy", "C", self.copy)
197 self.pasteitem = MenuItem(m, "Paste", "V", self.paste)
198 self.clearitem = MenuItem(m, "Clear", "", self.clear)
199
200 # Not yet implemented:
201 self.undoitem.enable(0)
202
203 # Groups of items enabled together:
204 self.windowgroup = [self.closeitem, self.saveitem, self.saveasitem, self.editmenu]
205 self.focusgroup = [self.cutitem, self.copyitem, self.clearitem]
206 self.windowgroup_on = -1
207 self.focusgroup_on = -1
Jack Jansen111fdcf1996-04-16 14:34:26 +0000208 self.pastegroup_on = -1
Jack Jansene7b900d1996-04-11 15:41:39 +0000209
210 def updatemenubar(self):
211 changed = 0
212 on = (self.active <> None)
213 if on <> self.windowgroup_on:
214 for m in self.windowgroup:
215 m.enable(on)
216 self.windowgroup_on = on
217 changed = 1
218 if on:
Jack Jansen111fdcf1996-04-16 14:34:26 +0000219 # only if we have an edit menu
Jack Jansene7b900d1996-04-11 15:41:39 +0000220 on = self.active.have_selection()
Jack Jansen111fdcf1996-04-16 14:34:26 +0000221 if on <> self.focusgroup_on:
222 for m in self.focusgroup:
223 m.enable(on)
224 self.focusgroup_on = on
225 changed = 1
Jack Jansenee677912001-04-25 22:05:36 +0000226 if hasattr(Scrap, 'InfoScrap'):
227 on = (Scrap.InfoScrap()[0] <> 0)
228 else:
229 # Not there yet on Carbon, simply always enable
230 on = 1
Jack Jansen111fdcf1996-04-16 14:34:26 +0000231 if on <> self.pastegroup_on:
232 self.pasteitem.enable(on)
233 self.pastegroup_on = on
234 changed = 1
Jack Jansene7b900d1996-04-11 15:41:39 +0000235 if changed:
236 DrawMenuBar()
237
238 #
239 # Apple menu
240 #
241
242 def do_about(self, id, item, window, event):
243 EasyDialogs.Message("A simple single-font text editor")
244
245 #
246 # File menu
247 #
248
249 def open(self, *args):
250 self._open(0)
251
252 def openfile(self, *args):
253 self._open(1)
254
255 def _open(self, askfile):
256 if askfile:
257 fss, ok = macfs.StandardGetFile('TEXT')
258 if not ok:
259 return
260 path = fss.as_pathname()
261 name = os.path.split(path)[-1]
262 try:
263 fp = open(path, 'rb') # NOTE binary, we need cr as end-of-line
264 data = fp.read()
265 fp.close()
266 except IOError, arg:
267 EasyDialogs.Message("IOERROR: "+`arg`)
268 return
269 else:
270 path = None
271 name = "Untitled %d"%self.num
272 data = ''
273 w = TEWindow(self)
274 w.open(path, name, data)
275 self.num = self.num + 1
276
277 def closewin(self, *args):
278 if self.active:
279 self.active.close()
280 else:
281 EasyDialogs.Message("No active window?")
282
283 def save(self, *args):
284 if self.active:
285 self.active.menu_save()
286 else:
287 EasyDialogs.Message("No active window?")
288
289 def saveas(self, *args):
290 if self.active:
291 self.active.menu_save_as()
292 else:
293 EasyDialogs.Message("No active window?")
294
295
296 def quit(self, *args):
297 for w in self._windows.values():
298 w.close()
299 if self._windows:
300 return
Jack Jansenef5cd051996-09-17 12:39:12 +0000301 self._quit()
Jack Jansene7b900d1996-04-11 15:41:39 +0000302
303 #
304 # Edit menu
305 #
306
307 def undo(self, *args):
308 pass
309
310 def cut(self, *args):
311 if self.active:
312 self.active.menu_cut()
313 else:
314 EasyDialogs.Message("No active window?")
315
316 def copy(self, *args):
317 if self.active:
318 self.active.menu_copy()
319 else:
320 EasyDialogs.Message("No active window?")
321
322 def paste(self, *args):
323 if self.active:
324 self.active.menu_paste()
325 else:
326 EasyDialogs.Message("No active window?")
327
328 def clear(self, *args):
329 if self.active:
330 self.active.menu_clear()
331 else:
332 EasyDialogs.Message("No active window?")
333
334 #
335 # Other stuff
336 #
337
338 def idle(self, *args):
Jack Jansen84445071996-04-19 15:54:47 +0000339 if self.active:
340 self.active.do_idle()
Jack Jansencbed91b2001-08-03 13:31:36 +0000341 else:
342 Qd.SetCursor(Qd.qd.arrow)
Jack Jansene7b900d1996-04-11 15:41:39 +0000343
344def main():
345 App = Ped()
346 App.mainloop()
347
348if __name__ == '__main__':
349 main()
350