1 #----------------------------------------------------------------------
2 # Name: wxPython.lib.editor.Editor
3 # Purpose: An intelligent text editor with colorization capabilities.
6 # Authors: Dirk Holtwic, Robin Dunn
9 # Authors: Adam Feuer, Steve Howell
12 # This code used to support a fairly complex subclass that did
13 # syntax coloring and outliner collapse mode. Adam and Steve
14 # inherited the code, and added a lot of basic editor
15 # functionality that had not been there before, such as cut-and-paste.
18 # Created: 15-Dec-1999
20 # Copyright: (c) 1999 by Dirk Holtwick, 1999
21 # Licence: wxWindows license
22 #----------------------------------------------------------------------
23 # 12/14/2003 - Jeff Grimmett (grimmtooth@softhome.net)
25 # o 2.5 compatability update.
27 # 12/21/2003 - Jeff Grimmett (grimmtooth@softhome.net)
29 # o wxEditor -> Editor
40 #----------------------------
42 def ForceBetween(min, val
, max):
50 def LineTrimmer(lineOfText
):
51 if len(lineOfText
) == 0:
53 elif lineOfText
[-1] == '\r':
54 return lineOfText
[:-1]
58 def LineSplitter(text
):
59 return map (LineTrimmer
, text
.split('\n'))
62 #----------------------------
65 def __init__(self
, parent
):
72 def SetScrollbars(self
, fw
, fh
, w
, h
, x
, y
):
73 if (self
.ow
!= w
or self
.oh
!= h
or self
.ox
!= x
or self
.oy
!= y
):
74 self
.parent
.SetScrollbars(fw
, fh
, w
, h
, x
, y
)
80 #----------------------------------------------------------------------
82 class Editor(wx
.ScrolledWindow
):
84 def __init__(self
, parent
, id,
85 pos
=wx
.DefaultPosition
, size
=wx
.DefaultSize
, style
=0):
87 wx
.ScrolledWindow
.__init
__(self
, parent
, id,
91 self
.isDrawing
= False
98 self
.InitDoubleBuffering()
103 self
.SpacesPerTab
= 4
105 ##------------------ Init stuff
107 def InitCoords(self
):
120 self
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnLeftDown
)
121 self
.Bind(wx
.EVT_LEFT_UP
, self
.OnLeftUp
)
122 self
.Bind(wx
.EVT_MOTION
, self
.OnMotion
)
123 self
.Bind(wx
.EVT_SCROLLWIN
, self
.OnScroll
)
124 self
.Bind(wx
.EVT_CHAR
, self
.OnChar
)
125 self
.Bind(wx
.EVT_PAINT
, self
.OnPaint
)
126 self
.Bind(wx
.EVT_SIZE
, self
.OnSize
)
127 self
.Bind(wx
.EVT_WINDOW_DESTROY
, self
.OnDestroy
)
128 self
.Bind(wx
.EVT_ERASE_BACKGROUND
, self
.OnEraseBackground
)
130 ##------------------- Platform-specific stuff
132 def NiceFontForPlatform(self
):
133 if wx
.Platform
== "__WXMSW__":
134 font
= wx
.Font(10, wx
.MODERN
, wx
.NORMAL
, wx
.NORMAL
)
136 font
= wx
.Font(12, wx
.MODERN
, wx
.NORMAL
, wx
.NORMAL
, False)
137 if wx
.Platform
== "__WXMAC__":
138 font
.SetNoAntiAliasing()
141 def UnixKeyHack(self
, key
):
143 # this will be obsolete when we get the new wxWindows patch
147 # Which patch? I don't know if this is needed, but I don't know
148 # why it's here either. Play it safe; leave it in.
154 ##-------------------- UpdateView/Cursor code
156 def OnSize(self
, event
):
157 self
.AdjustScrollbars()
160 def SetCharDimensions(self
):
161 # TODO: We need a code review on this. It appears that Linux
162 # improperly reports window dimensions when the scrollbar's there.
163 self
.bw
, self
.bh
= self
.GetClientSize()
165 if wx
.Platform
== "__WXMSW__":
166 self
.sh
= self
.bh
/ self
.fh
167 self
.sw
= (self
.bw
/ self
.fw
) - 1
169 self
.sh
= self
.bh
/ self
.fh
170 if self
.LinesInFile() >= self
.sh
:
171 self
.bw
= self
.bw
- wx
.SystemSettings_GetMetric(wx
.SYS_VSCROLL_X
)
172 self
.sw
= (self
.bw
/ self
.fw
) - 1
174 self
.sw
= (self
.bw
/ self
.fw
) - 1
175 if self
.CalcMaxLineLen() >= self
.sw
:
176 self
.bh
= self
.bh
- wx
.SystemSettings_GetMetric(wx
.SYS_HSCROLL_Y
)
177 self
.sh
= self
.bh
/ self
.fh
180 def UpdateView(self
, dc
= None):
182 dc
= wx
.ClientDC(self
)
184 self
.SetCharDimensions()
185 self
.KeepCursorOnScreen()
186 self
.DrawSimpleCursor(0,0, dc
, True)
189 def OnPaint(self
, event
):
190 dc
= wx
.PaintDC(self
)
193 self
.isDrawing
= True
195 wx
.CallAfter(self
.AdjustScrollbars
)
196 self
.isDrawing
= False
198 def OnEraseBackground(self
, evt
):
201 ##-------------------- Drawing code
204 dc
= wx
.ClientDC(self
)
205 self
.font
= self
.NiceFontForPlatform()
206 dc
.SetFont(self
.font
)
207 self
.fw
= dc
.GetCharWidth()
208 self
.fh
= dc
.GetCharHeight()
211 self
.fgColor
= wx
.NamedColour('black')
212 self
.bgColor
= wx
.NamedColour('white')
213 self
.selectColor
= wx
.Colour(238, 220, 120) # r, g, b = emacsOrange
215 def InitDoubleBuffering(self
):
218 def DrawEditText(self
, t
, x
, y
, dc
):
219 dc
.DrawText(t
, x
* self
.fw
, y
* self
.fh
)
221 def DrawLine(self
, line
, dc
):
222 if self
.IsLine(line
):
225 dc
.SetTextForeground(self
.fgColor
)
226 fragments
= selection
.Selection(
227 self
.SelectBegin
, self
.SelectEnd
,
228 self
.sx
, self
.sw
, line
, t
)
230 for (data
, selected
) in fragments
:
232 dc
.SetTextBackground(self
.selectColor
)
233 if x
== 0 and len(data
) == 0 and len(fragments
) == 1:
236 dc
.SetTextBackground(self
.bgColor
)
237 self
.DrawEditText(data
, x
, line
- self
.sy
, dc
)
240 def Draw(self
, odc
=None):
242 odc
= wx
.ClientDC(self
)
244 bmp
= wx
.EmptyBitmap(max(1,self
.bw
), max(1,self
.bh
))
245 dc
= wx
.BufferedDC(odc
, bmp
)
247 dc
.SetFont(self
.font
)
248 dc
.SetBackgroundMode(wx
.SOLID
)
249 dc
.SetTextBackground(self
.bgColor
)
250 dc
.SetTextForeground(self
.fgColor
)
252 for line
in range(self
.sy
, self
.sy
+ self
.sh
):
253 self
.DrawLine(line
, dc
)
254 if len(self
.lines
) < self
.sh
+ self
.sy
:
255 self
.DrawEofMarker(dc
)
258 ##------------------ eofMarker stuff
260 def LoadImages(self
):
261 self
.eofMarker
= images
.GetBitmap(images
.EofImageData
)
263 def DrawEofMarker(self
,dc
):
265 y
= (len(self
.lines
) - self
.sy
) * self
.fh
267 dc
.DrawBitmap(self
.eofMarker
, x
, y
, hasTransparency
)
269 ##------------------ cursor-related functions
271 def DrawCursor(self
, dc
= None):
273 dc
= wx
.ClientDC(self
)
275 if (self
.LinesInFile())<self
.cy
: #-1 ?
276 self
.cy
= self
.LinesInFile()-1
277 s
= self
.lines
[self
.cy
]
279 x
= self
.cx
- self
.sx
280 y
= self
.cy
- self
.sy
281 self
.DrawSimpleCursor(x
, y
, dc
)
284 def DrawSimpleCursor(self
, xp
, yp
, dc
= None, old
=False):
286 dc
= wx
.ClientDC(self
)
296 dc
.Blit(x
,y
, szx
,szy
, dc
, x
,y
, wx
.SRC_INVERT
)
300 ##-------- Enforcing screen boundaries, cursor movement
302 def CalcMaxLineLen(self
):
303 """get length of longest line on screen"""
305 for line
in self
.lines
[self
.sy
:self
.sy
+self
.sh
]:
306 if len(line
) >maxlen
:
310 def KeepCursorOnScreen(self
):
311 self
.sy
= ForceBetween(max(0, self
.cy
-self
.sh
), self
.sy
, self
.cy
)
312 self
.sx
= ForceBetween(max(0, self
.cx
-self
.sw
), self
.sx
, self
.cx
)
313 self
.AdjustScrollbars()
315 def HorizBoundaries(self
):
316 self
.SetCharDimensions()
317 maxLineLen
= self
.CalcMaxLineLen()
318 self
.sx
= ForceBetween(0, self
.sx
, max(self
.sw
, maxLineLen
- self
.sw
+ 1))
319 self
.cx
= ForceBetween(self
.sx
, self
.cx
, self
.sx
+ self
.sw
- 1)
321 def VertBoundaries(self
):
322 self
.SetCharDimensions()
323 self
.sy
= ForceBetween(0, self
.sy
, max(self
.sh
, self
.LinesInFile() - self
.sh
+ 1))
324 self
.cy
= ForceBetween(self
.sy
, self
.cy
, self
.sy
+ self
.sh
- 1)
326 def cVert(self
, num
):
327 self
.cy
= self
.cy
+ num
328 self
.cy
= ForceBetween(0, self
.cy
, self
.LinesInFile() - 1)
329 self
.sy
= ForceBetween(self
.cy
- self
.sh
+ 1, self
.sy
, self
.cy
)
330 self
.cx
= min(self
.cx
, self
.CurrentLineLength())
332 def cHoriz(self
, num
):
333 self
.cx
= self
.cx
+ num
334 self
.cx
= ForceBetween(0, self
.cx
, self
.CurrentLineLength())
335 self
.sx
= ForceBetween(self
.cx
- self
.sw
+ 1, self
.sx
, self
.cx
)
337 def AboveScreen(self
, row
):
340 def BelowScreen(self
, row
):
341 return row
>= self
.sy
+ self
.sh
343 def LeftOfScreen(self
, col
):
346 def RightOfScreen(self
, col
):
347 return col
>= self
.sx
+ self
.sw
349 ##----------------- data structure helper functions
354 def SetText(self
, lines
):
359 self
.AdjustScrollbars()
360 self
.UpdateView(None)
362 def IsLine(self
, lineNum
):
363 return (0<=lineNum
) and (lineNum
<self
.LinesInFile())
365 def GetTextLine(self
, lineNum
):
366 if self
.IsLine(lineNum
):
367 return self
.lines
[lineNum
]
370 def SetTextLine(self
, lineNum
, text
):
371 if self
.IsLine(lineNum
):
372 self
.lines
[lineNum
] = text
374 def CurrentLineLength(self
):
375 return len(self
.lines
[self
.cy
])
377 def LinesInFile(self
):
378 return len(self
.lines
)
380 def UnTouchBuffer(self
):
381 self
.bufferTouched
= False
383 def BufferWasTouched(self
):
384 return self
.bufferTouched
386 def TouchBuffer(self
):
387 self
.bufferTouched
= True
390 ##-------------------------- Mouse scroll timing functions
392 def InitScrolling(self
):
393 # we don't rely on the windows system to scroll for us; we just
394 # redraw the screen manually every time
395 self
.EnableScrolling(False, False)
396 self
.nextScrollTime
= 0
397 self
.SCROLLDELAY
= 0.050 # seconds
398 self
.scrollTimer
= wx
.Timer(self
)
399 self
.scroller
= Scroller(self
)
402 if time
.time() > self
.nextScrollTime
:
403 self
.nextScrollTime
= time
.time() + self
.SCROLLDELAY
408 def SetScrollTimer(self
):
410 self
.scrollTimer
.Start(1000*self
.SCROLLDELAY
/2, oneShot
)
411 self
.Bind(wx
.EVT_TIMER
, self
.OnTimer
)
413 def OnTimer(self
, event
):
414 screenX
, screenY
= wx
.GetMousePosition()
415 x
, y
= self
.ScreenToClientXY(screenX
, screenY
)
420 ##-------------------------- Mouse off screen functions
422 def HandleAboveScreen(self
, row
):
423 self
.SetScrollTimer()
429 def HandleBelowScreen(self
, row
):
430 self
.SetScrollTimer()
432 row
= self
.sy
+ self
.sh
433 row
= min(row
, self
.LinesInFile() - 1)
436 def HandleLeftOfScreen(self
, col
):
437 self
.SetScrollTimer()
443 def HandleRightOfScreen(self
, col
):
444 self
.SetScrollTimer()
446 col
= self
.sx
+ self
.sw
447 col
= min(col
, self
.CurrentLineLength())
450 ##------------------------ mousing functions
452 def MouseToRow(self
, mouseY
):
453 row
= self
.sy
+ (mouseY
/ self
.fh
)
454 if self
.AboveScreen(row
):
455 self
.HandleAboveScreen(row
)
456 elif self
.BelowScreen(row
):
457 self
.HandleBelowScreen(row
)
459 self
.cy
= min(row
, self
.LinesInFile() - 1)
461 def MouseToCol(self
, mouseX
):
462 col
= self
.sx
+ (mouseX
/ self
.fw
)
463 if self
.LeftOfScreen(col
):
464 self
.HandleLeftOfScreen(col
)
465 elif self
.RightOfScreen(col
):
466 self
.HandleRightOfScreen(col
)
468 self
.cx
= min(col
, self
.CurrentLineLength())
470 def MouseToCursor(self
, event
):
471 self
.MouseToRow(event
.GetY())
472 self
.MouseToCol(event
.GetX())
474 def OnMotion(self
, event
):
475 if event
.LeftIsDown() and self
.HasCapture():
476 self
.Selecting
= True
477 self
.MouseToCursor(event
)
480 def OnLeftDown(self
, event
):
481 self
.MouseToCursor(event
)
482 self
.SelectBegin
= (self
.cy
, self
.cx
)
483 self
.SelectEnd
= None
487 def OnLeftUp(self
, event
):
488 if not self
.HasCapture():
491 if self
.SelectEnd
is None:
494 self
.Selecting
= False
495 self
.SelectNotify(False, self
.SelectBegin
, self
.SelectEnd
)
498 self
.scrollTimer
.Stop()
501 #------------------------- Scrolling
503 def HorizScroll(self
, event
, eventType
):
504 maxLineLen
= self
.CalcMaxLineLen()
506 if eventType
== wx
.EVT_SCROLLWIN_LINEUP
:
508 elif eventType
== wx
.EVT_SCROLLWIN_LINEDOWN
:
510 elif eventType
== wx
.EVT_SCROLLWIN_PAGEUP
:
512 elif eventType
== wx
.EVT_SCROLLWIN_PAGEDOWN
:
514 elif eventType
== wx
.EVT_SCROLLWIN_TOP
:
515 self
.sx
= self
.cx
= 0
516 elif eventType
== wx
.EVT_SCROLLWIN_BOTTOM
:
517 self
.sx
= maxLineLen
- self
.sw
520 self
.sx
= event
.GetPosition()
522 self
.HorizBoundaries()
524 def VertScroll(self
, event
, eventType
):
525 if eventType
== wx
.EVT_SCROLLWIN_LINEUP
:
527 elif eventType
== wx
.EVT_SCROLLWIN_LINEDOWN
:
529 elif eventType
== wx
.EVT_SCROLLWIN_PAGEUP
:
531 elif eventType
== wx
.EVT_SCROLLWIN_PAGEDOWN
:
533 elif eventType
== wx
.EVT_SCROLLWIN_TOP
:
534 self
.sy
= self
.cy
= 0
535 elif eventType
== wx
.EVT_SCROLLWIN_BOTTOM
:
536 self
.sy
= self
.LinesInFile() - self
.sh
537 self
.cy
= self
.LinesInFile()
539 self
.sy
= event
.GetPosition()
541 self
.VertBoundaries()
543 def OnScroll(self
, event
):
544 dir = event
.GetOrientation()
545 eventType
= event
.GetEventType()
546 if dir == wx
.HORIZONTAL
:
547 self
.HorizScroll(event
, eventType
)
549 self
.VertScroll(event
, eventType
)
553 def AdjustScrollbars(self
):
555 self
.SetCharDimensions()
556 self
.scroller
.SetScrollbars(
558 self
.CalcMaxLineLen()+3, max(self
.LinesInFile()+1, self
.sh
),
561 #------------ backspace, delete, return
563 def BreakLine(self
, event
):
564 if self
.IsLine(self
.cy
):
565 t
= self
.lines
[self
.cy
]
566 self
.lines
= self
.lines
[:self
.cy
] + [t
[:self
.cx
],t
[self
.cx
:]] + self
.lines
[self
.cy
+1:]
571 def InsertChar(self
,char
):
572 if self
.IsLine(self
.cy
):
573 t
= self
.lines
[self
.cy
]
574 t
= t
[:self
.cx
] + char
+ t
[self
.cx
:]
575 self
.SetTextLine(self
.cy
, t
)
580 t1
= self
.lines
[self
.cy
]
581 t2
= self
.lines
[self
.cy
+1]
583 self
.lines
= self
.lines
[:self
.cy
] + [t1
+ t2
] + self
.lines
[self
.cy
+2:]
587 def DeleteChar(self
,x
,y
,oldtext
):
588 newtext
= oldtext
[:x
] + oldtext
[x
+1:]
589 self
.SetTextLine(y
, newtext
)
593 def BackSpace(self
, event
):
594 t
= self
.GetTextLine(self
.cy
)
596 self
.DeleteChar(self
.cx
-1,self
.cy
,t
)
607 def Delete(self
, event
):
608 t
= self
.GetTextLine(self
.cy
)
610 self
.DeleteChar(self
.cx
,self
.cy
,t
)
613 if self
.cy
< len(self
.lines
) - 1:
617 def Escape(self
, event
):
620 def TabKey(self
, event
):
621 numSpaces
= self
.SpacesPerTab
- (self
.cx
% self
.SpacesPerTab
)
622 self
.SingleLineInsert(' ' * numSpaces
)
624 ##----------- selection routines
626 def SelectUpdate(self
):
627 self
.SelectEnd
= (self
.cy
, self
.cx
)
628 self
.SelectNotify(self
.Selecting
, self
.SelectBegin
, self
.SelectEnd
)
631 def NormalizedSelect(self
):
632 (begin
, end
) = (self
.SelectBegin
, self
.SelectEnd
)
645 def FindSelection(self
):
646 if self
.SelectEnd
is None or self
.SelectBegin
is None:
649 (begin
, end
) = self
.NormalizedSelect()
652 return (bRow
, bCol
, eRow
, eCol
)
655 self
.SelectBegin
= None
656 self
.SelectEnd
= None
657 self
.Selecting
= False
658 self
.SelectNotify(False,None,None)
660 def CopySelection(self
, event
):
661 selection
= self
.FindSelection()
662 if selection
is None:
664 (bRow
, bCol
, eRow
, eCol
) = selection
667 self
.SingleLineCopy(bRow
, bCol
, eCol
)
669 self
.MultipleLineCopy(bRow
, bCol
, eRow
, eCol
)
671 def OnCopySelection(self
, event
):
672 self
.CopySelection(event
)
675 def CopyToClipboard(self
, linesOfText
):
676 do
= wx
.TextDataObject()
677 do
.SetText(os
.linesep
.join(linesOfText
))
678 wx
.TheClipboard
.Open()
679 wx
.TheClipboard
.SetData(do
)
680 wx
.TheClipboard
.Close()
682 def SingleLineCopy(self
, Row
, bCol
, eCol
):
683 Line
= self
.GetTextLine(Row
)
684 self
.CopyToClipboard([Line
[bCol
:eCol
]])
686 def MultipleLineCopy(self
, bRow
, bCol
, eRow
, eCol
):
687 bLine
= self
.GetTextLine(bRow
)[bCol
:]
688 eLine
= self
.GetTextLine(eRow
)[:eCol
]
689 self
.CopyToClipboard([bLine
] + [l
for l
in self
.lines
[bRow
+ 1:eRow
]] + [eLine
])
691 def OnDeleteSelection(self
, event
):
692 selection
= self
.FindSelection()
693 if selection
is None:
695 (bRow
, bCol
, eRow
, eCol
) = selection
698 self
.SingleLineDelete(bRow
, bCol
, eCol
)
700 self
.MultipleLineDelete(bRow
, bCol
, eRow
, eCol
)
710 def SingleLineDelete(self
, Row
, bCol
, eCol
):
711 ModLine
= self
.GetTextLine(Row
)
712 ModLine
= ModLine
[:bCol
] + ModLine
[eCol
:]
713 self
.SetTextLine(Row
,ModLine
)
715 def MultipleLineDelete(self
, bRow
, bCol
, eRow
, eCol
):
716 bLine
= self
.GetTextLine(bRow
)
717 eLine
= self
.GetTextLine(eRow
)
718 ModLine
= bLine
[:bCol
] + eLine
[eCol
:]
719 self
.lines
[bRow
:eRow
+ 1] = [ModLine
]
721 def OnPaste(self
, event
):
722 do
= wx
.TextDataObject()
723 wx
.TheClipboard
.Open()
724 success
= wx
.TheClipboard
.GetData(do
)
725 wx
.TheClipboard
.Close()
727 pastedLines
= LineSplitter(do
.GetText())
731 if len(pastedLines
) == 0:
734 elif len(pastedLines
) == 1:
735 self
.SingleLineInsert(pastedLines
[0])
737 self
.MultipleLinePaste(pastedLines
)
739 def SingleLineInsert(self
, newText
):
740 ModLine
= self
.GetTextLine(self
.cy
)
741 ModLine
= ModLine
[:self
.cx
] + newText
+ ModLine
[self
.cx
:]
742 self
.SetTextLine(self
.cy
, ModLine
)
743 self
.cHoriz(len(newText
))
747 def MultipleLinePaste(self
, pastedLines
):
748 FirstLine
= LastLine
= self
.GetTextLine(self
.cy
)
749 FirstLine
= FirstLine
[:self
.cx
] + pastedLines
[0]
750 LastLine
= pastedLines
[-1] + LastLine
[self
.cx
:]
752 NewSlice
= [FirstLine
]
753 NewSlice
+= [l
for l
in pastedLines
[1:-1]]
754 NewSlice
+= [LastLine
]
755 self
.lines
[self
.cy
:self
.cy
+ 1] = NewSlice
757 self
.cy
= self
.cy
+ len(pastedLines
)-1
758 self
.cx
= len(pastedLines
[-1])
762 def OnCutSelection(self
,event
):
763 self
.CopySelection(event
)
764 self
.OnDeleteSelection(event
)
766 #-------------- Keyboard movement implementations
768 def MoveDown(self
, event
):
771 def MoveUp(self
, event
):
774 def MoveLeft(self
, event
):
780 self
.cx
= self
.CurrentLineLength()
784 def MoveRight(self
, event
):
785 linelen
= self
.CurrentLineLength()
786 if self
.cx
== linelen
:
787 if self
.cy
== len(self
.lines
) - 1:
796 def MovePageDown(self
, event
):
799 def MovePageUp(self
, event
):
802 def MoveHome(self
, event
):
805 def MoveEnd(self
, event
):
806 self
.cx
= self
.CurrentLineLength()
808 def MoveStartOfFile(self
, event
):
812 def MoveEndOfFile(self
, event
):
813 self
.cy
= len(self
.lines
) - 1
814 self
.cx
= self
.CurrentLineLength()
816 #-------------- Key handler mapping tables
818 def SetMoveSpecialFuncs(self
, action
):
819 action
[wx
.WXK_DOWN
] = self
.MoveDown
820 action
[wx
.WXK_UP
] = self
.MoveUp
821 action
[wx
.WXK_LEFT
] = self
.MoveLeft
822 action
[wx
.WXK_RIGHT
] = self
.MoveRight
823 action
[wx
.WXK_NEXT
] = self
.MovePageDown
824 action
[wx
.WXK_PRIOR
] = self
.MovePageUp
825 action
[wx
.WXK_HOME
] = self
.MoveHome
826 action
[wx
.WXK_END
] = self
.MoveEnd
828 def SetMoveSpecialControlFuncs(self
, action
):
829 action
[wx
.WXK_HOME
] = self
.MoveStartOfFile
830 action
[wx
.WXK_END
] = self
.MoveEndOfFile
832 def SetAltFuncs(self
, action
):
833 # subclass implements
836 def SetControlFuncs(self
, action
):
837 action
['c'] = self
.OnCopySelection
838 action
['d'] = self
.OnDeleteSelection
839 action
['v'] = self
.OnPaste
840 action
['x'] = self
.OnCutSelection
842 def SetSpecialControlFuncs(self
, action
):
843 action
[wx
.WXK_INSERT
] = self
.OnCopySelection
845 def SetShiftFuncs(self
, action
):
846 action
[wx
.WXK_DELETE
] = self
.OnCutSelection
847 action
[wx
.WXK_INSERT
] = self
.OnPaste
849 def SetSpecialFuncs(self
, action
):
850 action
[wx
.WXK_BACK
] = self
.BackSpace
851 action
[wx
.WXK_DELETE
] = self
.Delete
852 action
[wx
.WXK_RETURN
] = self
.BreakLine
853 action
[wx
.WXK_ESCAPE
] = self
.Escape
854 action
[wx
.WXK_TAB
] = self
.TabKey
856 ##-------------- Logic for key handlers
859 def Move(self
, keySettingFunction
, key
, event
):
861 keySettingFunction(action
)
863 if not action
.has_key(key
):
866 if event
.ShiftDown():
867 if not self
.Selecting
:
868 self
.Selecting
= True
869 self
.SelectBegin
= (self
.cy
, self
.cx
)
871 self
.SelectEnd
= (self
.cy
, self
.cx
)
875 self
.Selecting
= False
877 self
.SelectNotify(self
.Selecting
, self
.SelectBegin
, self
.SelectEnd
)
881 def MoveSpecialKey(self
, event
, key
):
882 return self
.Move(self
.SetMoveSpecialFuncs
, key
, event
)
884 def MoveSpecialControlKey(self
, event
, key
):
885 if not event
.ControlDown():
887 return self
.Move(self
.SetMoveSpecialControlFuncs
, key
, event
)
889 def Dispatch(self
, keySettingFunction
, key
, event
):
891 keySettingFunction(action
)
892 if action
.has_key(key
):
898 def ModifierKey(self
, key
, event
, modifierKeyDown
, MappingFunc
):
899 if not modifierKeyDown
:
902 key
= self
.UnixKeyHack(key
)
907 if not self
.Dispatch(MappingFunc
, key
, event
):
911 def ControlKey(self
, event
, key
):
912 return self
.ModifierKey(key
, event
, event
.ControlDown(), self
.SetControlFuncs
)
914 def AltKey(self
, event
, key
):
915 return self
.ModifierKey(key
, event
, event
.AltDown(), self
.SetAltFuncs
)
917 def SpecialControlKey(self
, event
, key
):
918 if not event
.ControlDown():
920 if not self
.Dispatch(self
.SetSpecialControlFuncs
, key
, event
):
924 def ShiftKey(self
, event
, key
):
925 if not event
.ShiftDown():
927 return self
.Dispatch(self
.SetShiftFuncs
, key
, event
)
929 def NormalChar(self
, event
, key
):
933 if not self
.Dispatch(self
.SetSpecialFuncs
, key
, event
):
934 if (key
>31) and (key
<256):
935 self
.InsertChar(chr(key
))
940 self
.AdjustScrollbars()
942 def OnChar(self
, event
):
943 key
= event
.KeyCode()
944 filters
= [self
.AltKey
,
945 self
.MoveSpecialControlKey
,
947 self
.SpecialControlKey
,
951 for filter in filters
:
952 if filter(event
,key
):
956 #----------------------- Eliminate memory leaks
958 def OnDestroy(self
, event
):
964 self
.selectColor
= None
965 self
.scrollTimer
= None
966 self
.eofMarker
= None
968 #-------------------- Abstract methods for subclasses
973 def SelectNotify(self
, Selecting
, SelectionBegin
, SelectionEnd
):