1 # A minimal text editor.
4 # - Functionality: find, etc.
6 from Menu
import DrawMenuBar
7 from FrameWork
import *
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, 0x55555555)
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
)
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
)
196 self
.updatescrollbars()
197 self
.parent
.updatemenubar()
203 self
.updatescrollbars()
204 self
.parent
.updatemenubar()
206 def menu_paste(self
):
209 self
.updatescrollbars()
210 self
.parent
.updatemenubar()
213 def menu_clear(self
):
216 self
.updatescrollbars()
217 self
.parent
.updatemenubar()
222 self
.updatescrollbars()
223 self
.parent
.updatemenubar()
225 def have_selection(self
):
226 start
, stop
= self
.ted
.WEGetSelection()
230 return self
.ted
.WECanPaste()
233 which
, redo
= self
.ted
.WEGetUndoInfo()
234 which
= UNDOLABELS
[which
]
235 if which
== None: return None
241 class Wed(Application
):
243 Application
.__init
__(self
)
248 def makeusermenus(self
):
249 self
.filemenu
= m
= Menu(self
.menubar
, "File")
250 self
.newitem
= MenuItem(m
, "New window", "N", self
.open)
251 self
.openitem
= MenuItem(m
, "Open...", "O", self
.openfile
)
252 self
.closeitem
= MenuItem(m
, "Close", "W", self
.closewin
)
254 self
.saveitem
= MenuItem(m
, "Save", "S", self
.save
)
255 self
.saveasitem
= MenuItem(m
, "Save as...", "", self
.saveas
)
257 self
.quititem
= MenuItem(m
, "Quit", "Q", self
.quit
)
259 self
.editmenu
= m
= Menu(self
.menubar
, "Edit")
260 self
.undoitem
= MenuItem(m
, "Undo", "Z", self
.undo
)
261 self
.cutitem
= MenuItem(m
, "Cut", "X", self
.cut
)
262 self
.copyitem
= MenuItem(m
, "Copy", "C", self
.copy
)
263 self
.pasteitem
= MenuItem(m
, "Paste", "V", self
.paste
)
264 self
.clearitem
= MenuItem(m
, "Clear", "", self
.clear
)
266 # Groups of items enabled together:
267 self
.windowgroup
= [self
.closeitem
, self
.saveitem
, self
.saveasitem
, self
.editmenu
]
268 self
.focusgroup
= [self
.cutitem
, self
.copyitem
, self
.clearitem
]
269 self
.windowgroup_on
= -1
270 self
.focusgroup_on
= -1
271 self
.pastegroup_on
= -1
272 self
.undo_label
= "never"
274 def updatemenubar(self
):
276 on
= (self
.active
<> None)
277 if on
<> self
.windowgroup_on
:
278 for m
in self
.windowgroup
:
280 self
.windowgroup_on
= on
283 # only if we have an edit menu
284 on
= self
.active
.have_selection()
285 if on
<> self
.focusgroup_on
:
286 for m
in self
.focusgroup
:
288 self
.focusgroup_on
= on
290 on
= self
.active
.can_paste()
291 if on
<> self
.pastegroup_on
:
292 self
.pasteitem
.enable(on
)
293 self
.pastegroup_on
= on
295 on
= self
.active
.can_undo()
296 if on
<> self
.undo_label
:
298 self
.undoitem
.enable(1)
299 self
.undoitem
.settext(on
)
302 self
.undoitem
.settext("Nothing to undo")
303 self
.undoitem
.enable(0)
312 def do_about(self
, id, item
, window
, event
):
313 EasyDialogs
.Message("A simple single-font text editor based on WASTE")
319 def open(self
, *args
):
322 def openfile(self
, *args
):
325 def _open(self
, askfile
):
327 fss
, ok
= macfs
.StandardGetFile('TEXT')
330 path
= fss
.as_pathname()
331 name
= os
.path
.split(path
)[-1]
333 fp
= open(path
, 'rb') # NOTE binary, we need cr as end-of-line
337 EasyDialogs
.Message("IOERROR: "+`arg`
)
341 name
= "Untitled %d"%self
.num
343 w
= WasteWindow(self
)
344 w
.open(path
, name
, data
)
345 self
.num
= self
.num
+ 1
347 def closewin(self
, *args
):
351 EasyDialogs
.Message("No active window?")
353 def save(self
, *args
):
355 self
.active
.menu_save()
357 EasyDialogs
.Message("No active window?")
359 def saveas(self
, *args
):
361 self
.active
.menu_save_as()
363 EasyDialogs
.Message("No active window?")
366 def quit(self
, *args
):
367 for w
in self
._windows
.values():
377 def undo(self
, *args
):
379 self
.active
.menu_undo()
381 EasyDialogs
.Message("No active window?")
383 def cut(self
, *args
):
385 self
.active
.menu_cut()
387 EasyDialogs
.Message("No active window?")
389 def copy(self
, *args
):
391 self
.active
.menu_copy()
393 EasyDialogs
.Message("No active window?")
395 def paste(self
, *args
):
397 self
.active
.menu_paste()
399 EasyDialogs
.Message("No active window?")
401 def clear(self
, *args
):
403 self
.active
.menu_clear()
405 EasyDialogs
.Message("No active window?")
411 def idle(self
, event
):
413 self
.active
.do_idle(event
)
419 if __name__
== '__main__':