1 from Carbon
import Evt
, Events
, Fm
, Fonts
2 from Carbon
import Qd
, Res
, Scrap
3 from Carbon
import TE
, TextEdit
, Win
5 from Carbon
.Appearance
import kThemeStateActive
, kThemeStateInactive
13 from types
import TupleType
, StringType
16 class TextBox(Wbase
.Widget
):
18 """A static text widget"""
20 def __init__(self
, possize
, text
="", align
=TextEdit
.teJustLeft
,
22 backgroundcolor
=(0xffff, 0xffff, 0xffff)
24 if fontsettings
is None:
26 fontsettings
= W
.getdefaultfont()
27 Wbase
.Widget
.__init
__(self
, possize
)
28 self
.fontsettings
= fontsettings
31 self
._backgroundcolor
= backgroundcolor
33 def draw(self
, visRgn
= None):
35 (font
, style
, size
, color
) = self
.fontsettings
36 fontid
= GetFNum(font
)
37 savestate
= Qd
.GetPenState()
41 Qd
.RGBForeColor(color
)
42 Qd
.RGBBackColor(self
._backgroundcolor
)
43 TE
.TETextBox(self
.text
, self
._bounds
, self
.align
)
44 Qd
.RGBBackColor((0xffff, 0xffff, 0xffff))
45 Qd
.SetPenState(savestate
)
52 if self
._parentwindow
and self
._parentwindow
.wid
:
60 def getscrollrects(self
):
61 """Return (destrect, viewrect)."""
66 def updatescrollbars(self
):
67 (dl
, dt
, dr
, db
), (vl
, vt
, vr
, vb
) = self
.getscrollrects()
68 if self
._parent
._barx
:
71 bar
= self
._parent
._barx
72 bar
.setmax(destwidth
- viewwidth
)
74 # MacOS 8.1 doesn't automatically disable
75 # scrollbars whose max <= min
76 bar
.enable(destwidth
> viewwidth
)
78 bar
.setviewsize(viewwidth
)
80 if self
._parent
._bary
:
83 bar
= self
._parent
._bary
84 bar
.setmax(destheight
- viewheight
)
86 # MacOS 8.1 doesn't automatically disable
87 # scrollbars whose max <= min
88 bar
.enable(destheight
> viewheight
)
90 bar
.setviewsize(viewheight
)
94 UNDOLABELS
= [ # Indexed by WEGetUndoInfo() value
95 None, "", "typing", "Cut", "Paste", "Clear", "Drag", "Style",
96 "Ruler", "backspace", "delete", "transform", "resize"]
99 class EditText(Wbase
.SelectableWidget
, _ScrollWidget
):
101 """A text edit widget, mainly for simple entry fields."""
103 def __init__(self
, possize
, text
="",
104 callback
=None, inset
=(3, 3),
106 tabsettings
= (32, 0),
108 if fontsettings
is None:
110 fontsettings
= W
.getdefaultfont()
111 Wbase
.SelectableWidget
.__init
__(self
, possize
)
114 self
.selection
= None
115 self
.oldselection
= None
116 self
._callback
= callback
122 self
.readonly
= readonly
123 self
.fontsettings
= fontsettings
124 self
.tabsettings
= tabsettings
125 if type(inset
) <> TupleType
:
126 self
.inset
= (inset
, inset
)
131 if not hasattr(self
._parent
, "_barx"):
132 self
._parent
._barx
= None
133 if not hasattr(self
._parent
, "_bary"):
134 self
._parent
._bary
= None
137 viewrect
, destrect
= self
._calctextbounds
()
138 flags
= self
._getflags
()
139 self
.ted
= waste
.WENew(destrect
, viewrect
, flags
)
140 self
.ted
.WEInstallTabHooks()
141 self
.ted
.WESetAlignment(WASTEconst
.weFlushLeft
)
142 self
.setfontsettings(self
.fontsettings
)
143 self
.settabsettings(self
.tabsettings
)
144 self
.ted
.WEUseText(Res
.Resource(self
.temptext
))
147 self
.setselection(self
.selection
[0], self
.selection
[1])
148 self
.selection
= None
152 self
.updatescrollbars()
153 self
.bind("pageup", self
.scrollpageup
)
154 self
.bind("pagedown", self
.scrollpagedown
)
155 self
.bind("top", self
.scrolltop
)
156 self
.bind("bottom", self
.scrollbottom
)
160 self
._parent
._barx
= None
161 self
._parent
._bary
= None
164 Wbase
.SelectableWidget
.close(self
)
166 def textchanged(self
, all
=0):
169 def selectionchanged(self
):
171 self
.oldselection
= self
.getselection()
173 def gettabsettings(self
):
174 return self
.tabsettings
176 def settabsettings(self
, (tabsize
, tabmode
)):
177 self
.tabsettings
= (tabsize
, tabmode
)
178 if hasattr(self
.ted
, "WESetTabSize"):
179 port
= self
._parentwindow
.wid
.GetWindowPort()
181 (font
, style
, size
, color
) = self
.getfontsettings()
182 savesettings
= GetPortFontSettings(port
)
183 SetPortFontSettings(port
, (font
, style
, size
))
184 tabsize
= Qd
.StringWidth(' ' * tabsize
)
185 SetPortFontSettings(port
, savesettings
)
186 tabsize
= max(tabsize
, 1)
187 self
.ted
.WESetTabSize(tabsize
)
189 Qd
.EraseRect(self
.ted
.WEGetViewRect())
190 self
.ted
.WEUpdate(port
.visRgn
)
192 def getfontsettings(self
):
193 from Carbon
import Res
194 (font
, style
, size
, color
) = self
.ted
.WEGetRunInfo(0)[4]
195 font
= Fm
.GetFontName(font
)
196 return (font
, style
, size
, color
)
198 def setfontsettings(self
, (font
, style
, size
, color
)):
200 if type(font
) <> StringType
:
201 font
= Fm
.GetFontName(font
)
202 self
.fontsettings
= (font
, style
, size
, color
)
203 fontid
= GetFNum(font
)
204 readonly
= self
.ted
.WEFeatureFlag(WASTEconst
.weFReadOnly
, -1)
206 self
.ted
.WEFeatureFlag(WASTEconst
.weFReadOnly
, 0)
208 self
.ted
.WEFeatureFlag(WASTEconst
.weFInhibitRecal
, 1)
209 selstart
, selend
= self
.ted
.WEGetSelection()
210 self
.ted
.WESetSelection(0, self
.ted
.WEGetTextLength())
211 self
.ted
.WESetStyle(WASTEconst
.weDoFace
, (0, 0, 0, (0, 0, 0)))
212 self
.ted
.WESetStyle(WASTEconst
.weDoFace |
213 WASTEconst
.weDoColor |
214 WASTEconst
.weDoFont |
216 (fontid
, style
, size
, color
))
217 self
.ted
.WEFeatureFlag(WASTEconst
.weFInhibitRecal
, 0)
219 self
.ted
.WESetSelection(selstart
, selend
)
222 self
.ted
.WEFeatureFlag(WASTEconst
.weFReadOnly
, 1)
223 viewrect
= self
.ted
.WEGetViewRect()
224 Qd
.EraseRect(viewrect
)
225 self
.ted
.WEUpdate(self
._parentwindow
.wid
.GetWindowPort().visRgn
)
226 self
.selectionchanged()
227 self
.updatescrollbars()
229 def adjust(self
, oldbounds
):
231 # Note: if App.DrawThemeEditTextFrame is ever used, it will be necessary
232 # to unconditionally outset the invalidated rectangles, since Appearance
233 # frames are drawn outside the bounds.
234 if self
._selected
and self
._parentwindow
._hasselframes
:
235 self
.GetWindow().InvalWindowRect(Qd
.InsetRect(oldbounds
, -3, -3))
236 self
.GetWindow().InvalWindowRect(Qd
.InsetRect(self
._bounds
, -3, -3))
238 self
.GetWindow().InvalWindowRect(oldbounds
)
239 self
.GetWindow().InvalWindowRect(self
._bounds
)
240 viewrect
, destrect
= self
._calctextbounds
()
241 self
.ted
.WESetViewRect(viewrect
)
242 self
.ted
.WESetDestRect(destrect
)
245 if self
.ted
.WEGetDestRect()[3] < viewrect
[1]:
247 self
.updatescrollbars()
249 # interface -----------------------
255 self
.ted
.WESetSelection(0, self
.ted
.WEGetTextLength())
256 self
.selectionchanged()
257 self
.updatescrollbars()
259 def selectline(self
, lineno
, charoffset
= 0):
260 newselstart
, newselend
= self
.ted
.WEGetLineRange(lineno
)
261 # Autoscroll makes the *end* of the selection visible, which,
262 # in the case of a whole line, is the beginning of the *next* line.
263 # So sometimes it leaves our line just above the view rect.
264 # Let's fool Waste by initially selecting one char less:
265 self
.ted
.WESetSelection(newselstart
+ charoffset
, newselend
-1)
266 self
.ted
.WESetSelection(newselstart
+ charoffset
, newselend
)
267 self
.selectionchanged()
268 self
.updatescrollbars()
270 def getselection(self
):
272 return self
.ted
.WEGetSelection()
274 return self
.selection
276 def setselection(self
, selstart
, selend
):
277 self
.selectionchanged()
279 self
.ted
.WESetSelection(selstart
, selend
)
281 self
.updatescrollbars()
283 self
.selection
= selstart
, selend
285 def offsettoline(self
, offset
):
286 return self
.ted
.WEOffsetToLine(offset
)
288 def countlines(self
):
289 return self
.ted
.WECountLines()
291 def getselectedtext(self
):
292 selstart
, selend
= self
.ted
.WEGetSelection()
293 return self
.ted
.WEGetText().data
[selstart
:selend
]
295 def expandselection(self
):
296 oldselstart
, oldselend
= self
.ted
.WEGetSelection()
297 selstart
, selend
= min(oldselstart
, oldselend
), max(oldselstart
, oldselend
)
298 if selstart
<> selend
and chr(self
.ted
.WEGetChar(selend
-1)) == '\r':
300 newselstart
, dummy
= self
.ted
.WEFindLine(selstart
, 1)
301 dummy
, newselend
= self
.ted
.WEFindLine(selend
, 1)
302 if oldselstart
<> newselstart
or oldselend
<> newselend
:
303 self
.ted
.WESetSelection(newselstart
, newselend
)
304 self
.updatescrollbars()
305 self
.selectionchanged()
307 def insert(self
, text
):
308 self
.ted
.WEInsert(text
, None, None)
310 self
.selectionchanged()
317 self
.ted
.WEUseText(Res
.Resource(text
))
320 viewrect
, destrect
= self
._calctextbounds
()
321 self
.ted
.WESetViewRect(viewrect
)
322 self
.ted
.WESetDestRect(destrect
)
324 Qd
.RectRgn(rgn
, viewrect
)
325 Qd
.EraseRect(viewrect
)
327 self
.updatescrollbars()
334 return self
.ted
.WEGetText().data
337 def key(self
, char
, event
):
338 (what
, message
, when
, where
, modifiers
) = event
339 if self
._enabled
and not modifiers
& Events
.cmdKey
or char
in Wkeys
.arrowkeys
:
340 self
.ted
.WEKey(ord(char
), modifiers
)
341 if char
not in Wkeys
.navigationkeys
:
343 if char
not in Wkeys
.scrollkeys
:
344 self
.selectionchanged()
345 self
.updatescrollbars()
347 Wbase
.CallbackCall(self
._callback
, 0, char
, modifiers
)
349 def click(self
, point
, modifiers
):
350 if not self
._enabled
:
352 self
.ted
.WEClick(point
, modifiers
, Evt
.TickCount())
353 self
.selectionchanged()
354 self
.updatescrollbars()
361 def rollover(self
, point
, onoff
):
363 Wbase
.SetCursor("iBeam")
365 def activate(self
, onoff
):
366 self
._activated
= onoff
370 # DISABLED! There are too many places where it is assumed that
371 # the frame of an EditText item is 1 pixel, inside the bounds.
372 #state = [kThemeStateActive, kThemeStateInactive][not onoff]
373 #App.DrawThemeEditTextFrame(Qd.InsetRect(self._bounds, 1, 1), state)
377 self
.ted
.WEActivate()
379 self
.ted
.WEDeactivate()
380 self
.drawselframe(onoff
)
382 def select(self
, onoff
, isclick
= 0):
383 if Wbase
.SelectableWidget
.select(self
, onoff
):
387 self
.ted
.WEActivate()
388 if self
._parentwindow
._tabbable
and not isclick
:
391 self
.ted
.WEDeactivate()
392 self
.drawselframe(onoff
)
394 def draw(self
, visRgn
= None):
397 visRgn
= self
._parentwindow
.wid
.GetWindowPort().visRgn
398 self
.ted
.WEUpdate(visRgn
)
400 # DISABLED! There are too many places where it is assumed that
401 # the frame of an EditText item is 1 pixel, inside the bounds.
402 #state = [kThemeStateActive, kThemeStateInactive][not self._activated]
403 #App.DrawThemeEditTextFrame(Qd.InsetRect(self._bounds, 1, 1), state)
404 Qd
.FrameRect(self
._bounds
)
406 if self
._selected
and self
._activated
:
410 def scrollpageup(self
):
411 if self
._parent
._bary
and self
._parent
._bary
._enabled
:
414 def scrollpagedown(self
):
415 if self
._parent
._bary
and self
._parent
._bary
._enabled
:
419 if self
._parent
._bary
and self
._parent
._bary
._enabled
:
420 self
.vscroll(self
._parent
._bary
.getmin())
421 if self
._parent
._barx
and self
._parent
._barx
._enabled
:
422 self
.hscroll(self
._parent
._barx
.getmin())
424 def scrollbottom(self
):
425 if self
._parent
._bary
and self
._parent
._bary
._enabled
:
426 self
.vscroll(self
._parent
._bary
.getmax())
429 def domenu_copy(self
, *args
):
430 selbegin
, selend
= self
.ted
.WEGetSelection()
431 if selbegin
== selend
:
433 if hasattr(Scrap
, 'ZeroScrap'):
436 Scrap
.ClearCurrentScrap()
438 self
.updatescrollbars()
440 def domenu_cut(self
, *args
):
441 selbegin
, selend
= self
.ted
.WEGetSelection()
442 if selbegin
== selend
:
444 if hasattr(Scrap
, 'ZeroScrap'):
447 Scrap
.ClearCurrentScrap()
449 self
.updatescrollbars()
452 self
.selectionchanged()
454 Wbase
.CallbackCall(self
._callback
, 0, "", None)
456 def domenu_paste(self
, *args
):
457 if not self
.ted
.WECanPaste():
461 self
.updatescrollbars()
463 self
.selectionchanged()
465 Wbase
.CallbackCall(self
._callback
, 0, "", None)
467 def domenu_clear(self
, *args
):
470 self
.updatescrollbars()
472 self
.selectionchanged()
474 Wbase
.CallbackCall(self
._callback
, 0, "", None)
476 def domenu_undo(self
, *args
):
477 which
, redo
= self
.ted
.WEGetUndoInfo()
481 self
.updatescrollbars()
483 self
.selectionchanged()
485 Wbase
.CallbackCall(self
._callback
, 0, "", None)
487 def can_undo(self
, menuitem
):
488 #doundo = self.ted.WEFeatureFlag(WASTEconst.weFUndo, -1)
492 which
, redo
= self
.ted
.WEGetUndoInfo()
493 if which
< len(UNDOLABELS
):
494 which
= UNDOLABELS
[which
]
500 which
= "Redo "+which
502 which
= "Undo "+which
503 menuitem
.settext(which
)
506 def domenu_selectall(self
, *args
):
510 def getscrollrects(self
):
511 return self
.ted
.WEGetDestRect(), self
.ted
.WEGetViewRect()
513 def vscroll(self
, value
):
514 lineheight
= self
.ted
.WEGetHeight(0, 1)
515 dr
= self
.ted
.WEGetDestRect()
516 vr
= self
.ted
.WEGetViewRect()
517 viewheight
= vr
[3] - vr
[1]
518 maxdelta
= vr
[1] - dr
[1]
519 mindelta
= vr
[3] - dr
[3]
525 delta
= viewheight
- lineheight
527 delta
= lineheight
- viewheight
529 delta
= vr
[1] - dr
[1] - value
530 delta
= min(maxdelta
, delta
)
531 delta
= max(mindelta
, delta
)
532 self
.ted
.WEScroll(0, delta
)
533 self
.updatescrollbars()
535 def hscroll(self
, value
):
536 dr
= self
.ted
.WEGetDestRect()
537 vr
= self
.ted
.WEGetViewRect()
538 destwidth
= dr
[2] - dr
[0]
539 viewwidth
= vr
[2] - vr
[0]
540 viewoffset
= maxdelta
= vr
[0] - dr
[0]
541 mindelta
= vr
[2] - dr
[2]
547 delta
= 0.5 * (vr
[2] - vr
[0])
549 delta
= 0.5 * (vr
[0] - vr
[2])
551 delta
= vr
[0] - dr
[0] - value
552 #cur = (32767 * viewoffset) / (destwidth - viewwidth)
553 #delta = (cur-value)*(destwidth - viewwidth)/32767
554 #if abs(delta - viewoffset) <=2:
555 # # compensate for irritating rounding error
557 delta
= min(maxdelta
, delta
)
558 delta
= max(mindelta
, delta
)
559 self
.ted
.WEScroll(delta
, 0)
560 self
.updatescrollbars()
564 flags
= WASTEconst
.weDoAutoScroll | WASTEconst
.weDoMonoStyled
566 flags
= flags | WASTEconst
.weDoReadOnly
568 flags
= flags | WASTEconst
.weDoUndo
571 def _getviewrect(self
):
572 return Qd
.InsetRect(self
._bounds
, self
.inset
[0], self
.inset
[1])
574 def _calctextbounds(self
):
575 viewrect
= l
, t
, r
, b
= self
._getviewrect
()
577 dl
, dt
, dr
, db
= self
.ted
.WEGetDestRect()
578 vl
, vt
, vr
, vb
= self
.ted
.WEGetViewRect()
580 if (db
- dt
) < (b
- t
):
583 destrect
= l
, dt
+ yshift
, r
, db
+ yshift
586 return viewrect
, destrect
589 class TextEditor(EditText
):
591 """A text edit widget."""
593 def __init__(self
, possize
, text
="", callback
=None, wrap
=1, inset
=(4, 4),
597 EditText
.__init
__(self
, possize
, text
, callback
, inset
, fontsettings
, tabsettings
, readonly
)
601 flags
= WASTEconst
.weDoAutoScroll | WASTEconst
.weDoMonoStyled | \
602 WASTEconst
.weDoOutlineHilite
604 flags
= flags | WASTEconst
.weDoReadOnly
606 flags
= flags | WASTEconst
.weDoUndo
609 def _getviewrect(self
):
610 l
, t
, r
, b
= self
._bounds
611 return (l
+ 5, t
+ 2, r
, b
- 2)
613 def _calctextbounds(self
):
615 return EditText
._calctextbounds
(self
)
617 viewrect
= l
, t
, r
, b
= self
._getviewrect
()
619 dl
, dt
, dr
, db
= self
.ted
.WEGetDestRect()
620 vl
, vt
, vr
, vb
= self
.ted
.WEGetViewRect()
623 if (db
- dt
) < (b
- t
):
625 destrect
= (dl
+ xshift
, dt
+ yshift
, dr
+ xshift
, db
+ yshift
)
627 destrect
= (l
, t
, r
+ 5000, b
)
628 return viewrect
, destrect
630 def draw(self
, visRgn
= None):
633 visRgn
= self
._parentwindow
.wid
.GetWindowPort().visRgn
634 self
.ted
.WEUpdate(visRgn
)
635 if self
._selected
and self
._activated
:
638 def activate(self
, onoff
):
639 self
._activated
= onoff
642 # doesn't draw frame, as EditText.activate does
645 self
.ted
.WEActivate()
647 self
.ted
.WEDeactivate()
648 self
.drawselframe(onoff
)
652 commentPat
= re
.compile("[ \t]*(#)")
653 indentPat
= re
.compile("[ \t]*")
654 kStringColor
= (0, 0x7fff, 0)
655 kCommentColor
= (0, 0, 0xb000)
658 class PyEditor(TextEditor
):
660 """A specialized Python source edit widget"""
662 def __init__(self
, possize
, text
="", callback
=None, inset
=(4, 4),
668 TextEditor
.__init
__(self
, possize
, text
, callback
, 0, inset
, fontsettings
, tabsettings
, readonly
)
669 self
.bind("cmd[", self
.domenu_shiftleft
)
670 self
.bind("cmd]", self
.domenu_shiftright
)
671 self
.bind("cmdshift[", self
.domenu_uncomment
)
672 self
.bind("cmdshift]", self
.domenu_comment
)
673 self
.bind("cmdshiftd", self
.alldirty
)
674 self
.file = file # only for debugger reference
675 self
._debugger
= debugger
677 debugger
.register_editor(self
, self
.file)
678 self
._dirty
= (0, None)
682 # TextEditor.open(self)
683 # if self.do_fontify:
685 # self._dirty = (None, None)
688 flags
= (WASTEconst
.weDoDrawOffscreen | WASTEconst
.weDoUseTempMem |
689 WASTEconst
.weDoAutoScroll | WASTEconst
.weDoOutlineHilite
)
691 flags
= flags | WASTEconst
.weDoReadOnly
693 flags
= flags | WASTEconst
.weDoUndo
696 def textchanged(self
, all
=0):
699 self
._dirty
= (0, None)
701 oldsel
= self
.oldselection
702 sel
= self
.getselection()
706 selstart
, selend
= sel
707 selstart
, selend
= min(selstart
, selend
), max(selstart
, selend
)
709 oldselstart
, oldselend
= min(oldsel
), max(oldsel
)
710 selstart
, selend
= min(selstart
, oldselstart
), max(selend
, oldselend
)
711 startline
= self
.offsettoline(selstart
)
712 endline
= self
.offsettoline(selend
)
713 selstart
, _
= self
.ted
.WEGetLineRange(startline
)
714 _
, selend
= self
.ted
.WEGetLineRange(endline
)
716 selstart
= selstart
- 1
717 self
._dirty
= (selstart
, selend
)
722 if not self
.do_fontify
:
724 start
, end
= self
._dirty
727 textLength
= self
.ted
.WEGetTextLength()
731 self
._dirty
= (None, None)
733 self
.fontify(start
, end
)
734 self
._dirty
= (None, None)
736 def alldirty(self
, *args
):
737 self
._dirty
= (0, None)
739 def fontify(self
, start
=0, end
=None):
740 #W.SetCursor('watch')
742 self
.ted
.WEFeatureFlag(WASTEconst
.weFReadOnly
, 0)
743 self
.ted
.WEFeatureFlag(WASTEconst
.weFOutlineHilite
, 0)
744 self
.ted
.WEDeactivate()
745 self
.ted
.WEFeatureFlag(WASTEconst
.weFAutoScroll
, 0)
746 self
.ted
.WEFeatureFlag(WASTEconst
.weFUndo
, 0)
747 pytext
= self
.get().replace("\r", "\n")
751 end
= min(end
, len(pytext
))
752 selstart
, selend
= self
.ted
.WEGetSelection()
753 self
.ted
.WESetSelection(start
, end
)
754 self
.ted
.WESetStyle(WASTEconst
.weDoFace | WASTEconst
.weDoColor
,
755 (0, 0, 12, (0, 0, 0)))
757 tags
= PyFontify
.fontify(pytext
, start
, end
)
759 'string': (WASTEconst
.weDoColor
, (0, 0, 0, kStringColor
)),
760 'keyword': (WASTEconst
.weDoFace
, (0, 1, 0, (0, 0, 0))),
761 'comment': (WASTEconst
.weDoFace | WASTEconst
.weDoColor
, (0, 0, 0, kCommentColor
)),
762 'identifier': (WASTEconst
.weDoColor
, (0, 0, 0, (0xbfff, 0, 0)))
764 setselection
= self
.ted
.WESetSelection
765 setstyle
= self
.ted
.WESetStyle
766 for tag
, start
, end
, sublist
in tags
:
767 setselection(start
, end
)
768 mode
, style
= styles
[tag
]
769 setstyle(mode
, style
)
770 self
.ted
.WESetSelection(selstart
, selend
)
772 self
.ted
.WEFeatureFlag(WASTEconst
.weFAutoScroll
, 1)
773 self
.ted
.WEFeatureFlag(WASTEconst
.weFUndo
, 1)
774 self
.ted
.WEActivate()
775 self
.ted
.WEFeatureFlag(WASTEconst
.weFOutlineHilite
, 1)
777 self
.ted
.WEFeatureFlag(WASTEconst
.weFReadOnly
, 1)
779 def domenu_shiftleft(self
):
780 self
.expandselection()
781 selstart
, selend
= self
.ted
.WEGetSelection()
782 selstart
, selend
= min(selstart
, selend
), max(selstart
, selend
)
783 snippet
= self
.getselectedtext()
784 lines
= string
.split(snippet
, '\r')
785 for i
in range(len(lines
)):
786 if lines
[i
][:1] == '\t':
787 lines
[i
] = lines
[i
][1:]
788 snippet
= string
.join(lines
, '\r')
790 self
.ted
.WESetSelection(selstart
, selstart
+ len(snippet
))
792 def domenu_shiftright(self
):
793 self
.expandselection()
794 selstart
, selend
= self
.ted
.WEGetSelection()
795 selstart
, selend
= min(selstart
, selend
), max(selstart
, selend
)
796 snippet
= self
.getselectedtext()
797 lines
= string
.split(snippet
, '\r')
798 for i
in range(len(lines
) - (not lines
[-1])):
799 lines
[i
] = '\t' + lines
[i
]
800 snippet
= string
.join(lines
, '\r')
802 self
.ted
.WESetSelection(selstart
, selstart
+ len(snippet
))
804 def domenu_uncomment(self
):
805 self
.expandselection()
806 selstart
, selend
= self
.ted
.WEGetSelection()
807 selstart
, selend
= min(selstart
, selend
), max(selstart
, selend
)
808 snippet
= self
.getselectedtext()
809 lines
= string
.split(snippet
, '\r')
810 for i
in range(len(lines
)):
811 m
= commentPat
.match(lines
[i
])
814 lines
[i
] = lines
[i
][:pos
] + lines
[i
][pos
+1:]
815 snippet
= string
.join(lines
, '\r')
817 self
.ted
.WESetSelection(selstart
, selstart
+ len(snippet
))
819 def domenu_comment(self
):
820 self
.expandselection()
821 selstart
, selend
= self
.ted
.WEGetSelection()
822 selstart
, selend
= min(selstart
, selend
), max(selstart
, selend
)
823 snippet
= self
.getselectedtext()
824 lines
= string
.split(snippet
, '\r')
825 indent
= 3000 # arbitrary large number...
827 if string
.strip(line
):
828 m
= indentPat
.match(line
)
830 indent
= min(indent
, m
.regs
[0][1])
834 for i
in range(len(lines
) - (not lines
[-1])):
835 lines
[i
] = lines
[i
][:indent
] + "#" + lines
[i
][indent
:]
836 snippet
= string
.join(lines
, '\r')
838 self
.ted
.WESetSelection(selstart
, selstart
+ len(snippet
))
840 def setfile(self
, file):
843 def set(self
, text
, file = ''):
847 self
._debugger
.unregister_editor(self
, oldfile
)
848 self
._debugger
.register_editor(self
, file)
849 TextEditor
.set(self
, text
)
853 self
._debugger
.unregister_editor(self
, self
.file)
854 self
._debugger
= None
855 TextEditor
.close(self
)
857 def click(self
, point
, modifiers
):
858 if not self
._enabled
:
860 if self
._debugger
and self
.pt_in_breaks(point
):
861 self
.breakhit(point
, modifiers
)
863 bl
, bt
, br
, bb
= self
._getbreakrect
()
864 Qd
.EraseRect((bl
, bt
, br
-1, bb
))
865 TextEditor
.click(self
, point
, modifiers
)
866 self
.drawbreakpoints()
868 TextEditor
.click(self
, point
, modifiers
)
869 if self
.ted
.WEGetClickCount() >= 3:
870 # select block with our indent
871 lines
= string
.split(self
.get(), '\r')
872 selstart
, selend
= self
.ted
.WEGetSelection()
873 lineno
= self
.ted
.WEOffsetToLine(selstart
)
876 while line
[tabs
:] and line
[tabs
] == '\t':
878 tabstag
= '\t' * tabs
882 for i
in range(lineno
- 1, -1, -1):
884 if line
[:tabs
] <> tabstag
:
887 for i
in range(lineno
+ 1, toline
):
889 if line
[:tabs
] <> tabstag
:
892 selstart
, dummy
= self
.ted
.WEGetLineRange(fromline
)
893 dummy
, selend
= self
.ted
.WEGetLineRange(toline
)
894 self
.ted
.WESetSelection(selstart
, selend
)
896 def breakhit(self
, point
, modifiers
):
899 destrect
= self
.ted
.WEGetDestRect()
900 offset
, edge
= self
.ted
.WEGetOffset(point
)
901 lineno
= self
.ted
.WEOffsetToLine(offset
) + 1
902 if point
[1] <= destrect
[3]:
903 self
._debugger
.clear_breaks_above(self
.file, self
.countlines())
904 self
._debugger
.toggle_break(self
.file, lineno
)
906 self
._debugger
.clear_breaks_above(self
.file, lineno
)
908 def key(self
, char
, event
):
909 (what
, message
, when
, where
, modifiers
) = event
910 if modifiers
& Events
.cmdKey
and not char
in Wkeys
.arrowkeys
:
913 selstart
, selend
= self
.ted
.WEGetSelection()
914 selstart
, selend
= min(selstart
, selend
), max(selstart
, selend
)
915 lastchar
= chr(self
.ted
.WEGetChar(selstart
-1))
916 if lastchar
<> '\r' and selstart
:
917 pos
, dummy
= self
.ted
.WEFindLine(selstart
, 0)
918 lineres
= Res
.Resource('')
919 self
.ted
.WECopyRange(pos
, selstart
, lineres
, None, None)
920 line
= lineres
.data
+ '\n'
921 tabcount
= self
.extratabs(line
)
922 self
.ted
.WEKey(ord('\r'), 0)
923 for i
in range(tabcount
):
924 self
.ted
.WEKey(ord('\t'), 0)
926 self
.ted
.WEKey(ord('\r'), 0)
928 self
.ted
.WEKey(ord(char
), modifiers
)
929 self
.balanceparens(char
)
931 self
.ted
.WEKey(ord(char
), modifiers
)
932 if char
not in Wkeys
.navigationkeys
:
934 self
.selectionchanged()
935 self
.updatescrollbars()
937 def balanceparens(self
, char
):
945 selstart
, selend
= self
.ted
.WEGetSelection()
946 count
= min(selstart
, selend
) - 2
947 mincount
= max(0, count
- 2048)
949 while count
> mincount
:
950 testchar
= chr(self
.ted
.WEGetChar(count
))
951 if testchar
in "\"'" and chr(self
.ted
.WEGetChar(count
- 1)) <> '\\':
952 if lastquote
== testchar
:
953 recursionlevel
= recursionlevel
- 1
956 recursionlevel
= recursionlevel
+ 1
958 elif not lastquote
and testchar
== char
:
959 recursionlevel
= recursionlevel
+ 1
960 elif not lastquote
and testchar
== target
:
961 recursionlevel
= recursionlevel
- 1
962 if recursionlevel
== 0:
964 autoscroll
= self
.ted
.WEFeatureFlag(WASTEconst
.weFAutoScroll
, -1)
966 self
.ted
.WEFeatureFlag(WASTEconst
.weFAutoScroll
, 0)
967 self
.ted
.WESetSelection(count
, count
+ 1)
968 Qd
.QDFlushPortBuffer(self
._parentwindow
.wid
, None) # needed under OSX
970 self
.ted
.WESetSelection(selstart
, selend
)
972 self
.ted
.WEFeatureFlag(WASTEconst
.weFAutoScroll
, 1)
976 def extratabs(self
, line
):
981 tabcount
= tabcount
+ 1
984 tags
= PyFontify
.fontify(line
)
985 # strip comments and strings
986 for tag
, start
, end
, sublist
in tags
:
987 if tag
in ('string', 'comment'):
988 cleanline
= cleanline
+ line
[last
:start
]
990 cleanline
= cleanline
+ line
[last
:]
991 cleanline
= string
.strip(cleanline
)
992 if cleanline
and cleanline
[-1] == ':':
993 tabcount
= tabcount
+ 1
995 # extra indent after unbalanced (, [ or {
996 for open, close
in (('(', ')'), ('[', ']'), ('{', '}')):
997 count
= string
.count(cleanline
, open)
998 if count
and count
> string
.count(cleanline
, close
):
999 tabcount
= tabcount
+ 2
1003 def rollover(self
, point
, onoff
):
1005 if self
._debugger
and self
.pt_in_breaks(point
):
1006 Wbase
.SetCursor("arrow")
1008 Wbase
.SetCursor("iBeam")
1010 def draw(self
, visRgn
= None):
1011 TextEditor
.draw(self
, visRgn
)
1013 self
.drawbreakpoints()
1015 def showbreakpoints(self
, onoff
):
1016 if (not not self
._debugger
) <> onoff
:
1020 raise W
.AlertError
, "Can't debug in \"Optimize bytecode\" mode.\r(see \"Default startup options\" in EditPythonPreferences)"
1022 self
._debugger
= PyDebugger
.getdebugger()
1023 self
._debugger
.register_editor(self
, self
.file)
1024 elif self
._debugger
:
1025 self
._debugger
.unregister_editor(self
, self
.file)
1026 self
._debugger
= None
1027 self
.adjust(self
._bounds
)
1029 def togglebreakpoints(self
):
1030 self
.showbreakpoints(not self
._debugger
)
1032 def clearbreakpoints(self
):
1034 self
._debugger
.clear_all_file_breaks(self
.file)
1036 def editbreakpoints(self
):
1038 self
._debugger
.edit_breaks()
1039 self
._debugger
.breaksviewer
.selectfile(self
.file)
1041 def drawbreakpoints(self
, eraseall
= 0):
1042 breakrect
= bl
, bt
, br
, bb
= self
._getbreakrect
()
1045 Qd
.PenPat(Qd
.qd
.gray
)
1046 Qd
.PaintRect((br
, bt
, br
+ 1, bb
))
1048 self
._parentwindow
.tempcliprect(breakrect
)
1049 Qd
.RGBForeColor((0xffff, 0, 0))
1053 Qd_PaintOval
= Qd
.PaintOval
1054 Qd_EraseRect
= Qd
.EraseRect
1055 for lineno
in self
._debugger
.get_file_breaks(self
.file):
1056 start
, end
= self_ted
.WEGetLineRange(lineno
- 1)
1057 if lineno
<> self_ted
.WEOffsetToLine(start
) + 1:
1058 # breakpoints beyond our text: erase rest, and back out
1059 Qd_EraseRect((bl
, lasttop
, br
, bb
))
1061 (x
, y
), h
= self_ted
.WEGetPoint(start
, 0)
1063 #print y, (lasttop, bottom)
1064 if bottom
> lasttop
:
1065 Qd_EraseRect((bl
, lasttop
, br
, y
+ h
* eraseall
))
1067 redbullet
= bl
+ 2, y
+ 3, bl
+ 8, y
+ 9
1068 Qd_PaintOval(redbullet
)
1070 Qd_EraseRect((bl
, lasttop
, br
, bb
))
1071 Qd
.RGBForeColor((0, 0, 0))
1073 self
._parentwindow
.restoreclip()
1075 def updatescrollbars(self
):
1077 self
.drawbreakpoints(1)
1078 TextEditor
.updatescrollbars(self
)
1080 def pt_in_breaks(self
, point
):
1081 return Qd
.PtInRect(point
, self
._getbreakrect
())
1083 def _getbreakrect(self
):
1085 l
, t
, r
, b
= self
._bounds
1086 return (l
+1, t
+1, l
+ 12, b
-1)
1090 def _getviewrect(self
):
1091 l
, t
, r
, b
= self
._bounds
1093 return (l
+ 17, t
+ 2, r
, b
- 2)
1095 return (l
+ 5, t
+ 2, r
, b
- 2)
1097 def _calctextbounds(self
):
1098 viewrect
= l
, t
, r
, b
= self
._getviewrect
()
1100 dl
, dt
, dr
, db
= self
.ted
.WEGetDestRect()
1101 vl
, vt
, vr
, vb
= self
.ted
.WEGetViewRect()
1104 if (db
- dt
) < (b
- t
):
1106 destrect
= (dl
+ xshift
, dt
+ yshift
, dr
+ xshift
, db
+ yshift
)
1108 destrect
= (l
, t
, r
+ 5000, b
)
1109 return viewrect
, destrect
1112 def GetFNum(fontname
):
1113 """Same as Fm.GetFNum(), but maps a missing font to Monaco instead of the system font."""
1114 if fontname
<> Fm
.GetFontName(0):
1115 fontid
= Fm
.GetFNum(fontname
)
1117 fontid
= Fonts
.monaco
1122 # b/w compat. Anyone using this?
1123 GetFName
= Fm
.GetFontName
1125 def GetPortFontSettings(port
):
1126 return Fm
.GetFontName(port
.txFont
), port
.txFace
, port
.txSize
1128 def SetPortFontSettings(port
, (font
, face
, size
)):
1129 saveport
= Qd
.GetPort()
1131 Qd
.TextFont(GetFNum(font
))
1134 Qd
.SetPort(saveport
)