blob: 3b8973ad11ff386ec5678b31d3f37a0ccc32e48d [file] [log] [blame]
Just van Rossum40f9b7b1999-01-30 22:39:17 +00001import Qd
2import TE
3import Fm
4import waste
5import WASTEconst
6import Res
7import Evt
8import Events
9import Scrap
10import string
11
12import Win
13import Wbase
14import Wkeys
15import Wcontrols
16import PyFontify
17from types import *
18import Fonts
19import TextEdit
20
21
22
23class TextBox(Wbase.Widget):
24
25 """A static text widget"""
26
Just van Rossumb7ad8211999-09-26 12:21:32 +000027 def __init__(self, possize, text="", align=TextEdit.teJustLeft,
28 fontsettings=None,
29 backgroundcolor=(0xffff, 0xffff, 0xffff)
Just van Rossum40f9b7b1999-01-30 22:39:17 +000030 ):
Just van Rossumb7ad8211999-09-26 12:21:32 +000031 if fontsettings is None:
32 import W
33 fontsettings = W.getdefaultfont()
Just van Rossum40f9b7b1999-01-30 22:39:17 +000034 Wbase.Widget.__init__(self, possize)
35 self.fontsettings = fontsettings
36 self.text = text
37 self.align = align
38 self._backgroundcolor = backgroundcolor
39
40 def draw(self, visRgn = None):
41 if self._visible:
42 (font, style, size, color) = self.fontsettings
43 fontid = GetFNum(font)
44 savestate = Qd.GetPenState()
45 Qd.TextFont(fontid)
46 Qd.TextFace(style)
47 Qd.TextSize(size)
48 Qd.RGBForeColor(color)
49 Qd.RGBBackColor(self._backgroundcolor)
50 TE.TETextBox(self.text, self._bounds, self.align)
51 Qd.RGBBackColor((0xffff, 0xffff, 0xffff))
52 Qd.SetPenState(savestate)
53
54 def get(self):
55 return self.text
56
57 def set(self, text):
58 self.text = text
59 if self._parentwindow and self._parentwindow.wid:
60 self.SetPort()
61 self.draw()
62
63
64class _ScrollWidget:
65
66 # to be overridden
67 def getscrollbarvalues(self):
68 return None, None
69
70 # internal method
71 def updatescrollbars(self):
72 vx, vy = self.getscrollbarvalues()
73 if self._parent._barx:
74 if vx <> None:
75 self._parent._barx.enable(1)
76 self._parent._barx.set(vx)
77 else:
78 self._parent._barx.enable(0)
79 if self._parent._bary:
80 if vy <> None:
81 self._parent._bary.enable(1)
82 self._parent._bary.set(vy)
83 else:
84 self._parent._bary.enable(0)
85
86
87UNDOLABELS = [ # Indexed by WEGetUndoInfo() value
Jack Jansen316a0102001-02-21 15:45:55 +000088 None, "", "typing", "Cut", "Paste", "Clear", "Drag", "Style",
89 "Ruler", "backspace", "delete", "transform", "resize"]
Just van Rossum40f9b7b1999-01-30 22:39:17 +000090
91
92class EditText(Wbase.SelectableWidget, _ScrollWidget):
93
94 """A text edit widget, mainly for simple entry fields."""
95
Just van Rossumb7ad8211999-09-26 12:21:32 +000096 def __init__(self, possize, text="",
97 callback=None, inset=(3, 3),
98 fontsettings=None,
Just van Rossum40f9b7b1999-01-30 22:39:17 +000099 tabsettings = (32, 0),
100 readonly = 0):
Just van Rossumb7ad8211999-09-26 12:21:32 +0000101 if fontsettings is None:
102 import W
103 fontsettings = W.getdefaultfont()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000104 Wbase.SelectableWidget.__init__(self, possize)
105 self.temptext = text
106 self.ted = None
107 self.selection = None
108 self._callback = callback
109 self.changed = 0
110 self.selchanged = 0
111 self._selected = 0
112 self._enabled = 1
113 self.wrap = 1
114 self.readonly = readonly
115 self.fontsettings = fontsettings
116 self.tabsettings = tabsettings
117 if type(inset) <> TupleType:
118 self.inset = (inset, inset)
119 else:
120 self.inset = inset
121
122 def open(self):
123 if not hasattr(self._parent, "_barx"):
124 self._parent._barx = None
125 if not hasattr(self._parent, "_bary"):
126 self._parent._bary = None
127 self._calcbounds()
128 self.SetPort()
129 viewrect, destrect = self._calctextbounds()
130 flags = self._getflags()
131 self.ted = waste.WENew(destrect, viewrect, flags)
132 self.ted.WEInstallTabHooks()
133 self.ted.WESetAlignment(WASTEconst.weFlushLeft)
134 self.setfontsettings(self.fontsettings)
135 self.settabsettings(self.tabsettings)
136 self.ted.WEUseText(Res.Resource(self.temptext))
137 self.ted.WECalText()
138 if self.selection:
139 self.setselection(self.selection[0], self.selection[1])
140 self.selection = None
141 else:
142 self.selview()
143 self.temptext = None
144 self.updatescrollbars()
145 self.bind("pageup", self.scrollpageup)
146 self.bind("pagedown", self.scrollpagedown)
147 self.bind("top", self.scrolltop)
148 self.bind("bottom", self.scrollbottom)
149 self.selchanged = 0
150
151 def close(self):
152 self._parent._barx = None
153 self._parent._bary = None
154 self.ted = None
155 self.temptext = None
156 Wbase.SelectableWidget.close(self)
157
158 def gettabsettings(self):
159 return self.tabsettings
160
161 def settabsettings(self, (tabsize, tabmode)):
162 self.tabsettings = (tabsize, tabmode)
163 if hasattr(self.ted, "WESetTabSize"):
164 port = self._parentwindow.wid.GetWindowPort()
165 if tabmode:
166 (font, style, size, color) = self.getfontsettings()
167 savesettings = GetPortFontSettings(port)
168 SetPortFontSettings(port, (font, style, size))
169 tabsize = Qd.StringWidth(' ' * tabsize)
170 SetPortFontSettings(port, savesettings)
171 tabsize = max(tabsize, 1)
172 self.ted.WESetTabSize(tabsize)
173 self.SetPort()
174 Qd.EraseRect(self.ted.WEGetViewRect())
175 self.ted.WEUpdate(port.visRgn)
176
177 def getfontsettings(self):
178 import Res
179 (font, style, size, color) = self.ted.WEGetRunInfo(0)[4]
180 font = Fm.GetFontName(font)
181 return (font, style, size, color)
182
183 def setfontsettings(self, (font, style, size, color)):
184 self.SetPort()
185 if type(font) <> StringType:
186 font = Fm.GetFontName(font)
187 self.fontsettings = (font, style, size, color)
188 fontid = GetFNum(font)
189 readonly = self.ted.WEFeatureFlag(WASTEconst.weFReadOnly, -1)
190 if readonly:
191 self.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 0)
192 try:
193 self.ted.WEFeatureFlag(WASTEconst.weFInhibitRecal, 1)
194 selstart, selend = self.ted.WEGetSelection()
195 self.ted.WESetSelection(0, self.ted.WEGetTextLength())
196 self.ted.WESetStyle(WASTEconst.weDoFace, (0, 0, 0, (0, 0, 0)))
197 self.ted.WESetStyle(WASTEconst.weDoFace |
198 WASTEconst.weDoColor |
199 WASTEconst.weDoFont |
200 WASTEconst.weDoSize,
201 (fontid, style, size, color))
202 self.ted.WEFeatureFlag(WASTEconst.weFInhibitRecal, 0)
203 self.ted.WECalText()
204 self.ted.WESetSelection(selstart, selend)
205 finally:
206 if readonly:
207 self.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 1)
208 viewrect = self.ted.WEGetViewRect()
209 Qd.EraseRect(viewrect)
210 self.ted.WEUpdate(self._parentwindow.wid.GetWindowPort().visRgn)
211 self.selchanged = 1
212 self.updatescrollbars()
213
214 def adjust(self, oldbounds):
215 self.SetPort()
216 if self._selected and self._parentwindow._hasselframes:
Jack Jansen73023402001-01-23 14:58:20 +0000217 self.GetWindow().InvalWindowRect(Qd.InsetRect(oldbounds, -3, -3))
218 self.GetWindow().InvalWindowRect(Qd.InsetRect(self._bounds, -3, -3))
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000219 else:
Jack Jansen73023402001-01-23 14:58:20 +0000220 self.GetWindow().InvalWindowRect(oldbounds)
221 self.GetWindow().InvalWindowRect(self._bounds)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000222 viewrect, destrect = self._calctextbounds()
223 self.ted.WESetViewRect(viewrect)
224 self.ted.WESetDestRect(destrect)
225 if self.wrap:
226 self.ted.WECalText()
227 if self.ted.WEGetDestRect()[3] < viewrect[1]:
228 self.selview()
229 self.updatescrollbars()
230
231 # interface -----------------------
232 # selection stuff
233 def selview(self):
234 self.ted.WESelView()
235
236 def selectall(self):
237 self.ted.WESetSelection(0, self.ted.WEGetTextLength())
238 self.selchanged = 1
239 self.updatescrollbars()
240
241 def selectline(self, lineno, charoffset = 0):
242 newselstart, newselend = self.ted.WEGetLineRange(lineno)
243 # Autoscroll makes the *end* of the selection visible, which,
244 # in the case of a whole line, is the beginning of the *next* line.
245 # So sometimes it leaves our line just above the view rect.
246 # Let's fool Waste by initially selecting one char less:
247 self.ted.WESetSelection(newselstart + charoffset, newselend-1)
248 self.ted.WESetSelection(newselstart + charoffset, newselend)
249 self.selchanged = 1
250 self.updatescrollbars()
251
252 def getselection(self):
253 if self.ted:
254 return self.ted.WEGetSelection()
255 else:
256 return self.selection
257
258 def setselection(self, selstart, selend):
259 self.selchanged = 1
260 if self.ted:
261 self.ted.WESetSelection(selstart, selend)
262 self.ted.WESelView()
263 self.updatescrollbars()
264 else:
265 self.selection = selstart, selend
266
267 def offsettoline(self, offset):
268 return self.ted.WEOffsetToLine(offset)
269
270 def countlines(self):
271 return self.ted.WECountLines()
272
273 def getselectedtext(self):
274 selstart, selend = self.ted.WEGetSelection()
275 return self.ted.WEGetText().data[selstart:selend]
276
277 def expandselection(self):
278 oldselstart, oldselend = self.ted.WEGetSelection()
279 selstart, selend = min(oldselstart, oldselend), max(oldselstart, oldselend)
280 if selstart <> selend and chr(self.ted.WEGetChar(selend-1)) == '\r':
281 selend = selend - 1
Just van Rossumb10eb842001-06-21 17:51:17 +0000282 newselstart, dummy = self.ted.WEFindLine(selstart, 1)
283 dummy, newselend = self.ted.WEFindLine(selend, 1)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000284 if oldselstart <> newselstart or oldselend <> newselend:
285 self.ted.WESetSelection(newselstart, newselend)
286 self.updatescrollbars()
287 self.selchanged = 1
288
289 def insert(self, text):
290 self.ted.WEInsert(text, None, None)
291 self.changed = 1
292 self.selchanged = 1
293
294 # text
295 def set(self, text):
296 if not self.ted:
297 self.temptext = text
298 else:
299 self.ted.WEUseText(Res.Resource(text))
300 self.ted.WECalText()
301 self.SetPort()
302 viewrect, destrect = self._calctextbounds()
303 self.ted.WESetViewRect(viewrect)
304 self.ted.WESetDestRect(destrect)
305 rgn = Qd.NewRgn()
306 Qd.RectRgn(rgn, viewrect)
307 Qd.EraseRect(viewrect)
308 self.draw(rgn)
Jack Jansen73023402001-01-23 14:58:20 +0000309 #self.GetWindow().InvalWindowRect(self.ted.WEGetViewRect())
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000310 self.updatescrollbars()
311
312 def get(self):
313 if not self._parent:
314 return self.temptext
315 else:
316 return self.ted.WEGetText().data
317
318 # events
319 def key(self, char, event):
320 (what, message, when, where, modifiers) = event
321 if self._enabled and not modifiers & Events.cmdKey or char in Wkeys.arrowkeys:
322 self.ted.WEKey(ord(char), modifiers)
323 if char not in Wkeys.navigationkeys:
324 self.changed = 1
325 if char not in Wkeys.scrollkeys:
326 self.selchanged = 1
327 self.updatescrollbars()
328 if self._callback:
329 Wbase.CallbackCall(self._callback, 0, char, modifiers)
330
331 def click(self, point, modifiers):
332 if not self._enabled:
333 return
334 self.ted.WEClick(point, modifiers, Evt.TickCount())
335 self.selchanged = 1
336 self.updatescrollbars()
337 return 1
338
339 def idle(self):
340 self.SetPort()
341 self.ted.WEIdle()
342
343 def rollover(self, point, onoff):
344 if onoff:
345 Wbase.SetCursor("iBeam")
346
347 def activate(self, onoff):
348 self._activated = onoff
349 if self._selected and self._visible:
350 if onoff:
351 self.ted.WEActivate()
352 else:
353 self.ted.WEDeactivate()
354 if self._selected:
355 self.drawselframe(onoff)
356
357 def select(self, onoff, isclick = 0):
358 if Wbase.SelectableWidget.select(self, onoff):
359 return
360 self.SetPort()
361 if onoff:
362 self.ted.WEActivate()
363 if self._parentwindow._tabbable and not isclick:
364 self.selectall()
365 else:
366 self.ted.WEDeactivate()
367 self.drawselframe(onoff)
368
369 def draw(self, visRgn = None):
370 if self._visible:
371 if not visRgn:
372 visRgn = self._parentwindow.wid.GetWindowPort().visRgn
373 self.ted.WEUpdate(visRgn)
374 if self._selected and self._activated:
375 self.drawselframe(1)
376 Qd.FrameRect(self._bounds)
377
378 # scrolling
379 def scrollpageup(self):
380 if self._parent._bary and self._parent._bary._enabled:
381 self.vscroll("++")
382
383 def scrollpagedown(self):
384 if self._parent._bary and self._parent._bary._enabled:
385 self.vscroll("--")
386
387 def scrolltop(self):
388 if self._parent._bary and self._parent._bary._enabled:
389 self.vscroll(0)
390 if self._parent._barx and self._parent._barx._enabled:
391 self.hscroll(0)
392
393 def scrollbottom(self):
394 if self._parent._bary and self._parent._bary._enabled:
395 self.vscroll(32767)
396
397 # menu handlers
398 def domenu_copy(self, *args):
399 selbegin, selend = self.ted.WEGetSelection()
400 if selbegin == selend:
401 return
402 Scrap.ZeroScrap()
403 self.ted.WECopy()
404 self.updatescrollbars()
405
406 def domenu_cut(self, *args):
407 selbegin, selend = self.ted.WEGetSelection()
408 if selbegin == selend:
409 return
410 Scrap.ZeroScrap()
411 self.ted.WECut()
412 self.updatescrollbars()
413 self.selview()
414 self.changed = 1
415 self.selchanged = 1
416 if self._callback:
417 Wbase.CallbackCall(self._callback, 0, "", None)
418
419 def domenu_paste(self, *args):
420 if not self.ted.WECanPaste():
421 return
422 self.selview()
423 self.ted.WEPaste()
424 self.updatescrollbars()
425 self.changed = 1
426 self.selchanged = 1
427 if self._callback:
428 Wbase.CallbackCall(self._callback, 0, "", None)
429
430 def domenu_clear(self, *args):
431 self.ted.WEDelete()
432 self.selview()
433 self.updatescrollbars()
434 self.changed = 1
435 self.selchanged = 1
436 if self._callback:
437 Wbase.CallbackCall(self._callback, 0, "", None)
438
439 def domenu_undo(self, *args):
440 which, redo = self.ted.WEGetUndoInfo()
441 if not which:
442 return
443 self.ted.WEUndo()
444 self.updatescrollbars()
445 self.changed = 1
446 self.selchanged = 1
447 if self._callback:
448 Wbase.CallbackCall(self._callback, 0, "", None)
449
450 def can_undo(self, menuitem):
451 #doundo = self.ted.WEFeatureFlag(WASTEconst.weFUndo, -1)
452 #print doundo
453 #if not doundo:
454 # return 0
455 which, redo = self.ted.WEGetUndoInfo()
Jack Jansen316a0102001-02-21 15:45:55 +0000456 if which < len(UNDOLABELS):
457 which = UNDOLABELS[which]
458 else:
459 which = ""
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000460 if which == None:
461 return None
462 if redo:
463 which = "Redo "+which
464 else:
465 which = "Undo "+which
466 menuitem.settext(which)
467 return 1
468
469 def domenu_selectall(self, *args):
470 self.selectall()
471
472 # private
473 def getscrollbarvalues(self):
474 dr = self.ted.WEGetDestRect()
475 vr = self.ted.WEGetViewRect()
476 vx = Wcontrols._scalebarvalue(dr[0], dr[2], vr[0], vr[2])
477 vy = Wcontrols._scalebarvalue(dr[1], dr[3], vr[1], vr[3])
478 return vx, vy
479
480 def vscroll(self, value):
481 lineheight = self.ted.WEGetHeight(0, 1)
482 dr = self.ted.WEGetDestRect()
483 vr = self.ted.WEGetViewRect()
484 destheight = dr[3] - dr[1]
485 viewheight = vr[3] - vr[1]
486 viewoffset = maxdelta = vr[1] - dr[1]
487 mindelta = vr[3] - dr[3]
488 if value == "+":
489 delta = lineheight
490 elif value == "-":
491 delta = - lineheight
492 elif value == "++":
493 delta = viewheight - lineheight
494 elif value == "--":
495 delta = lineheight - viewheight
496 else: # in thumb
Just van Rossum6c487c41999-04-22 22:16:58 +0000497 cur = (32767L * viewoffset) / (destheight - viewheight)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000498 delta = (cur-value)*(destheight - viewheight)/32767
499 if abs(delta - viewoffset) <=2:
500 # compensate for irritating rounding error
501 delta = viewoffset
502 delta = min(maxdelta, delta)
503 delta = max(mindelta, delta)
504 self.ted.WEScroll(0, delta)
505 self.updatescrollbars()
506
507 def hscroll(self, value):
508 dr = self.ted.WEGetDestRect()
509 vr = self.ted.WEGetViewRect()
510 destwidth = dr[2] - dr[0]
511 viewwidth = vr[2] - vr[0]
512 viewoffset = maxdelta = vr[0] - dr[0]
513 mindelta = vr[2] - dr[2]
514 if value == "+":
515 delta = 32
516 elif value == "-":
517 delta = - 32
518 elif value == "++":
519 delta = 0.5 * (vr[2] - vr[0])
520 elif value == "--":
521 delta = 0.5 * (vr[0] - vr[2])
522 else: # in thumb
523 cur = (32767 * viewoffset) / (destwidth - viewwidth)
524 delta = (cur-value)*(destwidth - viewwidth)/32767
525 if abs(delta - viewoffset) <=2:
526 # compensate for irritating rounding error
527 delta = viewoffset
528 delta = min(maxdelta, delta)
529 delta = max(mindelta, delta)
530 self.ted.WEScroll(delta, 0)
531 self.updatescrollbars()
532
533 # some internals
534 def _getflags(self):
535 flags = WASTEconst.weDoAutoScroll | WASTEconst.weDoMonoStyled
536 if self.readonly:
537 flags = flags | WASTEconst.weDoReadOnly
538 else:
539 flags = flags | WASTEconst.weDoUndo
540 return flags
541
542 def _getviewrect(self):
543 return Qd.InsetRect(self._bounds, self.inset[0], self.inset[1])
544
545 def _calctextbounds(self):
546 viewrect = l, t, r, b = self._getviewrect()
547 if self.ted:
548 dl, dt, dr, db = self.ted.WEGetDestRect()
549 vl, vt, vr, vb = self.ted.WEGetViewRect()
550 yshift = t - vt
551 if (db - dt) < (b - t):
552 destrect = viewrect
553 else:
554 destrect = l, dt + yshift, r, db + yshift
555 else:
556 destrect = viewrect
557 return viewrect, destrect
558
559
560class TextEditor(EditText):
561
562 """A text edit widget."""
563
Just van Rossumb7ad8211999-09-26 12:21:32 +0000564 def __init__(self, possize, text="", callback=None, wrap=1, inset=(4, 4),
565 fontsettings=None,
566 tabsettings=(32, 0),
567 readonly=0):
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000568 EditText.__init__(self, possize, text, callback, inset, fontsettings, tabsettings, readonly)
569 self.wrap = wrap
570
571 def _getflags(self):
572 flags = WASTEconst.weDoAutoScroll | WASTEconst.weDoMonoStyled | \
573 WASTEconst.weDoOutlineHilite
574 if self.readonly:
575 flags = flags | WASTEconst.weDoReadOnly
576 else:
577 flags = flags | WASTEconst.weDoUndo
578 return flags
579
580 def _getviewrect(self):
581 l, t, r, b = self._bounds
582 return (l + 5, t + 2, r, b - 2)
583
584 def _calctextbounds(self):
585 if self.wrap:
586 return EditText._calctextbounds(self)
587 else:
588 viewrect = l, t, r, b = self._getviewrect()
589 if self.ted:
590 dl, dt, dr, db = self.ted.WEGetDestRect()
591 vl, vt, vr, vb = self.ted.WEGetViewRect()
592 xshift = l - vl
593 yshift = t - vt
594 if (db - dt) < (b - t):
595 yshift = t - dt
596 destrect = (dl + xshift, dt + yshift, dr + xshift, db + yshift)
597 else:
598 destrect = (l, t, r + 5000, b)
599 return viewrect, destrect
600
601 def draw(self, visRgn = None):
602 if self._visible:
603 if not visRgn:
604 visRgn = self._parentwindow.wid.GetWindowPort().visRgn
605 self.ted.WEUpdate(visRgn)
606 if self._selected and self._activated:
607 self.drawselframe(1)
608
609
Jack Jansen9ad27522001-02-21 13:54:31 +0000610import re
Just van Rossumb10eb842001-06-21 17:51:17 +0000611commentPat = re.compile("[ \t]*(#)")
612indentPat = re.compile("[ \t]*")
613
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000614
615class PyEditor(TextEditor):
616
617 """A specialized Python source edit widget"""
618
Just van Rossumb7ad8211999-09-26 12:21:32 +0000619 def __init__(self, possize, text="", callback=None, inset=(4, 4),
620 fontsettings=None,
621 tabsettings=(32, 0),
622 readonly=0,
623 debugger=None,
624 file=''):
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000625 TextEditor.__init__(self, possize, text, callback, 0, inset, fontsettings, tabsettings, readonly)
626 self.bind("cmd[", self.domenu_shiftleft)
627 self.bind("cmd]", self.domenu_shiftright)
628 self.bind("cmdshift[", self.domenu_uncomment)
629 self.bind("cmdshift]", self.domenu_comment)
630 self.file = file # only for debugger reference
631 self._debugger = debugger
632 if debugger:
633 debugger.register_editor(self, self.file)
634
635 def domenu_shiftleft(self):
636 self.expandselection()
637 selstart, selend = self.ted.WEGetSelection()
638 selstart, selend = min(selstart, selend), max(selstart, selend)
639 snippet = self.getselectedtext()
640 lines = string.split(snippet, '\r')
641 for i in range(len(lines)):
642 if lines[i][:1] == '\t':
643 lines[i] = lines[i][1:]
644 snippet = string.join(lines, '\r')
645 self.insert(snippet)
646 self.ted.WESetSelection(selstart, selstart + len(snippet))
647
648 def domenu_shiftright(self):
649 self.expandselection()
650 selstart, selend = self.ted.WEGetSelection()
651 selstart, selend = min(selstart, selend), max(selstart, selend)
652 snippet = self.getselectedtext()
653 lines = string.split(snippet, '\r')
654 for i in range(len(lines) - (not lines[-1])):
655 lines[i] = '\t' + lines[i]
656 snippet = string.join(lines, '\r')
657 self.insert(snippet)
658 self.ted.WESetSelection(selstart, selstart + len(snippet))
659
660 def domenu_uncomment(self):
661 self.expandselection()
662 selstart, selend = self.ted.WEGetSelection()
663 selstart, selend = min(selstart, selend), max(selstart, selend)
664 snippet = self.getselectedtext()
665 lines = string.split(snippet, '\r')
666 for i in range(len(lines)):
Jack Jansen9ad27522001-02-21 13:54:31 +0000667 m = commentPat.match(lines[i])
668 if m:
669 pos = m.start(1)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000670 lines[i] = lines[i][:pos] + lines[i][pos+1:]
671 snippet = string.join(lines, '\r')
672 self.insert(snippet)
673 self.ted.WESetSelection(selstart, selstart + len(snippet))
674
675 def domenu_comment(self):
676 self.expandselection()
677 selstart, selend = self.ted.WEGetSelection()
678 selstart, selend = min(selstart, selend), max(selstart, selend)
679 snippet = self.getselectedtext()
680 lines = string.split(snippet, '\r')
681 indent = 3000 # arbitrary large number...
682 for line in lines:
683 if string.strip(line):
Jack Jansen9ad27522001-02-21 13:54:31 +0000684 m = indentPat.match(line)
685 if m:
686 indent = min(indent, m.regs[0][1])
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000687 else:
688 indent = 0
689 break
690 for i in range(len(lines) - (not lines[-1])):
691 lines[i] = lines[i][:indent] + "#" + lines[i][indent:]
692 snippet = string.join(lines, '\r')
693 self.insert(snippet)
694 self.ted.WESetSelection(selstart, selstart + len(snippet))
695
696 def setfile(self, file):
697 self.file = file
698
699 def set(self, text, file = ''):
700 oldfile = self.file
701 self.file = file
702 if self._debugger:
703 self._debugger.unregister_editor(self, oldfile)
704 self._debugger.register_editor(self, file)
705 TextEditor.set(self, text)
706
707 def close(self):
708 if self._debugger:
709 self._debugger.unregister_editor(self, self.file)
710 self._debugger = None
711 TextEditor.close(self)
712
713 def click(self, point, modifiers):
714 if not self._enabled:
715 return
716 if self._debugger and self.pt_in_breaks(point):
717 self.breakhit(point, modifiers)
718 elif self._debugger:
719 bl, bt, br, bb = self._getbreakrect()
720 Qd.EraseRect((bl, bt, br-1, bb))
721 TextEditor.click(self, point, modifiers)
722 self.drawbreakpoints()
723 else:
724 TextEditor.click(self, point, modifiers)
725 if self.ted.WEGetClickCount() >= 3:
726 # select block with our indent
727 lines = string.split(self.get(), '\r')
728 selstart, selend = self.ted.WEGetSelection()
729 lineno = self.ted.WEOffsetToLine(selstart)
730 tabs = 0
731 line = lines[lineno]
732 while line[tabs:] and line[tabs] == '\t':
733 tabs = tabs + 1
734 tabstag = '\t' * tabs
735 fromline = 0
736 toline = len(lines)
737 if tabs:
738 for i in range(lineno - 1, -1, -1):
739 line = lines[i]
740 if line[:tabs] <> tabstag:
741 fromline = i + 1
742 break
743 for i in range(lineno + 1, toline):
744 line = lines[i]
745 if line[:tabs] <> tabstag:
746 toline = i - 1
747 break
748 selstart, dummy = self.ted.WEGetLineRange(fromline)
749 dummy, selend = self.ted.WEGetLineRange(toline)
750 self.ted.WESetSelection(selstart, selend)
751
752 def breakhit(self, point, modifiers):
753 if not self.file:
754 return
755 destrect = self.ted.WEGetDestRect()
756 offset, edge = self.ted.WEGetOffset(point)
757 lineno = self.ted.WEOffsetToLine(offset) + 1
758 if point[1] <= destrect[3]:
759 self._debugger.clear_breaks_above(self.file, self.countlines())
760 self._debugger.toggle_break(self.file, lineno)
761 else:
762 self._debugger.clear_breaks_above(self.file, lineno)
763
764 def key(self, char, event):
765 (what, message, when, where, modifiers) = event
766 if modifiers & Events.cmdKey and not char in Wkeys.arrowkeys:
767 return
768 if char == '\r':
769 selstart, selend = self.ted.WEGetSelection()
770 selstart, selend = min(selstart, selend), max(selstart, selend)
771 lastchar = chr(self.ted.WEGetChar(selstart-1))
772 if lastchar <> '\r' and selstart:
773 pos, dummy = self.ted.WEFindLine(selstart, 0)
774 lineres = Res.Resource('')
775 self.ted.WECopyRange(pos, selstart, lineres, None, None)
776 line = lineres.data + '\n'
777 tabcount = self.extratabs(line)
778 self.ted.WEKey(ord('\r'), 0)
779 for i in range(tabcount):
780 self.ted.WEKey(ord('\t'), 0)
781 else:
782 self.ted.WEKey(ord('\r'), 0)
783 elif char in ')]}':
784 self.ted.WEKey(ord(char), modifiers)
785 self.balanceparens(char)
786 else:
787 self.ted.WEKey(ord(char), modifiers)
788 if char not in Wkeys.navigationkeys:
789 self.changed = 1
790 self.selchanged = 1
791 self.updatescrollbars()
792
793 def balanceparens(self, char):
794 if char == ')':
795 target = '('
796 elif char == ']':
797 target = '['
798 elif char == '}':
799 target = '{'
800 recursionlevel = 1
801 selstart, selend = self.ted.WEGetSelection()
802 count = min(selstart, selend) - 2
803 mincount = max(0, count - 2048)
804 lastquote = None
805 while count > mincount:
806 testchar = chr(self.ted.WEGetChar(count))
807 if testchar in "\"'" and chr(self.ted.WEGetChar(count - 1)) <> '\\':
808 if lastquote == testchar:
809 recursionlevel = recursionlevel - 1
810 lastquote = None
811 elif not lastquote:
812 recursionlevel = recursionlevel + 1
813 lastquote = testchar
814 elif not lastquote and testchar == char:
815 recursionlevel = recursionlevel + 1
816 elif not lastquote and testchar == target:
817 recursionlevel = recursionlevel - 1
818 if recursionlevel == 0:
819 import time
820 autoscroll = self.ted.WEFeatureFlag(WASTEconst.weFAutoScroll, -1)
821 if autoscroll:
822 self.ted.WEFeatureFlag(WASTEconst.weFAutoScroll, 0)
823 self.ted.WESetSelection(count, count + 1)
824 time.sleep(0.2)
825 self.ted.WESetSelection(selstart, selend)
826 if autoscroll:
827 self.ted.WEFeatureFlag(WASTEconst.weFAutoScroll, 1)
828 break
829 count = count - 1
830
831 def extratabs(self, line):
832 tabcount = 0
833 for c in line:
834 if c <> '\t':
835 break
836 tabcount = tabcount + 1
837 last = 0
838 cleanline = ''
839 tags = PyFontify.fontify(line)
840 # strip comments and strings
841 for tag, start, end, sublist in tags:
842 if tag in ('string', 'comment'):
843 cleanline = cleanline + line[last:start]
844 last = end
845 cleanline = cleanline + line[last:]
846 cleanline = string.strip(cleanline)
847 if cleanline and cleanline[-1] == ':':
848 tabcount = tabcount + 1
849 else:
850 # extra indent after unbalanced (, [ or {
851 for open, close in (('(', ')'), ('[', ']'), ('{', '}')):
852 count = string.count(cleanline, open)
853 if count and count > string.count(cleanline, close):
854 tabcount = tabcount + 2
855 break
856 return tabcount
857
858 def rollover(self, point, onoff):
859 if onoff:
860 if self._debugger and self.pt_in_breaks(point):
861 Wbase.SetCursor("arrow")
862 else:
863 Wbase.SetCursor("iBeam")
864
865 def draw(self, visRgn = None):
866 TextEditor.draw(self, visRgn)
867 if self._debugger:
868 self.drawbreakpoints()
869
870 def showbreakpoints(self, onoff):
871 if (not not self._debugger) <> onoff:
872 if onoff:
873 if not __debug__:
874 import W
Just van Rossumdc3c6172001-06-19 21:37:33 +0000875 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 +0000876 import PyDebugger
877 self._debugger = PyDebugger.getdebugger()
878 self._debugger.register_editor(self, self.file)
879 elif self._debugger:
880 self._debugger.unregister_editor(self, self.file)
881 self._debugger = None
882 self.adjust(self._bounds)
883
884 def togglebreakpoints(self):
885 self.showbreakpoints(not self._debugger)
886
887 def clearbreakpoints(self):
888 if self.file:
889 self._debugger.clear_all_file_breaks(self.file)
890
891 def editbreakpoints(self):
892 if self._debugger:
893 self._debugger.edit_breaks()
894 self._debugger.breaksviewer.selectfile(self.file)
895
896 def drawbreakpoints(self, eraseall = 0):
897 breakrect = bl, bt, br, bb = self._getbreakrect()
898 br = br - 1
899 self.SetPort()
900 Qd.PenPat(Qd.qd.gray)
901 Qd.PaintRect((br, bt, br + 1, bb))
902 Qd.PenNormal()
903 self._parentwindow.tempcliprect(breakrect)
904 Qd.RGBForeColor((0xffff, 0, 0))
905 try:
906 lasttop = bt
907 self_ted = self.ted
908 Qd_PaintOval = Qd.PaintOval
909 Qd_EraseRect = Qd.EraseRect
910 for lineno in self._debugger.get_file_breaks(self.file):
911 start, end = self_ted.WEGetLineRange(lineno - 1)
912 if lineno <> self_ted.WEOffsetToLine(start) + 1:
913 # breakpoints beyond our text: erase rest, and back out
914 Qd_EraseRect((bl, lasttop, br, bb))
915 break
916 (x, y), h = self_ted.WEGetPoint(start, 0)
917 bottom = y + h
918 #print y, (lasttop, bottom)
919 if bottom > lasttop:
920 Qd_EraseRect((bl, lasttop, br, y + h * eraseall))
921 lasttop = bottom
922 redbullet = bl + 2, y + 3, bl + 8, y + 9
923 Qd_PaintOval(redbullet)
924 else:
925 Qd_EraseRect((bl, lasttop, br, bb))
926 Qd.RGBForeColor((0, 0, 0))
927 finally:
928 self._parentwindow.restoreclip()
929
930 def updatescrollbars(self):
931 if self._debugger:
932 self.drawbreakpoints(1)
933 TextEditor.updatescrollbars(self)
934
935 def pt_in_breaks(self, point):
936 return Qd.PtInRect(point, self._getbreakrect())
937
938 def _getbreakrect(self):
939 if self._debugger:
940 l, t, r, b = self._bounds
941 return (l+1, t+1, l + 12, b-1)
942 else:
943 return (0, 0, 0, 0)
944
945 def _getviewrect(self):
946 l, t, r, b = self._bounds
947 if self._debugger:
948 return (l + 17, t + 2, r, b - 2)
949 else:
950 return (l + 5, t + 2, r, b - 2)
951
952 def _calctextbounds(self):
953 viewrect = l, t, r, b = self._getviewrect()
954 if self.ted:
955 dl, dt, dr, db = self.ted.WEGetDestRect()
956 vl, vt, vr, vb = self.ted.WEGetViewRect()
957 xshift = l - vl
958 yshift = t - vt
959 if (db - dt) < (b - t):
960 yshift = t - dt
961 destrect = (dl + xshift, dt + yshift, dr + xshift, db + yshift)
962 else:
963 destrect = (l, t, r + 5000, b)
964 return viewrect, destrect
965
966
967def GetFNum(fontname):
968 """Same as Fm.GetFNum(), but maps a missing font to Monaco instead of the system font."""
969 if fontname <> Fm.GetFontName(0):
970 fontid = Fm.GetFNum(fontname)
971 if fontid == 0:
972 fontid = Fonts.monaco
973 else:
974 fontid = 0
975 return fontid
976
977# b/w compat. Anyone using this?
978GetFName = Fm.GetFontName
979
980def GetPortFontSettings(port):
981 return Fm.GetFontName(port.txFont), port.txFace, port.txSize
982
983def SetPortFontSettings(port, (font, face, size)):
984 saveport = Qd.GetPort()
985 Qd.SetPort(port)
986 Qd.TextFont(GetFNum(font))
987 Qd.TextFace(face)
988 Qd.TextSize(size)
989 Qd.SetPort(saveport)