blob: 41ea5ec818e2fd0fbef6578f892be459a58ca2dc [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
282 newselstart, dummy = self.ted.WEFindLine(selstart, 0)
283 dummy, newselend = self.ted.WEFindLine(selend, 0)
284 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
611commentPat = re.compile("[ \t]*\(#\)")
612indentPat = re.compile("\t*")
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000613
614class PyEditor(TextEditor):
615
616 """A specialized Python source edit widget"""
617
Just van Rossumb7ad8211999-09-26 12:21:32 +0000618 def __init__(self, possize, text="", callback=None, inset=(4, 4),
619 fontsettings=None,
620 tabsettings=(32, 0),
621 readonly=0,
622 debugger=None,
623 file=''):
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000624 TextEditor.__init__(self, possize, text, callback, 0, inset, fontsettings, tabsettings, readonly)
625 self.bind("cmd[", self.domenu_shiftleft)
626 self.bind("cmd]", self.domenu_shiftright)
627 self.bind("cmdshift[", self.domenu_uncomment)
628 self.bind("cmdshift]", self.domenu_comment)
629 self.file = file # only for debugger reference
630 self._debugger = debugger
631 if debugger:
632 debugger.register_editor(self, self.file)
633
634 def domenu_shiftleft(self):
635 self.expandselection()
636 selstart, selend = self.ted.WEGetSelection()
637 selstart, selend = min(selstart, selend), max(selstart, selend)
638 snippet = self.getselectedtext()
639 lines = string.split(snippet, '\r')
640 for i in range(len(lines)):
641 if lines[i][:1] == '\t':
642 lines[i] = lines[i][1:]
643 snippet = string.join(lines, '\r')
644 self.insert(snippet)
645 self.ted.WESetSelection(selstart, selstart + len(snippet))
646
647 def domenu_shiftright(self):
648 self.expandselection()
649 selstart, selend = self.ted.WEGetSelection()
650 selstart, selend = min(selstart, selend), max(selstart, selend)
651 snippet = self.getselectedtext()
652 lines = string.split(snippet, '\r')
653 for i in range(len(lines) - (not lines[-1])):
654 lines[i] = '\t' + lines[i]
655 snippet = string.join(lines, '\r')
656 self.insert(snippet)
657 self.ted.WESetSelection(selstart, selstart + len(snippet))
658
659 def domenu_uncomment(self):
660 self.expandselection()
661 selstart, selend = self.ted.WEGetSelection()
662 selstart, selend = min(selstart, selend), max(selstart, selend)
663 snippet = self.getselectedtext()
664 lines = string.split(snippet, '\r')
665 for i in range(len(lines)):
Jack Jansen9ad27522001-02-21 13:54:31 +0000666 m = commentPat.match(lines[i])
667 if m:
668 pos = m.start(1)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000669 lines[i] = lines[i][:pos] + lines[i][pos+1:]
670 snippet = string.join(lines, '\r')
671 self.insert(snippet)
672 self.ted.WESetSelection(selstart, selstart + len(snippet))
673
674 def domenu_comment(self):
675 self.expandselection()
676 selstart, selend = self.ted.WEGetSelection()
677 selstart, selend = min(selstart, selend), max(selstart, selend)
678 snippet = self.getselectedtext()
679 lines = string.split(snippet, '\r')
680 indent = 3000 # arbitrary large number...
681 for line in lines:
682 if string.strip(line):
Jack Jansen9ad27522001-02-21 13:54:31 +0000683 m = indentPat.match(line)
684 if m:
685 indent = min(indent, m.regs[0][1])
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000686 else:
687 indent = 0
688 break
689 for i in range(len(lines) - (not lines[-1])):
690 lines[i] = lines[i][:indent] + "#" + lines[i][indent:]
691 snippet = string.join(lines, '\r')
692 self.insert(snippet)
693 self.ted.WESetSelection(selstart, selstart + len(snippet))
694
695 def setfile(self, file):
696 self.file = file
697
698 def set(self, text, file = ''):
699 oldfile = self.file
700 self.file = file
701 if self._debugger:
702 self._debugger.unregister_editor(self, oldfile)
703 self._debugger.register_editor(self, file)
704 TextEditor.set(self, text)
705
706 def close(self):
707 if self._debugger:
708 self._debugger.unregister_editor(self, self.file)
709 self._debugger = None
710 TextEditor.close(self)
711
712 def click(self, point, modifiers):
713 if not self._enabled:
714 return
715 if self._debugger and self.pt_in_breaks(point):
716 self.breakhit(point, modifiers)
717 elif self._debugger:
718 bl, bt, br, bb = self._getbreakrect()
719 Qd.EraseRect((bl, bt, br-1, bb))
720 TextEditor.click(self, point, modifiers)
721 self.drawbreakpoints()
722 else:
723 TextEditor.click(self, point, modifiers)
724 if self.ted.WEGetClickCount() >= 3:
725 # select block with our indent
726 lines = string.split(self.get(), '\r')
727 selstart, selend = self.ted.WEGetSelection()
728 lineno = self.ted.WEOffsetToLine(selstart)
729 tabs = 0
730 line = lines[lineno]
731 while line[tabs:] and line[tabs] == '\t':
732 tabs = tabs + 1
733 tabstag = '\t' * tabs
734 fromline = 0
735 toline = len(lines)
736 if tabs:
737 for i in range(lineno - 1, -1, -1):
738 line = lines[i]
739 if line[:tabs] <> tabstag:
740 fromline = i + 1
741 break
742 for i in range(lineno + 1, toline):
743 line = lines[i]
744 if line[:tabs] <> tabstag:
745 toline = i - 1
746 break
747 selstart, dummy = self.ted.WEGetLineRange(fromline)
748 dummy, selend = self.ted.WEGetLineRange(toline)
749 self.ted.WESetSelection(selstart, selend)
750
751 def breakhit(self, point, modifiers):
752 if not self.file:
753 return
754 destrect = self.ted.WEGetDestRect()
755 offset, edge = self.ted.WEGetOffset(point)
756 lineno = self.ted.WEOffsetToLine(offset) + 1
757 if point[1] <= destrect[3]:
758 self._debugger.clear_breaks_above(self.file, self.countlines())
759 self._debugger.toggle_break(self.file, lineno)
760 else:
761 self._debugger.clear_breaks_above(self.file, lineno)
762
763 def key(self, char, event):
764 (what, message, when, where, modifiers) = event
765 if modifiers & Events.cmdKey and not char in Wkeys.arrowkeys:
766 return
767 if char == '\r':
768 selstart, selend = self.ted.WEGetSelection()
769 selstart, selend = min(selstart, selend), max(selstart, selend)
770 lastchar = chr(self.ted.WEGetChar(selstart-1))
771 if lastchar <> '\r' and selstart:
772 pos, dummy = self.ted.WEFindLine(selstart, 0)
773 lineres = Res.Resource('')
774 self.ted.WECopyRange(pos, selstart, lineres, None, None)
775 line = lineres.data + '\n'
776 tabcount = self.extratabs(line)
777 self.ted.WEKey(ord('\r'), 0)
778 for i in range(tabcount):
779 self.ted.WEKey(ord('\t'), 0)
780 else:
781 self.ted.WEKey(ord('\r'), 0)
782 elif char in ')]}':
783 self.ted.WEKey(ord(char), modifiers)
784 self.balanceparens(char)
785 else:
786 self.ted.WEKey(ord(char), modifiers)
787 if char not in Wkeys.navigationkeys:
788 self.changed = 1
789 self.selchanged = 1
790 self.updatescrollbars()
791
792 def balanceparens(self, char):
793 if char == ')':
794 target = '('
795 elif char == ']':
796 target = '['
797 elif char == '}':
798 target = '{'
799 recursionlevel = 1
800 selstart, selend = self.ted.WEGetSelection()
801 count = min(selstart, selend) - 2
802 mincount = max(0, count - 2048)
803 lastquote = None
804 while count > mincount:
805 testchar = chr(self.ted.WEGetChar(count))
806 if testchar in "\"'" and chr(self.ted.WEGetChar(count - 1)) <> '\\':
807 if lastquote == testchar:
808 recursionlevel = recursionlevel - 1
809 lastquote = None
810 elif not lastquote:
811 recursionlevel = recursionlevel + 1
812 lastquote = testchar
813 elif not lastquote and testchar == char:
814 recursionlevel = recursionlevel + 1
815 elif not lastquote and testchar == target:
816 recursionlevel = recursionlevel - 1
817 if recursionlevel == 0:
818 import time
819 autoscroll = self.ted.WEFeatureFlag(WASTEconst.weFAutoScroll, -1)
820 if autoscroll:
821 self.ted.WEFeatureFlag(WASTEconst.weFAutoScroll, 0)
822 self.ted.WESetSelection(count, count + 1)
823 time.sleep(0.2)
824 self.ted.WESetSelection(selstart, selend)
825 if autoscroll:
826 self.ted.WEFeatureFlag(WASTEconst.weFAutoScroll, 1)
827 break
828 count = count - 1
829
830 def extratabs(self, line):
831 tabcount = 0
832 for c in line:
833 if c <> '\t':
834 break
835 tabcount = tabcount + 1
836 last = 0
837 cleanline = ''
838 tags = PyFontify.fontify(line)
839 # strip comments and strings
840 for tag, start, end, sublist in tags:
841 if tag in ('string', 'comment'):
842 cleanline = cleanline + line[last:start]
843 last = end
844 cleanline = cleanline + line[last:]
845 cleanline = string.strip(cleanline)
846 if cleanline and cleanline[-1] == ':':
847 tabcount = tabcount + 1
848 else:
849 # extra indent after unbalanced (, [ or {
850 for open, close in (('(', ')'), ('[', ']'), ('{', '}')):
851 count = string.count(cleanline, open)
852 if count and count > string.count(cleanline, close):
853 tabcount = tabcount + 2
854 break
855 return tabcount
856
857 def rollover(self, point, onoff):
858 if onoff:
859 if self._debugger and self.pt_in_breaks(point):
860 Wbase.SetCursor("arrow")
861 else:
862 Wbase.SetCursor("iBeam")
863
864 def draw(self, visRgn = None):
865 TextEditor.draw(self, visRgn)
866 if self._debugger:
867 self.drawbreakpoints()
868
869 def showbreakpoints(self, onoff):
870 if (not not self._debugger) <> onoff:
871 if onoff:
872 if not __debug__:
873 import W
Just van Rossumedab9391999-02-02 22:31:05 +0000874 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 +0000875 import PyDebugger
876 self._debugger = PyDebugger.getdebugger()
877 self._debugger.register_editor(self, self.file)
878 elif self._debugger:
879 self._debugger.unregister_editor(self, self.file)
880 self._debugger = None
881 self.adjust(self._bounds)
882
883 def togglebreakpoints(self):
884 self.showbreakpoints(not self._debugger)
885
886 def clearbreakpoints(self):
887 if self.file:
888 self._debugger.clear_all_file_breaks(self.file)
889
890 def editbreakpoints(self):
891 if self._debugger:
892 self._debugger.edit_breaks()
893 self._debugger.breaksviewer.selectfile(self.file)
894
895 def drawbreakpoints(self, eraseall = 0):
896 breakrect = bl, bt, br, bb = self._getbreakrect()
897 br = br - 1
898 self.SetPort()
899 Qd.PenPat(Qd.qd.gray)
900 Qd.PaintRect((br, bt, br + 1, bb))
901 Qd.PenNormal()
902 self._parentwindow.tempcliprect(breakrect)
903 Qd.RGBForeColor((0xffff, 0, 0))
904 try:
905 lasttop = bt
906 self_ted = self.ted
907 Qd_PaintOval = Qd.PaintOval
908 Qd_EraseRect = Qd.EraseRect
909 for lineno in self._debugger.get_file_breaks(self.file):
910 start, end = self_ted.WEGetLineRange(lineno - 1)
911 if lineno <> self_ted.WEOffsetToLine(start) + 1:
912 # breakpoints beyond our text: erase rest, and back out
913 Qd_EraseRect((bl, lasttop, br, bb))
914 break
915 (x, y), h = self_ted.WEGetPoint(start, 0)
916 bottom = y + h
917 #print y, (lasttop, bottom)
918 if bottom > lasttop:
919 Qd_EraseRect((bl, lasttop, br, y + h * eraseall))
920 lasttop = bottom
921 redbullet = bl + 2, y + 3, bl + 8, y + 9
922 Qd_PaintOval(redbullet)
923 else:
924 Qd_EraseRect((bl, lasttop, br, bb))
925 Qd.RGBForeColor((0, 0, 0))
926 finally:
927 self._parentwindow.restoreclip()
928
929 def updatescrollbars(self):
930 if self._debugger:
931 self.drawbreakpoints(1)
932 TextEditor.updatescrollbars(self)
933
934 def pt_in_breaks(self, point):
935 return Qd.PtInRect(point, self._getbreakrect())
936
937 def _getbreakrect(self):
938 if self._debugger:
939 l, t, r, b = self._bounds
940 return (l+1, t+1, l + 12, b-1)
941 else:
942 return (0, 0, 0, 0)
943
944 def _getviewrect(self):
945 l, t, r, b = self._bounds
946 if self._debugger:
947 return (l + 17, t + 2, r, b - 2)
948 else:
949 return (l + 5, t + 2, r, b - 2)
950
951 def _calctextbounds(self):
952 viewrect = l, t, r, b = self._getviewrect()
953 if self.ted:
954 dl, dt, dr, db = self.ted.WEGetDestRect()
955 vl, vt, vr, vb = self.ted.WEGetViewRect()
956 xshift = l - vl
957 yshift = t - vt
958 if (db - dt) < (b - t):
959 yshift = t - dt
960 destrect = (dl + xshift, dt + yshift, dr + xshift, db + yshift)
961 else:
962 destrect = (l, t, r + 5000, b)
963 return viewrect, destrect
964
965
966def GetFNum(fontname):
967 """Same as Fm.GetFNum(), but maps a missing font to Monaco instead of the system font."""
968 if fontname <> Fm.GetFontName(0):
969 fontid = Fm.GetFNum(fontname)
970 if fontid == 0:
971 fontid = Fonts.monaco
972 else:
973 fontid = 0
974 return fontid
975
976# b/w compat. Anyone using this?
977GetFName = Fm.GetFontName
978
979def GetPortFontSettings(port):
980 return Fm.GetFontName(port.txFont), port.txFace, port.txSize
981
982def SetPortFontSettings(port, (font, face, size)):
983 saveport = Qd.GetPort()
984 Qd.SetPort(port)
985 Qd.TextFont(GetFNum(font))
986 Qd.TextFace(face)
987 Qd.TextSize(size)
988 Qd.SetPort(saveport)