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