blob: e21926d9de77c376a2785b71ba2015ca5757f991 [file] [log] [blame]
Just van Rossumf7f93882001-11-02 19:24:41 +00001from Carbon import Evt, Events, Fm, Fonts
2from Carbon import Qd, Res, Scrap
3from Carbon import TE, TextEdit, Win
Just van Rossumf376ef02001-11-18 14:12:43 +00004from Carbon import App
5from Carbon.Appearance import kThemeStateActive, kThemeStateInactive
Just van Rossum40f9b7b1999-01-30 22:39:17 +00006import waste
7import WASTEconst
Just van Rossum40f9b7b1999-01-30 22:39:17 +00008import Wbase
9import Wkeys
10import Wcontrols
11import PyFontify
Just van Rossumf7f93882001-11-02 19:24:41 +000012import string
13from types import TupleType, StringType
Just van Rossum40f9b7b1999-01-30 22:39:17 +000014
15
16class TextBox(Wbase.Widget):
17
18 """A static text widget"""
19
Just van Rossumb7ad8211999-09-26 12:21:32 +000020 def __init__(self, possize, text="", align=TextEdit.teJustLeft,
21 fontsettings=None,
22 backgroundcolor=(0xffff, 0xffff, 0xffff)
Just van Rossum40f9b7b1999-01-30 22:39:17 +000023 ):
Just van Rossumb7ad8211999-09-26 12:21:32 +000024 if fontsettings is None:
25 import W
26 fontsettings = W.getdefaultfont()
Just van Rossum40f9b7b1999-01-30 22:39:17 +000027 Wbase.Widget.__init__(self, possize)
28 self.fontsettings = fontsettings
29 self.text = text
30 self.align = align
31 self._backgroundcolor = backgroundcolor
32
33 def draw(self, visRgn = None):
34 if self._visible:
35 (font, style, size, color) = self.fontsettings
36 fontid = GetFNum(font)
37 savestate = Qd.GetPenState()
38 Qd.TextFont(fontid)
39 Qd.TextFace(style)
40 Qd.TextSize(size)
41 Qd.RGBForeColor(color)
42 Qd.RGBBackColor(self._backgroundcolor)
43 TE.TETextBox(self.text, self._bounds, self.align)
44 Qd.RGBBackColor((0xffff, 0xffff, 0xffff))
45 Qd.SetPenState(savestate)
46
47 def get(self):
48 return self.text
49
50 def set(self, text):
51 self.text = text
52 if self._parentwindow and self._parentwindow.wid:
53 self.SetPort()
54 self.draw()
55
56
57class _ScrollWidget:
58
59 # to be overridden
Just van Rossumf376ef02001-11-18 14:12:43 +000060 def getscrollrects(self):
61 """Return (destrect, viewrect)."""
Just van Rossum40f9b7b1999-01-30 22:39:17 +000062 return None, None
63
64 # internal method
Just van Rossum40f9b7b1999-01-30 22:39:17 +000065
Just van Rossumf376ef02001-11-18 14:12:43 +000066 def updatescrollbars(self):
67 (dl, dt, dr, db), (vl, vt, vr, vb) = self.getscrollrects()
68 if self._parent._barx:
69 viewwidth = vr - vl
70 destwidth = dr - dl
71 bar = self._parent._barx
72 bar.setmax(destwidth - viewwidth)
Jack Jansenb6b6c6c2001-12-04 13:30:29 +000073
74 # MacOS 8.1 doesn't automatically disable
75 # scrollbars whose max <= min
76 bar.enable(destwidth > viewwidth)
77
Just van Rossumf376ef02001-11-18 14:12:43 +000078 bar.setviewsize(viewwidth)
79 bar.set(vl - dl)
80 if self._parent._bary:
81 viewheight = vb - vt
82 destheight = db - dt
83 bar = self._parent._bary
84 bar.setmax(destheight - viewheight)
Jack Jansenb6b6c6c2001-12-04 13:30:29 +000085
86 # MacOS 8.1 doesn't automatically disable
87 # scrollbars whose max <= min
88 bar.enable(destheight > viewheight)
89
Just van Rossumf376ef02001-11-18 14:12:43 +000090 bar.setviewsize(viewheight)
91 bar.set(vt - dt)
92
Just van Rossum40f9b7b1999-01-30 22:39:17 +000093
94UNDOLABELS = [ # Indexed by WEGetUndoInfo() value
Jack Jansen316a0102001-02-21 15:45:55 +000095 None, "", "typing", "Cut", "Paste", "Clear", "Drag", "Style",
96 "Ruler", "backspace", "delete", "transform", "resize"]
Just van Rossum40f9b7b1999-01-30 22:39:17 +000097
98
99class EditText(Wbase.SelectableWidget, _ScrollWidget):
100
101 """A text edit widget, mainly for simple entry fields."""
102
Just van Rossumb7ad8211999-09-26 12:21:32 +0000103 def __init__(self, possize, text="",
104 callback=None, inset=(3, 3),
105 fontsettings=None,
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000106 tabsettings = (32, 0),
107 readonly = 0):
Just van Rossumb7ad8211999-09-26 12:21:32 +0000108 if fontsettings is None:
109 import W
110 fontsettings = W.getdefaultfont()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000111 Wbase.SelectableWidget.__init__(self, possize)
112 self.temptext = text
113 self.ted = None
114 self.selection = None
Just van Rossumf7f93882001-11-02 19:24:41 +0000115 self.oldselection = None
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000116 self._callback = callback
117 self.changed = 0
118 self.selchanged = 0
119 self._selected = 0
120 self._enabled = 1
121 self.wrap = 1
122 self.readonly = readonly
123 self.fontsettings = fontsettings
124 self.tabsettings = tabsettings
125 if type(inset) <> TupleType:
126 self.inset = (inset, inset)
127 else:
128 self.inset = inset
129
130 def open(self):
131 if not hasattr(self._parent, "_barx"):
132 self._parent._barx = None
133 if not hasattr(self._parent, "_bary"):
134 self._parent._bary = None
135 self._calcbounds()
136 self.SetPort()
137 viewrect, destrect = self._calctextbounds()
138 flags = self._getflags()
139 self.ted = waste.WENew(destrect, viewrect, flags)
140 self.ted.WEInstallTabHooks()
141 self.ted.WESetAlignment(WASTEconst.weFlushLeft)
142 self.setfontsettings(self.fontsettings)
143 self.settabsettings(self.tabsettings)
144 self.ted.WEUseText(Res.Resource(self.temptext))
145 self.ted.WECalText()
146 if self.selection:
147 self.setselection(self.selection[0], self.selection[1])
148 self.selection = None
149 else:
150 self.selview()
151 self.temptext = None
152 self.updatescrollbars()
153 self.bind("pageup", self.scrollpageup)
154 self.bind("pagedown", self.scrollpagedown)
155 self.bind("top", self.scrolltop)
156 self.bind("bottom", self.scrollbottom)
157 self.selchanged = 0
158
159 def close(self):
160 self._parent._barx = None
161 self._parent._bary = None
162 self.ted = None
163 self.temptext = None
164 Wbase.SelectableWidget.close(self)
165
Just van Rossumf7f93882001-11-02 19:24:41 +0000166 def textchanged(self, all=0):
167 self.changed = 1
168
169 def selectionchanged(self):
170 self.selchanged = 1
171 self.oldselection = self.getselection()
172
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000173 def gettabsettings(self):
174 return self.tabsettings
175
176 def settabsettings(self, (tabsize, tabmode)):
177 self.tabsettings = (tabsize, tabmode)
178 if hasattr(self.ted, "WESetTabSize"):
179 port = self._parentwindow.wid.GetWindowPort()
180 if tabmode:
181 (font, style, size, color) = self.getfontsettings()
182 savesettings = GetPortFontSettings(port)
183 SetPortFontSettings(port, (font, style, size))
184 tabsize = Qd.StringWidth(' ' * tabsize)
185 SetPortFontSettings(port, savesettings)
186 tabsize = max(tabsize, 1)
187 self.ted.WESetTabSize(tabsize)
188 self.SetPort()
189 Qd.EraseRect(self.ted.WEGetViewRect())
190 self.ted.WEUpdate(port.visRgn)
191
192 def getfontsettings(self):
Jack Jansen5a6fdcd2001-08-25 12:15:04 +0000193 from Carbon import Res
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000194 (font, style, size, color) = self.ted.WEGetRunInfo(0)[4]
195 font = Fm.GetFontName(font)
196 return (font, style, size, color)
197
198 def setfontsettings(self, (font, style, size, color)):
199 self.SetPort()
200 if type(font) <> StringType:
201 font = Fm.GetFontName(font)
202 self.fontsettings = (font, style, size, color)
203 fontid = GetFNum(font)
204 readonly = self.ted.WEFeatureFlag(WASTEconst.weFReadOnly, -1)
205 if readonly:
206 self.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 0)
207 try:
208 self.ted.WEFeatureFlag(WASTEconst.weFInhibitRecal, 1)
209 selstart, selend = self.ted.WEGetSelection()
210 self.ted.WESetSelection(0, self.ted.WEGetTextLength())
211 self.ted.WESetStyle(WASTEconst.weDoFace, (0, 0, 0, (0, 0, 0)))
212 self.ted.WESetStyle(WASTEconst.weDoFace |
213 WASTEconst.weDoColor |
214 WASTEconst.weDoFont |
215 WASTEconst.weDoSize,
216 (fontid, style, size, color))
217 self.ted.WEFeatureFlag(WASTEconst.weFInhibitRecal, 0)
218 self.ted.WECalText()
219 self.ted.WESetSelection(selstart, selend)
220 finally:
221 if readonly:
222 self.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 1)
223 viewrect = self.ted.WEGetViewRect()
224 Qd.EraseRect(viewrect)
225 self.ted.WEUpdate(self._parentwindow.wid.GetWindowPort().visRgn)
Just van Rossumf7f93882001-11-02 19:24:41 +0000226 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000227 self.updatescrollbars()
228
229 def adjust(self, oldbounds):
230 self.SetPort()
Jack Jansenb6b6c6c2001-12-04 13:30:29 +0000231 # Note: if App.DrawThemeEditTextFrame is ever used, it will be necessary
232 # to unconditionally outset the invalidated rectangles, since Appearance
233 # frames are drawn outside the bounds.
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000234 if self._selected and self._parentwindow._hasselframes:
Jack Jansen73023402001-01-23 14:58:20 +0000235 self.GetWindow().InvalWindowRect(Qd.InsetRect(oldbounds, -3, -3))
236 self.GetWindow().InvalWindowRect(Qd.InsetRect(self._bounds, -3, -3))
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000237 else:
Jack Jansen73023402001-01-23 14:58:20 +0000238 self.GetWindow().InvalWindowRect(oldbounds)
239 self.GetWindow().InvalWindowRect(self._bounds)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000240 viewrect, destrect = self._calctextbounds()
241 self.ted.WESetViewRect(viewrect)
242 self.ted.WESetDestRect(destrect)
243 if self.wrap:
244 self.ted.WECalText()
245 if self.ted.WEGetDestRect()[3] < viewrect[1]:
246 self.selview()
247 self.updatescrollbars()
248
249 # interface -----------------------
250 # selection stuff
251 def selview(self):
252 self.ted.WESelView()
253
254 def selectall(self):
255 self.ted.WESetSelection(0, self.ted.WEGetTextLength())
Just van Rossumf7f93882001-11-02 19:24:41 +0000256 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000257 self.updatescrollbars()
258
259 def selectline(self, lineno, charoffset = 0):
260 newselstart, newselend = self.ted.WEGetLineRange(lineno)
261 # Autoscroll makes the *end* of the selection visible, which,
262 # in the case of a whole line, is the beginning of the *next* line.
263 # So sometimes it leaves our line just above the view rect.
264 # Let's fool Waste by initially selecting one char less:
265 self.ted.WESetSelection(newselstart + charoffset, newselend-1)
266 self.ted.WESetSelection(newselstart + charoffset, newselend)
Just van Rossumf7f93882001-11-02 19:24:41 +0000267 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000268 self.updatescrollbars()
269
270 def getselection(self):
271 if self.ted:
272 return self.ted.WEGetSelection()
273 else:
274 return self.selection
275
276 def setselection(self, selstart, selend):
Just van Rossumf7f93882001-11-02 19:24:41 +0000277 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000278 if self.ted:
279 self.ted.WESetSelection(selstart, selend)
280 self.ted.WESelView()
281 self.updatescrollbars()
282 else:
283 self.selection = selstart, selend
284
285 def offsettoline(self, offset):
286 return self.ted.WEOffsetToLine(offset)
287
288 def countlines(self):
289 return self.ted.WECountLines()
290
291 def getselectedtext(self):
292 selstart, selend = self.ted.WEGetSelection()
293 return self.ted.WEGetText().data[selstart:selend]
294
295 def expandselection(self):
296 oldselstart, oldselend = self.ted.WEGetSelection()
297 selstart, selend = min(oldselstart, oldselend), max(oldselstart, oldselend)
298 if selstart <> selend and chr(self.ted.WEGetChar(selend-1)) == '\r':
299 selend = selend - 1
Just van Rossumb10eb842001-06-21 17:51:17 +0000300 newselstart, dummy = self.ted.WEFindLine(selstart, 1)
301 dummy, newselend = self.ted.WEFindLine(selend, 1)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000302 if oldselstart <> newselstart or oldselend <> newselend:
303 self.ted.WESetSelection(newselstart, newselend)
304 self.updatescrollbars()
Just van Rossumf7f93882001-11-02 19:24:41 +0000305 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000306
307 def insert(self, text):
308 self.ted.WEInsert(text, None, None)
Just van Rossumf7f93882001-11-02 19:24:41 +0000309 self.textchanged()
310 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000311
312 # text
313 def set(self, text):
314 if not self.ted:
315 self.temptext = text
316 else:
317 self.ted.WEUseText(Res.Resource(text))
318 self.ted.WECalText()
319 self.SetPort()
320 viewrect, destrect = self._calctextbounds()
321 self.ted.WESetViewRect(viewrect)
322 self.ted.WESetDestRect(destrect)
323 rgn = Qd.NewRgn()
324 Qd.RectRgn(rgn, viewrect)
325 Qd.EraseRect(viewrect)
326 self.draw(rgn)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000327 self.updatescrollbars()
Just van Rossumf7f93882001-11-02 19:24:41 +0000328 self.textchanged(1)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000329
330 def get(self):
331 if not self._parent:
332 return self.temptext
333 else:
334 return self.ted.WEGetText().data
335
336 # events
337 def key(self, char, event):
338 (what, message, when, where, modifiers) = event
339 if self._enabled and not modifiers & Events.cmdKey or char in Wkeys.arrowkeys:
340 self.ted.WEKey(ord(char), modifiers)
341 if char not in Wkeys.navigationkeys:
Just van Rossumf7f93882001-11-02 19:24:41 +0000342 self.textchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000343 if char not in Wkeys.scrollkeys:
Just van Rossumf7f93882001-11-02 19:24:41 +0000344 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000345 self.updatescrollbars()
346 if self._callback:
347 Wbase.CallbackCall(self._callback, 0, char, modifiers)
348
349 def click(self, point, modifiers):
350 if not self._enabled:
351 return
352 self.ted.WEClick(point, modifiers, Evt.TickCount())
Just van Rossumf7f93882001-11-02 19:24:41 +0000353 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000354 self.updatescrollbars()
355 return 1
356
357 def idle(self):
358 self.SetPort()
359 self.ted.WEIdle()
360
361 def rollover(self, point, onoff):
362 if onoff:
363 Wbase.SetCursor("iBeam")
364
365 def activate(self, onoff):
366 self._activated = onoff
Jack Jansenb6b6c6c2001-12-04 13:30:29 +0000367 if self._visible:
368 self.SetPort()
369
370 # DISABLED! There are too many places where it is assumed that
371 # the frame of an EditText item is 1 pixel, inside the bounds.
372 #state = [kThemeStateActive, kThemeStateInactive][not onoff]
373 #App.DrawThemeEditTextFrame(Qd.InsetRect(self._bounds, 1, 1), state)
374
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000375 if self._selected:
Jack Jansenb6b6c6c2001-12-04 13:30:29 +0000376 if onoff:
377 self.ted.WEActivate()
378 else:
379 self.ted.WEDeactivate()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000380 self.drawselframe(onoff)
381
382 def select(self, onoff, isclick = 0):
383 if Wbase.SelectableWidget.select(self, onoff):
384 return
385 self.SetPort()
386 if onoff:
387 self.ted.WEActivate()
388 if self._parentwindow._tabbable and not isclick:
389 self.selectall()
390 else:
391 self.ted.WEDeactivate()
392 self.drawselframe(onoff)
393
394 def draw(self, visRgn = None):
395 if self._visible:
396 if not visRgn:
397 visRgn = self._parentwindow.wid.GetWindowPort().visRgn
398 self.ted.WEUpdate(visRgn)
Jack Jansenb6b6c6c2001-12-04 13:30:29 +0000399
400 # DISABLED! There are too many places where it is assumed that
401 # the frame of an EditText item is 1 pixel, inside the bounds.
402 #state = [kThemeStateActive, kThemeStateInactive][not self._activated]
403 #App.DrawThemeEditTextFrame(Qd.InsetRect(self._bounds, 1, 1), state)
404 Qd.FrameRect(self._bounds)
405
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000406 if self._selected and self._activated:
407 self.drawselframe(1)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000408
409 # scrolling
410 def scrollpageup(self):
411 if self._parent._bary and self._parent._bary._enabled:
412 self.vscroll("++")
413
414 def scrollpagedown(self):
415 if self._parent._bary and self._parent._bary._enabled:
416 self.vscroll("--")
417
418 def scrolltop(self):
419 if self._parent._bary and self._parent._bary._enabled:
Just van Rossumf376ef02001-11-18 14:12:43 +0000420 self.vscroll(self._parent._bary.getmin())
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000421 if self._parent._barx and self._parent._barx._enabled:
Just van Rossumf376ef02001-11-18 14:12:43 +0000422 self.hscroll(self._parent._barx.getmin())
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000423
424 def scrollbottom(self):
425 if self._parent._bary and self._parent._bary._enabled:
Just van Rossumf376ef02001-11-18 14:12:43 +0000426 self.vscroll(self._parent._bary.getmax())
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000427
428 # menu handlers
429 def domenu_copy(self, *args):
430 selbegin, selend = self.ted.WEGetSelection()
431 if selbegin == selend:
432 return
433 Scrap.ZeroScrap()
434 self.ted.WECopy()
435 self.updatescrollbars()
436
437 def domenu_cut(self, *args):
438 selbegin, selend = self.ted.WEGetSelection()
439 if selbegin == selend:
440 return
441 Scrap.ZeroScrap()
442 self.ted.WECut()
443 self.updatescrollbars()
444 self.selview()
Just van Rossumf7f93882001-11-02 19:24:41 +0000445 self.textchanged()
446 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000447 if self._callback:
448 Wbase.CallbackCall(self._callback, 0, "", None)
449
450 def domenu_paste(self, *args):
451 if not self.ted.WECanPaste():
452 return
453 self.selview()
454 self.ted.WEPaste()
455 self.updatescrollbars()
Just van Rossumf7f93882001-11-02 19:24:41 +0000456 self.textchanged()
457 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000458 if self._callback:
459 Wbase.CallbackCall(self._callback, 0, "", None)
460
461 def domenu_clear(self, *args):
462 self.ted.WEDelete()
463 self.selview()
464 self.updatescrollbars()
Just van Rossumf7f93882001-11-02 19:24:41 +0000465 self.textchanged()
466 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000467 if self._callback:
468 Wbase.CallbackCall(self._callback, 0, "", None)
469
470 def domenu_undo(self, *args):
471 which, redo = self.ted.WEGetUndoInfo()
472 if not which:
473 return
474 self.ted.WEUndo()
475 self.updatescrollbars()
Just van Rossumf7f93882001-11-02 19:24:41 +0000476 self.textchanged()
477 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000478 if self._callback:
479 Wbase.CallbackCall(self._callback, 0, "", None)
480
481 def can_undo(self, menuitem):
482 #doundo = self.ted.WEFeatureFlag(WASTEconst.weFUndo, -1)
483 #print doundo
484 #if not doundo:
485 # return 0
486 which, redo = self.ted.WEGetUndoInfo()
Jack Jansen316a0102001-02-21 15:45:55 +0000487 if which < len(UNDOLABELS):
488 which = UNDOLABELS[which]
489 else:
490 which = ""
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000491 if which == None:
492 return None
493 if redo:
494 which = "Redo "+which
495 else:
496 which = "Undo "+which
497 menuitem.settext(which)
498 return 1
499
500 def domenu_selectall(self, *args):
501 self.selectall()
502
503 # private
Just van Rossumf376ef02001-11-18 14:12:43 +0000504 def getscrollrects(self):
505 return self.ted.WEGetDestRect(), self.ted.WEGetViewRect()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000506
507 def vscroll(self, value):
508 lineheight = self.ted.WEGetHeight(0, 1)
509 dr = self.ted.WEGetDestRect()
510 vr = self.ted.WEGetViewRect()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000511 viewheight = vr[3] - vr[1]
Just van Rossumf376ef02001-11-18 14:12:43 +0000512 maxdelta = vr[1] - dr[1]
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000513 mindelta = vr[3] - dr[3]
514 if value == "+":
515 delta = lineheight
516 elif value == "-":
517 delta = - lineheight
518 elif value == "++":
519 delta = viewheight - lineheight
520 elif value == "--":
521 delta = lineheight - viewheight
522 else: # in thumb
Just van Rossumf376ef02001-11-18 14:12:43 +0000523 delta = vr[1] - dr[1] - value
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000524 delta = min(maxdelta, delta)
525 delta = max(mindelta, delta)
526 self.ted.WEScroll(0, delta)
527 self.updatescrollbars()
528
529 def hscroll(self, value):
530 dr = self.ted.WEGetDestRect()
531 vr = self.ted.WEGetViewRect()
532 destwidth = dr[2] - dr[0]
533 viewwidth = vr[2] - vr[0]
534 viewoffset = maxdelta = vr[0] - dr[0]
535 mindelta = vr[2] - dr[2]
536 if value == "+":
537 delta = 32
538 elif value == "-":
539 delta = - 32
540 elif value == "++":
541 delta = 0.5 * (vr[2] - vr[0])
542 elif value == "--":
543 delta = 0.5 * (vr[0] - vr[2])
544 else: # in thumb
Just van Rossumf376ef02001-11-18 14:12:43 +0000545 delta = vr[0] - dr[0] - value
546 #cur = (32767 * viewoffset) / (destwidth - viewwidth)
547 #delta = (cur-value)*(destwidth - viewwidth)/32767
548 #if abs(delta - viewoffset) <=2:
549 # # compensate for irritating rounding error
550 # delta = viewoffset
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000551 delta = min(maxdelta, delta)
552 delta = max(mindelta, delta)
553 self.ted.WEScroll(delta, 0)
554 self.updatescrollbars()
555
556 # some internals
557 def _getflags(self):
558 flags = WASTEconst.weDoAutoScroll | WASTEconst.weDoMonoStyled
559 if self.readonly:
560 flags = flags | WASTEconst.weDoReadOnly
561 else:
562 flags = flags | WASTEconst.weDoUndo
563 return flags
564
565 def _getviewrect(self):
566 return Qd.InsetRect(self._bounds, self.inset[0], self.inset[1])
567
568 def _calctextbounds(self):
569 viewrect = l, t, r, b = self._getviewrect()
570 if self.ted:
571 dl, dt, dr, db = self.ted.WEGetDestRect()
572 vl, vt, vr, vb = self.ted.WEGetViewRect()
573 yshift = t - vt
574 if (db - dt) < (b - t):
575 destrect = viewrect
576 else:
577 destrect = l, dt + yshift, r, db + yshift
578 else:
579 destrect = viewrect
580 return viewrect, destrect
581
582
583class TextEditor(EditText):
584
585 """A text edit widget."""
586
Just van Rossumb7ad8211999-09-26 12:21:32 +0000587 def __init__(self, possize, text="", callback=None, wrap=1, inset=(4, 4),
588 fontsettings=None,
589 tabsettings=(32, 0),
590 readonly=0):
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000591 EditText.__init__(self, possize, text, callback, inset, fontsettings, tabsettings, readonly)
592 self.wrap = wrap
593
594 def _getflags(self):
595 flags = WASTEconst.weDoAutoScroll | WASTEconst.weDoMonoStyled | \
596 WASTEconst.weDoOutlineHilite
597 if self.readonly:
598 flags = flags | WASTEconst.weDoReadOnly
599 else:
600 flags = flags | WASTEconst.weDoUndo
601 return flags
602
603 def _getviewrect(self):
604 l, t, r, b = self._bounds
605 return (l + 5, t + 2, r, b - 2)
606
607 def _calctextbounds(self):
608 if self.wrap:
609 return EditText._calctextbounds(self)
610 else:
611 viewrect = l, t, r, b = self._getviewrect()
612 if self.ted:
613 dl, dt, dr, db = self.ted.WEGetDestRect()
614 vl, vt, vr, vb = self.ted.WEGetViewRect()
615 xshift = l - vl
616 yshift = t - vt
617 if (db - dt) < (b - t):
618 yshift = t - dt
619 destrect = (dl + xshift, dt + yshift, dr + xshift, db + yshift)
620 else:
621 destrect = (l, t, r + 5000, b)
622 return viewrect, destrect
623
624 def draw(self, visRgn = None):
625 if self._visible:
626 if not visRgn:
627 visRgn = self._parentwindow.wid.GetWindowPort().visRgn
628 self.ted.WEUpdate(visRgn)
629 if self._selected and self._activated:
630 self.drawselframe(1)
631
Jack Jansenb6b6c6c2001-12-04 13:30:29 +0000632 def activate(self, onoff):
633 self._activated = onoff
634 if self._visible:
635 self.SetPort()
636 # doesn't draw frame, as EditText.activate does
637 if self._selected:
638 if onoff:
639 self.ted.WEActivate()
640 else:
641 self.ted.WEDeactivate()
642 self.drawselframe(onoff)
643
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000644
Jack Jansen9ad27522001-02-21 13:54:31 +0000645import re
Just van Rossumb10eb842001-06-21 17:51:17 +0000646commentPat = re.compile("[ \t]*(#)")
647indentPat = re.compile("[ \t]*")
Just van Rossumf7f93882001-11-02 19:24:41 +0000648kStringColor = (0, 0x7fff, 0)
649kCommentColor = (0, 0, 0xb000)
Just van Rossumb10eb842001-06-21 17:51:17 +0000650
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000651
652class PyEditor(TextEditor):
653
654 """A specialized Python source edit widget"""
655
Just van Rossumb7ad8211999-09-26 12:21:32 +0000656 def __init__(self, possize, text="", callback=None, inset=(4, 4),
657 fontsettings=None,
658 tabsettings=(32, 0),
659 readonly=0,
660 debugger=None,
661 file=''):
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000662 TextEditor.__init__(self, possize, text, callback, 0, inset, fontsettings, tabsettings, readonly)
663 self.bind("cmd[", self.domenu_shiftleft)
664 self.bind("cmd]", self.domenu_shiftright)
665 self.bind("cmdshift[", self.domenu_uncomment)
666 self.bind("cmdshift]", self.domenu_comment)
Just van Rossumf7f93882001-11-02 19:24:41 +0000667 self.bind("cmdshiftd", self.alldirty)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000668 self.file = file # only for debugger reference
669 self._debugger = debugger
670 if debugger:
671 debugger.register_editor(self, self.file)
Just van Rossumf7f93882001-11-02 19:24:41 +0000672 self._dirty = (0, None)
673 self.do_fontify = 0
674
675 #def open(self):
676 # TextEditor.open(self)
677 # if self.do_fontify:
678 # self.fontify()
679 # self._dirty = (None, None)
680
681 def _getflags(self):
682 flags = (WASTEconst.weDoDrawOffscreen | WASTEconst.weDoUseTempMem |
683 WASTEconst.weDoAutoScroll | WASTEconst.weDoOutlineHilite)
684 if self.readonly:
685 flags = flags | WASTEconst.weDoReadOnly
686 else:
687 flags = flags | WASTEconst.weDoUndo
688 return flags
689
690 def textchanged(self, all=0):
691 self.changed = 1
692 if all:
693 self._dirty = (0, None)
694 return
695 oldsel = self.oldselection
696 sel = self.getselection()
697 if not sel:
698 # XXX what to do?
699 return
700 selstart, selend = sel
701 selstart, selend = min(selstart, selend), max(selstart, selend)
702 if oldsel:
703 oldselstart, oldselend = min(oldsel), max(oldsel)
704 selstart, selend = min(selstart, oldselstart), max(selend, oldselend)
705 startline = self.offsettoline(selstart)
706 endline = self.offsettoline(selend)
707 selstart, _ = self.ted.WEGetLineRange(startline)
708 _, selend = self.ted.WEGetLineRange(endline)
709 if selstart > 0:
710 selstart = selstart - 1
711 self._dirty = (selstart, selend)
712
713 def idle(self):
714 self.SetPort()
715 self.ted.WEIdle()
716 if not self.do_fontify:
717 return
718 start, end = self._dirty
719 if start is None:
720 return
721 textLength = self.ted.WEGetTextLength()
722 if end is None:
723 end = textLength
724 if start >= end:
725 self._dirty = (None, None)
726 else:
727 self.fontify(start, end)
728 self._dirty = (None, None)
729
730 def alldirty(self, *args):
731 self._dirty = (0, None)
732
733 def fontify(self, start=0, end=None):
734 #W.SetCursor('watch')
735 if self.readonly:
736 self.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 0)
737 self.ted.WEFeatureFlag(WASTEconst.weFOutlineHilite, 0)
738 self.ted.WEDeactivate()
739 self.ted.WEFeatureFlag(WASTEconst.weFAutoScroll, 0)
740 self.ted.WEFeatureFlag(WASTEconst.weFUndo, 0)
741 pytext = self.get().replace("\r", "\n")
742 if end is None:
743 end = len(pytext)
744 else:
745 end = min(end, len(pytext))
746 selstart, selend = self.ted.WEGetSelection()
747 self.ted.WESetSelection(start, end)
748 self.ted.WESetStyle(WASTEconst.weDoFace | WASTEconst.weDoColor,
749 (0, 0, 12, (0, 0, 0)))
750
751 tags = PyFontify.fontify(pytext, start, end)
752 styles = {
753 'string': (WASTEconst.weDoColor, (0, 0, 0, kStringColor)),
754 'keyword': (WASTEconst.weDoFace, (0, 1, 0, (0, 0, 0))),
755 'comment': (WASTEconst.weDoFace | WASTEconst.weDoColor, (0, 0, 0, kCommentColor)),
756 'identifier': (WASTEconst.weDoColor, (0, 0, 0, (0xbfff, 0, 0)))
757 }
758 setselection = self.ted.WESetSelection
759 setstyle = self.ted.WESetStyle
760 for tag, start, end, sublist in tags:
761 setselection(start, end)
762 mode, style = styles[tag]
763 setstyle(mode, style)
764 self.ted.WESetSelection(selstart, selend)
765 self.SetPort()
766 self.ted.WEFeatureFlag(WASTEconst.weFAutoScroll, 1)
767 self.ted.WEFeatureFlag(WASTEconst.weFUndo, 1)
768 self.ted.WEActivate()
769 self.ted.WEFeatureFlag(WASTEconst.weFOutlineHilite, 1)
770 if self.readonly:
771 self.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 1)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000772
773 def domenu_shiftleft(self):
774 self.expandselection()
775 selstart, selend = self.ted.WEGetSelection()
776 selstart, selend = min(selstart, selend), max(selstart, selend)
777 snippet = self.getselectedtext()
778 lines = string.split(snippet, '\r')
779 for i in range(len(lines)):
780 if lines[i][:1] == '\t':
781 lines[i] = lines[i][1:]
782 snippet = string.join(lines, '\r')
783 self.insert(snippet)
784 self.ted.WESetSelection(selstart, selstart + len(snippet))
785
786 def domenu_shiftright(self):
787 self.expandselection()
788 selstart, selend = self.ted.WEGetSelection()
789 selstart, selend = min(selstart, selend), max(selstart, selend)
790 snippet = self.getselectedtext()
791 lines = string.split(snippet, '\r')
792 for i in range(len(lines) - (not lines[-1])):
793 lines[i] = '\t' + lines[i]
794 snippet = string.join(lines, '\r')
795 self.insert(snippet)
796 self.ted.WESetSelection(selstart, selstart + len(snippet))
797
798 def domenu_uncomment(self):
799 self.expandselection()
800 selstart, selend = self.ted.WEGetSelection()
801 selstart, selend = min(selstart, selend), max(selstart, selend)
802 snippet = self.getselectedtext()
803 lines = string.split(snippet, '\r')
804 for i in range(len(lines)):
Jack Jansen9ad27522001-02-21 13:54:31 +0000805 m = commentPat.match(lines[i])
806 if m:
807 pos = m.start(1)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000808 lines[i] = lines[i][:pos] + lines[i][pos+1:]
809 snippet = string.join(lines, '\r')
810 self.insert(snippet)
811 self.ted.WESetSelection(selstart, selstart + len(snippet))
812
813 def domenu_comment(self):
814 self.expandselection()
815 selstart, selend = self.ted.WEGetSelection()
816 selstart, selend = min(selstart, selend), max(selstart, selend)
817 snippet = self.getselectedtext()
818 lines = string.split(snippet, '\r')
819 indent = 3000 # arbitrary large number...
820 for line in lines:
821 if string.strip(line):
Jack Jansen9ad27522001-02-21 13:54:31 +0000822 m = indentPat.match(line)
823 if m:
824 indent = min(indent, m.regs[0][1])
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000825 else:
826 indent = 0
827 break
828 for i in range(len(lines) - (not lines[-1])):
829 lines[i] = lines[i][:indent] + "#" + lines[i][indent:]
830 snippet = string.join(lines, '\r')
831 self.insert(snippet)
832 self.ted.WESetSelection(selstart, selstart + len(snippet))
833
834 def setfile(self, file):
835 self.file = file
836
837 def set(self, text, file = ''):
838 oldfile = self.file
839 self.file = file
840 if self._debugger:
841 self._debugger.unregister_editor(self, oldfile)
842 self._debugger.register_editor(self, file)
843 TextEditor.set(self, text)
844
845 def close(self):
846 if self._debugger:
847 self._debugger.unregister_editor(self, self.file)
848 self._debugger = None
849 TextEditor.close(self)
850
851 def click(self, point, modifiers):
852 if not self._enabled:
853 return
854 if self._debugger and self.pt_in_breaks(point):
855 self.breakhit(point, modifiers)
856 elif self._debugger:
857 bl, bt, br, bb = self._getbreakrect()
858 Qd.EraseRect((bl, bt, br-1, bb))
859 TextEditor.click(self, point, modifiers)
860 self.drawbreakpoints()
861 else:
862 TextEditor.click(self, point, modifiers)
863 if self.ted.WEGetClickCount() >= 3:
864 # select block with our indent
865 lines = string.split(self.get(), '\r')
866 selstart, selend = self.ted.WEGetSelection()
867 lineno = self.ted.WEOffsetToLine(selstart)
868 tabs = 0
869 line = lines[lineno]
870 while line[tabs:] and line[tabs] == '\t':
871 tabs = tabs + 1
872 tabstag = '\t' * tabs
873 fromline = 0
874 toline = len(lines)
875 if tabs:
876 for i in range(lineno - 1, -1, -1):
877 line = lines[i]
878 if line[:tabs] <> tabstag:
879 fromline = i + 1
880 break
881 for i in range(lineno + 1, toline):
882 line = lines[i]
883 if line[:tabs] <> tabstag:
884 toline = i - 1
885 break
886 selstart, dummy = self.ted.WEGetLineRange(fromline)
887 dummy, selend = self.ted.WEGetLineRange(toline)
888 self.ted.WESetSelection(selstart, selend)
889
890 def breakhit(self, point, modifiers):
891 if not self.file:
892 return
893 destrect = self.ted.WEGetDestRect()
894 offset, edge = self.ted.WEGetOffset(point)
895 lineno = self.ted.WEOffsetToLine(offset) + 1
896 if point[1] <= destrect[3]:
897 self._debugger.clear_breaks_above(self.file, self.countlines())
898 self._debugger.toggle_break(self.file, lineno)
899 else:
900 self._debugger.clear_breaks_above(self.file, lineno)
901
902 def key(self, char, event):
903 (what, message, when, where, modifiers) = event
904 if modifiers & Events.cmdKey and not char in Wkeys.arrowkeys:
905 return
906 if char == '\r':
907 selstart, selend = self.ted.WEGetSelection()
908 selstart, selend = min(selstart, selend), max(selstart, selend)
909 lastchar = chr(self.ted.WEGetChar(selstart-1))
910 if lastchar <> '\r' and selstart:
911 pos, dummy = self.ted.WEFindLine(selstart, 0)
912 lineres = Res.Resource('')
913 self.ted.WECopyRange(pos, selstart, lineres, None, None)
914 line = lineres.data + '\n'
915 tabcount = self.extratabs(line)
916 self.ted.WEKey(ord('\r'), 0)
917 for i in range(tabcount):
918 self.ted.WEKey(ord('\t'), 0)
919 else:
920 self.ted.WEKey(ord('\r'), 0)
921 elif char in ')]}':
922 self.ted.WEKey(ord(char), modifiers)
923 self.balanceparens(char)
924 else:
925 self.ted.WEKey(ord(char), modifiers)
926 if char not in Wkeys.navigationkeys:
Just van Rossumf7f93882001-11-02 19:24:41 +0000927 self.textchanged()
928 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000929 self.updatescrollbars()
930
931 def balanceparens(self, char):
932 if char == ')':
933 target = '('
934 elif char == ']':
935 target = '['
936 elif char == '}':
937 target = '{'
938 recursionlevel = 1
939 selstart, selend = self.ted.WEGetSelection()
940 count = min(selstart, selend) - 2
941 mincount = max(0, count - 2048)
942 lastquote = None
943 while count > mincount:
944 testchar = chr(self.ted.WEGetChar(count))
945 if testchar in "\"'" and chr(self.ted.WEGetChar(count - 1)) <> '\\':
946 if lastquote == testchar:
947 recursionlevel = recursionlevel - 1
948 lastquote = None
949 elif not lastquote:
950 recursionlevel = recursionlevel + 1
951 lastquote = testchar
952 elif not lastquote and testchar == char:
953 recursionlevel = recursionlevel + 1
954 elif not lastquote and testchar == target:
955 recursionlevel = recursionlevel - 1
956 if recursionlevel == 0:
957 import time
958 autoscroll = self.ted.WEFeatureFlag(WASTEconst.weFAutoScroll, -1)
959 if autoscroll:
960 self.ted.WEFeatureFlag(WASTEconst.weFAutoScroll, 0)
961 self.ted.WESetSelection(count, count + 1)
Just van Rossumf376ef02001-11-18 14:12:43 +0000962 Qd.QDFlushPortBuffer(self._parentwindow.wid, None) # needed under OSX
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000963 time.sleep(0.2)
964 self.ted.WESetSelection(selstart, selend)
965 if autoscroll:
966 self.ted.WEFeatureFlag(WASTEconst.weFAutoScroll, 1)
967 break
968 count = count - 1
969
970 def extratabs(self, line):
971 tabcount = 0
972 for c in line:
973 if c <> '\t':
974 break
975 tabcount = tabcount + 1
976 last = 0
977 cleanline = ''
978 tags = PyFontify.fontify(line)
979 # strip comments and strings
980 for tag, start, end, sublist in tags:
981 if tag in ('string', 'comment'):
982 cleanline = cleanline + line[last:start]
983 last = end
984 cleanline = cleanline + line[last:]
985 cleanline = string.strip(cleanline)
986 if cleanline and cleanline[-1] == ':':
987 tabcount = tabcount + 1
988 else:
989 # extra indent after unbalanced (, [ or {
990 for open, close in (('(', ')'), ('[', ']'), ('{', '}')):
991 count = string.count(cleanline, open)
992 if count and count > string.count(cleanline, close):
993 tabcount = tabcount + 2
994 break
995 return tabcount
996
997 def rollover(self, point, onoff):
998 if onoff:
999 if self._debugger and self.pt_in_breaks(point):
1000 Wbase.SetCursor("arrow")
1001 else:
1002 Wbase.SetCursor("iBeam")
1003
1004 def draw(self, visRgn = None):
1005 TextEditor.draw(self, visRgn)
1006 if self._debugger:
1007 self.drawbreakpoints()
1008
1009 def showbreakpoints(self, onoff):
1010 if (not not self._debugger) <> onoff:
1011 if onoff:
1012 if not __debug__:
1013 import W
Just van Rossumdc3c6172001-06-19 21:37:33 +00001014 raise W.AlertError, "Can't debug in \"Optimize bytecode\" mode.\r(see \"Default startup options\" in EditPythonPreferences)"
Just van Rossum40f9b7b1999-01-30 22:39:17 +00001015 import PyDebugger
1016 self._debugger = PyDebugger.getdebugger()
1017 self._debugger.register_editor(self, self.file)
1018 elif self._debugger:
1019 self._debugger.unregister_editor(self, self.file)
1020 self._debugger = None
1021 self.adjust(self._bounds)
1022
1023 def togglebreakpoints(self):
1024 self.showbreakpoints(not self._debugger)
1025
1026 def clearbreakpoints(self):
1027 if self.file:
1028 self._debugger.clear_all_file_breaks(self.file)
1029
1030 def editbreakpoints(self):
1031 if self._debugger:
1032 self._debugger.edit_breaks()
1033 self._debugger.breaksviewer.selectfile(self.file)
1034
1035 def drawbreakpoints(self, eraseall = 0):
1036 breakrect = bl, bt, br, bb = self._getbreakrect()
1037 br = br - 1
1038 self.SetPort()
1039 Qd.PenPat(Qd.qd.gray)
1040 Qd.PaintRect((br, bt, br + 1, bb))
1041 Qd.PenNormal()
1042 self._parentwindow.tempcliprect(breakrect)
1043 Qd.RGBForeColor((0xffff, 0, 0))
1044 try:
1045 lasttop = bt
1046 self_ted = self.ted
1047 Qd_PaintOval = Qd.PaintOval
1048 Qd_EraseRect = Qd.EraseRect
1049 for lineno in self._debugger.get_file_breaks(self.file):
1050 start, end = self_ted.WEGetLineRange(lineno - 1)
1051 if lineno <> self_ted.WEOffsetToLine(start) + 1:
1052 # breakpoints beyond our text: erase rest, and back out
1053 Qd_EraseRect((bl, lasttop, br, bb))
1054 break
1055 (x, y), h = self_ted.WEGetPoint(start, 0)
1056 bottom = y + h
1057 #print y, (lasttop, bottom)
1058 if bottom > lasttop:
1059 Qd_EraseRect((bl, lasttop, br, y + h * eraseall))
1060 lasttop = bottom
1061 redbullet = bl + 2, y + 3, bl + 8, y + 9
1062 Qd_PaintOval(redbullet)
1063 else:
1064 Qd_EraseRect((bl, lasttop, br, bb))
1065 Qd.RGBForeColor((0, 0, 0))
1066 finally:
1067 self._parentwindow.restoreclip()
1068
1069 def updatescrollbars(self):
1070 if self._debugger:
1071 self.drawbreakpoints(1)
1072 TextEditor.updatescrollbars(self)
1073
1074 def pt_in_breaks(self, point):
1075 return Qd.PtInRect(point, self._getbreakrect())
1076
1077 def _getbreakrect(self):
1078 if self._debugger:
1079 l, t, r, b = self._bounds
1080 return (l+1, t+1, l + 12, b-1)
1081 else:
1082 return (0, 0, 0, 0)
1083
1084 def _getviewrect(self):
1085 l, t, r, b = self._bounds
1086 if self._debugger:
1087 return (l + 17, t + 2, r, b - 2)
1088 else:
1089 return (l + 5, t + 2, r, b - 2)
1090
1091 def _calctextbounds(self):
1092 viewrect = l, t, r, b = self._getviewrect()
1093 if self.ted:
1094 dl, dt, dr, db = self.ted.WEGetDestRect()
1095 vl, vt, vr, vb = self.ted.WEGetViewRect()
1096 xshift = l - vl
1097 yshift = t - vt
1098 if (db - dt) < (b - t):
1099 yshift = t - dt
1100 destrect = (dl + xshift, dt + yshift, dr + xshift, db + yshift)
1101 else:
1102 destrect = (l, t, r + 5000, b)
1103 return viewrect, destrect
1104
1105
1106def GetFNum(fontname):
1107 """Same as Fm.GetFNum(), but maps a missing font to Monaco instead of the system font."""
1108 if fontname <> Fm.GetFontName(0):
1109 fontid = Fm.GetFNum(fontname)
1110 if fontid == 0:
1111 fontid = Fonts.monaco
1112 else:
1113 fontid = 0
1114 return fontid
1115
1116# b/w compat. Anyone using this?
1117GetFName = Fm.GetFontName
1118
1119def GetPortFontSettings(port):
1120 return Fm.GetFontName(port.txFont), port.txFace, port.txSize
1121
1122def SetPortFontSettings(port, (font, face, size)):
1123 saveport = Qd.GetPort()
1124 Qd.SetPort(port)
1125 Qd.TextFont(GetFNum(font))
1126 Qd.TextFace(face)
1127 Qd.TextSize(size)
1128 Qd.SetPort(saveport)