1 # A minimal text editor.
4 # - Functionality: find, etc.
6 from Carbon
.Menu
import DrawMenuBar
7 from FrameWork
import *
10 from Carbon
import Res
13 from Carbon
import Scrap
17 UNDOLABELS
= [ # Indexed by WEGetUndoInfo() value
18 None, "", "typing", "Cut", "Paste", "Clear", "Drag", "Style"]
21 Qd
.SetRectRgn(BIGREGION
, -16000, -16000, 16000, 16000)
23 class WasteWindow(ScrolledWindow
):
24 def open(self
, path
, name
, data
):
27 r
= windowbounds(400, 400)
28 w
= Win
.NewWindow(r
, name
, 1, 0, -1, 1, 0)
30 vr
= 0, 0, r
[2]-r
[0]-15, r
[3]-r
[1]-15
35 flags
= WASTEconst
.weDoAutoScroll | WASTEconst
.weDoOutlineHilite | \
36 WASTEconst
.weDoMonoStyled | WASTEconst
.weDoUndo
37 self
.ted
= waste
.WENew(dr
, vr
, flags
)
38 self
.tedtexthandle
= Res
.Resource(data
)
39 self
.ted
.WEUseText(self
.tedtexthandle
)
45 self
.do_activate(1, None)
47 def do_idle(self
, event
):
48 (what
, message
, when
, where
, modifiers
) = event
51 if self
.ted
.WEAdjustCursor(where
, BIGREGION
):
53 Qd
.SetCursor(Qd
.qd
.arrow
)
55 def getscrollbarvalues(self
):
56 dr
= self
.ted
.WEGetDestRect()
57 vr
= self
.ted
.WEGetViewRect()
58 vx
= self
.scalebarvalue(dr
[0], dr
[2], vr
[0], vr
[2])
59 vy
= self
.scalebarvalue(dr
[1], dr
[3], vr
[1], vr
[3])
60 ## print dr, vr, vx, vy
63 def scrollbar_callback(self
, which
, what
, value
):
66 height
= self
.ted
.WEGetHeight(0, 0x3fffffff)
67 cur
= self
.getscrollbarvalues()[1]
68 delta
= (cur
-value
)*height
/32767
70 topline_off
,dummy
= self
.ted
.WEGetOffset((1,1))
71 topline_num
= self
.ted
.WEOffsetToLine(topline_off
)
72 delta
= self
.ted
.WEGetHeight(topline_num
, topline_num
+1)
74 delta
= (self
.ted
.WEGetViewRect()[3]-10)
76 delta
= 10 # Random value
78 # XXXX Wrong: should be bottom line size
79 topline_off
,dummy
= self
.ted
.WEGetOffset((1,1))
80 topline_num
= self
.ted
.WEOffsetToLine(topline_off
)
81 delta
= -self
.ted
.WEGetHeight(topline_num
, topline_num
+1)
83 delta
= -(self
.ted
.WEGetViewRect()[3]-10)
86 self
.ted
.WEScroll(0, delta
)
87 ## print 'SCROLL Y', delta
91 vr
= self
.ted
.WEGetViewRect()
92 winwidth
= vr
[2]-vr
[0]
101 self
.ted
.WEScroll(delta
, 0)
103 l
, t
, r
, b
= self
.ted
.WEGetDestRect()
104 vl
, vt
, vr
, vb
= self
.ted
.WEGetViewRect()
109 ## print 'Extra scroll', dx, dy
110 self
.ted
.WEScroll(dx
, dy
)
112 ## print 'Extra downscroll', b-vb
113 self
.ted
.WEScroll(0, b
-vb
)
116 def do_activate(self
, onoff
, evt
):
117 ## print "ACTIVATE", onoff
119 ScrolledWindow
.do_activate(self
, onoff
, evt
)
121 self
.ted
.WEActivate()
122 self
.parent
.active
= self
123 self
.parent
.updatemenubar()
125 self
.ted
.WEDeactivate()
127 def do_update(self
, wid
, event
):
128 region
= wid
.GetWindowPort().visRgn
129 if Qd
.EmptyRgn(region
):
132 self
.ted
.WEUpdate(region
)
133 self
.updatescrollbars()
135 def do_postresize(self
, width
, height
, window
):
136 l
, t
, r
, b
= self
.ted
.WEGetViewRect()
137 vr
= (l
, t
, l
+width
-15, t
+height
-15)
138 self
.ted
.WESetViewRect(vr
)
139 self
.wid
.InvalWindowRect(vr
)
140 ScrolledWindow
.do_postresize(self
, width
, height
, window
)
142 def do_contentclick(self
, local
, modifiers
, evt
):
143 (what
, message
, when
, where
, modifiers
) = evt
144 self
.ted
.WEClick(local
, modifiers
, when
)
145 self
.updatescrollbars()
146 self
.parent
.updatemenubar()
148 def do_char(self
, ch
, event
):
150 (what
, message
, when
, where
, modifiers
) = event
151 self
.ted
.WEKey(ord(ch
), modifiers
)
153 self
.updatescrollbars()
154 self
.parent
.updatemenubar()
158 save
= EasyDialogs
.AskYesNoCancel('Save window "%s" before closing?'%self
.name
, 1)
163 if self
.parent
.active
== self
:
164 self
.parent
.active
= None
165 self
.parent
.updatemenubar()
167 del self
.tedtexthandle
173 return # Will call us recursively
174 ## print 'Saving to ', self.path
175 dhandle
= self
.ted
.WEGetText()
177 fp
= open(self
.path
, 'wb') # NOTE: wb, because data has CR for end-of-line
179 if data
[-1] <> '\r': fp
.write('\r')
183 def menu_save_as(self
):
184 fss
, ok
= macfs
.StandardPutFile('Save as:')
186 self
.path
= fss
.as_pathname()
187 self
.name
= os
.path
.split(self
.path
)[-1]
188 self
.wid
.SetWTitle(self
.name
)
193 if hasattr(Scrap
, 'ZeroScrap'):
196 Scrap
.ClearCurrentScrap()
198 self
.updatescrollbars()
199 self
.parent
.updatemenubar()
203 if hasattr(Scrap
, 'ZeroScrap'):
206 Scrap
.ClearCurrentScrap()
208 self
.updatescrollbars()
209 self
.parent
.updatemenubar()
211 def menu_paste(self
):
214 self
.updatescrollbars()
215 self
.parent
.updatemenubar()
218 def menu_clear(self
):
221 self
.updatescrollbars()
222 self
.parent
.updatemenubar()
227 self
.updatescrollbars()
228 self
.parent
.updatemenubar()
230 def have_selection(self
):
231 start
, stop
= self
.ted
.WEGetSelection()
235 return self
.ted
.WECanPaste()
238 which
, redo
= self
.ted
.WEGetUndoInfo()
239 which
= UNDOLABELS
[which
]
240 if which
== None: return None
246 class Wed(Application
):
248 Application
.__init
__(self
)
253 def makeusermenus(self
):
254 self
.filemenu
= m
= Menu(self
.menubar
, "File")
255 self
.newitem
= MenuItem(m
, "New window", "N", self
.open)
256 self
.openitem
= MenuItem(m
, "Open...", "O", self
.openfile
)
257 self
.closeitem
= MenuItem(m
, "Close", "W", self
.closewin
)
259 self
.saveitem
= MenuItem(m
, "Save", "S", self
.save
)
260 self
.saveasitem
= MenuItem(m
, "Save as...", "", self
.saveas
)
262 self
.quititem
= MenuItem(m
, "Quit", "Q", self
.quit
)
264 self
.editmenu
= m
= Menu(self
.menubar
, "Edit")
265 self
.undoitem
= MenuItem(m
, "Undo", "Z", self
.undo
)
266 self
.cutitem
= MenuItem(m
, "Cut", "X", self
.cut
)
267 self
.copyitem
= MenuItem(m
, "Copy", "C", self
.copy
)
268 self
.pasteitem
= MenuItem(m
, "Paste", "V", self
.paste
)
269 self
.clearitem
= MenuItem(m
, "Clear", "", self
.clear
)
271 # Groups of items enabled together:
272 self
.windowgroup
= [self
.closeitem
, self
.saveitem
, self
.saveasitem
, self
.editmenu
]
273 self
.focusgroup
= [self
.cutitem
, self
.copyitem
, self
.clearitem
]
274 self
.windowgroup_on
= -1
275 self
.focusgroup_on
= -1
276 self
.pastegroup_on
= -1
277 self
.undo_label
= "never"
279 def updatemenubar(self
):
281 on
= (self
.active
<> None)
282 if on
<> self
.windowgroup_on
:
283 for m
in self
.windowgroup
:
285 self
.windowgroup_on
= on
288 # only if we have an edit menu
289 on
= self
.active
.have_selection()
290 if on
<> self
.focusgroup_on
:
291 for m
in self
.focusgroup
:
293 self
.focusgroup_on
= on
295 on
= self
.active
.can_paste()
296 if on
<> self
.pastegroup_on
:
297 self
.pasteitem
.enable(on
)
298 self
.pastegroup_on
= on
300 on
= self
.active
.can_undo()
301 if on
<> self
.undo_label
:
303 self
.undoitem
.enable(1)
304 self
.undoitem
.settext(on
)
307 self
.undoitem
.settext("Nothing to undo")
308 self
.undoitem
.enable(0)
317 def do_about(self
, id, item
, window
, event
):
318 EasyDialogs
.Message("A simple single-font text editor based on WASTE")
324 def open(self
, *args
):
327 def openfile(self
, *args
):
330 def _open(self
, askfile
):
332 fss
, ok
= macfs
.StandardGetFile('TEXT')
335 path
= fss
.as_pathname()
336 name
= os
.path
.split(path
)[-1]
338 fp
= open(path
, 'rb') # NOTE binary, we need cr as end-of-line
342 EasyDialogs
.Message("IOERROR: "+`arg`
)
346 name
= "Untitled %d"%self
.num
348 w
= WasteWindow(self
)
349 w
.open(path
, name
, data
)
350 self
.num
= self
.num
+ 1
352 def closewin(self
, *args
):
356 EasyDialogs
.Message("No active window?")
358 def save(self
, *args
):
360 self
.active
.menu_save()
362 EasyDialogs
.Message("No active window?")
364 def saveas(self
, *args
):
366 self
.active
.menu_save_as()
368 EasyDialogs
.Message("No active window?")
371 def quit(self
, *args
):
372 for w
in self
._windows
.values():
382 def undo(self
, *args
):
384 self
.active
.menu_undo()
386 EasyDialogs
.Message("No active window?")
388 def cut(self
, *args
):
390 self
.active
.menu_cut()
392 EasyDialogs
.Message("No active window?")
394 def copy(self
, *args
):
396 self
.active
.menu_copy()
398 EasyDialogs
.Message("No active window?")
400 def paste(self
, *args
):
402 self
.active
.menu_paste()
404 EasyDialogs
.Message("No active window?")
406 def clear(self
, *args
):
408 self
.active
.menu_clear()
410 EasyDialogs
.Message("No active window?")
416 def idle(self
, event
):
418 self
.active
.do_idle(event
)
420 Qd
.SetCursor(Qd
.qd
.arrow
)
426 if __name__
== '__main__':