]> git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/ide/activegrid/tool/STCTextEditor.py
Don't use the old wxPython namespace
[wxWidgets.git] / wxPython / samples / ide / activegrid / tool / STCTextEditor.py
1 #----------------------------------------------------------------------------
2 # Name: STCTextEditor.py
3 # Purpose: Text Editor for wx.lib.pydocview tbat uses the Styled Text Control
4 #
5 # Author: Peter Yared, Morgan Hua
6 #
7 # Created: 8/10/03
8 # CVS-ID: $Id$
9 # Copyright: (c) 2003-2006 ActiveGrid, Inc.
10 # License: wxWindows License
11 #----------------------------------------------------------------------------
12
13 import wx
14 import wx.stc
15 import wx.lib.docview
16 import wx.lib.multisash
17 import wx.lib.pydocview
18 import string
19 import FindService
20 import os
21 import sys
22 _ = wx.GetTranslation
23
24 #----------------------------------------------------------------------------
25 # Constants
26 #----------------------------------------------------------------------------
27
28 TEXT_ID = wx.NewId()
29 VIEW_WHITESPACE_ID = wx.NewId()
30 VIEW_EOL_ID = wx.NewId()
31 VIEW_INDENTATION_GUIDES_ID = wx.NewId()
32 VIEW_RIGHT_EDGE_ID = wx.NewId()
33 VIEW_LINE_NUMBERS_ID = wx.NewId()
34 ZOOM_ID = wx.NewId()
35 ZOOM_NORMAL_ID = wx.NewId()
36 ZOOM_IN_ID = wx.NewId()
37 ZOOM_OUT_ID = wx.NewId()
38 CHOOSE_FONT_ID = wx.NewId()
39 WORD_WRAP_ID = wx.NewId()
40 TEXT_STATUS_BAR_ID = wx.NewId()
41
42
43 #----------------------------------------------------------------------------
44 # Classes
45 #----------------------------------------------------------------------------
46
47 class TextDocument(wx.lib.docview.Document):
48
49
50 def __init__(self):
51 wx.lib.docview.Document .__init__(self)
52 self._inModify = False
53
54
55 def SaveObject(self, fileObject):
56 view = self.GetFirstView()
57 fileObject.write(view.GetValue())
58 view.SetModifyFalse()
59 return True
60
61
62 def LoadObject(self, fileObject):
63 view = self.GetFirstView()
64 data = fileObject.read()
65 view.SetValue(data)
66 view.SetModifyFalse()
67 return True
68
69
70 def IsModified(self):
71 view = self.GetFirstView()
72 if view:
73 return view.IsModified()
74 return False
75
76
77 def Modify(self, modify):
78 if self._inModify:
79 return
80 self._inModify = True
81
82 view = self.GetFirstView()
83 if not modify and view:
84 view.SetModifyFalse()
85
86 wx.lib.docview.Document.Modify(self, modify) # this must called be after the SetModifyFalse call above.
87
88 self._inModify = False
89
90
91 def OnCreateCommandProcessor(self):
92 # Don't create a command processor, it has its own
93 pass
94
95
96 # Use this to override MultiClient.Select to prevent yellow background.
97 def MultiClientSelectBGNotYellow(a):
98 a.GetParent().multiView.UnSelect()
99 a.selected = True
100 #a.SetBackgroundColour(wx.Colour(255,255,0)) # Yellow
101 a.Refresh()
102
103 class TextView(wx.lib.docview.View):
104 MARKER_NUM = 0
105 MARKER_MASK = 0x1
106
107 #----------------------------------------------------------------------------
108 # Overridden methods
109 #----------------------------------------------------------------------------
110
111 def __init__(self):
112 wx.lib.docview.View.__init__(self)
113 self._textEditor = None
114 self._markerCount = 0
115 self._commandProcessor = None
116 self._dynSash = None
117
118
119 def GetCtrlClass(self):
120 """ Used in split window to instantiate new instances """
121 return TextCtrl
122
123
124 def GetCtrl(self):
125 if wx.Platform == "__WXMAC__":
126 # look for active one first
127 self._textEditor = self._GetActiveCtrl(self._dynSash)
128 if self._textEditor == None: # it is possible none are active
129 # look for any existing one
130 self._textEditor = self._FindCtrl(self._dynSash)
131 return self._textEditor
132
133
134 def SetCtrl(self, ctrl):
135 self._textEditor = ctrl
136
137
138 def OnCreatePrintout(self):
139 """ for Print Preview and Print """
140 return TextPrintout(self, self.GetDocument().GetPrintableName())
141
142
143 def OnCreate(self, doc, flags):
144 frame = wx.GetApp().CreateDocumentFrame(self, doc, flags, style = wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
145 # wxBug: DynamicSashWindow doesn't work on Mac, so revert to
146 # multisash implementation
147 if wx.Platform == "__WXMAC__":
148 wx.lib.multisash.MultiClient.Select = MultiClientSelectBGNotYellow
149 self._dynSash = wx.lib.multisash.MultiSash(frame, -1)
150 self._dynSash.SetDefaultChildClass(self.GetCtrlClass()) # wxBug: MultiSash instantiates the first TextCtrl with this call
151
152 self._textEditor = self.GetCtrl() # wxBug: grab the TextCtrl from the MultiSash datastructure
153 else:
154 self._dynSash = wx.gizmos.DynamicSashWindow(frame, -1, style=wx.CLIP_CHILDREN)
155 self._dynSash._view = self
156 self._textEditor = self.GetCtrlClass()(self._dynSash, -1, style=wx.NO_BORDER)
157 wx.EVT_LEFT_DOWN(self._textEditor, self.OnLeftClick)
158 self._textEditor.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModify)
159
160 self._CreateSizer(frame)
161 self.Activate()
162 frame.Show(True)
163 frame.Layout()
164 return True
165
166
167 def OnModify(self, event):
168 self.GetDocument().Modify(self._textEditor.GetModify())
169
170
171 def _CreateSizer(self, frame):
172 sizer = wx.BoxSizer(wx.HORIZONTAL)
173 sizer.Add(self._dynSash, 1, wx.EXPAND)
174 frame.SetSizer(sizer)
175
176
177 def OnLeftClick(self, event):
178 self.Activate()
179 event.Skip()
180
181
182 def OnUpdate(self, sender = None, hint = None):
183 if wx.lib.docview.View.OnUpdate(self, sender, hint):
184 return
185
186 if hint == "ViewStuff":
187 self.GetCtrl().SetViewDefaults()
188 elif hint == "Font":
189 font, color = self.GetCtrl().GetFontAndColorFromConfig()
190 self.GetCtrl().SetFont(font)
191 self.GetCtrl().SetFontColor(color)
192
193
194 def OnActivateView(self, activate, activeView, deactiveView):
195 if activate and self.GetCtrl():
196 # In MDI mode just calling set focus doesn't work and in SDI mode using CallAfter causes an endless loop
197 if self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
198 self.SetFocus()
199 else:
200 wx.CallAfter(self.SetFocus)
201
202
203 def SetFocus(self):
204 if self.GetCtrl():
205 self.GetCtrl().SetFocus()
206
207
208 def OnClose(self, deleteWindow = True):
209 if not wx.lib.docview.View.OnClose(self, deleteWindow):
210 return False
211 self.Activate(False)
212 if deleteWindow and self.GetFrame():
213 self.GetFrame().Destroy()
214 return True
215
216
217 def ProcessEvent(self, event):
218 id = event.GetId()
219 if id == wx.ID_UNDO:
220 self.GetCtrl().Undo()
221 return True
222 elif id == wx.ID_REDO:
223 self.GetCtrl().Redo()
224 return True
225 elif id == wx.ID_CUT:
226 self.GetCtrl().Cut()
227 return True
228 elif id == wx.ID_COPY:
229 self.GetCtrl().Copy()
230 return True
231 elif id == wx.ID_PASTE:
232 self.GetCtrl().OnPaste()
233 return True
234 elif id == wx.ID_CLEAR:
235 self.GetCtrl().OnClear()
236 return True
237 elif id == wx.ID_SELECTALL:
238 self.GetCtrl().SetSelection(0, -1)
239 return True
240 elif id == VIEW_WHITESPACE_ID:
241 self.GetCtrl().SetViewWhiteSpace(not self.GetCtrl().GetViewWhiteSpace())
242 return True
243 elif id == VIEW_EOL_ID:
244 self.GetCtrl().SetViewEOL(not self.GetCtrl().GetViewEOL())
245 return True
246 elif id == VIEW_INDENTATION_GUIDES_ID:
247 self.GetCtrl().SetIndentationGuides(not self.GetCtrl().GetIndentationGuides())
248 return True
249 elif id == VIEW_RIGHT_EDGE_ID:
250 self.GetCtrl().SetViewRightEdge(not self.GetCtrl().GetViewRightEdge())
251 return True
252 elif id == VIEW_LINE_NUMBERS_ID:
253 self.GetCtrl().SetViewLineNumbers(not self.GetCtrl().GetViewLineNumbers())
254 return True
255 elif id == ZOOM_NORMAL_ID:
256 self.GetCtrl().SetZoom(0)
257 return True
258 elif id == ZOOM_IN_ID:
259 self.GetCtrl().CmdKeyExecute(wx.stc.STC_CMD_ZOOMIN)
260 return True
261 elif id == ZOOM_OUT_ID:
262 self.GetCtrl().CmdKeyExecute(wx.stc.STC_CMD_ZOOMOUT)
263 return True
264 elif id == CHOOSE_FONT_ID:
265 self.OnChooseFont()
266 return True
267 elif id == WORD_WRAP_ID:
268 self.GetCtrl().SetWordWrap(not self.GetCtrl().GetWordWrap())
269 return True
270 elif id == FindService.FindService.FIND_ID:
271 self.OnFind()
272 return True
273 elif id == FindService.FindService.FIND_PREVIOUS_ID:
274 self.DoFind(forceFindPrevious = True)
275 return True
276 elif id == FindService.FindService.FIND_NEXT_ID:
277 self.DoFind(forceFindNext = True)
278 return True
279 elif id == FindService.FindService.REPLACE_ID:
280 self.OnFind(replace = True)
281 return True
282 elif id == FindService.FindService.FINDONE_ID:
283 self.DoFind()
284 return True
285 elif id == FindService.FindService.REPLACEONE_ID:
286 self.DoFind(replace = True)
287 return True
288 elif id == FindService.FindService.REPLACEALL_ID:
289 self.DoFind(replaceAll = True)
290 return True
291 elif id == FindService.FindService.GOTO_LINE_ID:
292 self.OnGotoLine(event)
293 return True
294 else:
295 return wx.lib.docview.View.ProcessEvent(self, event)
296
297
298 def ProcessUpdateUIEvent(self, event):
299 if not self.GetCtrl():
300 return False
301
302 id = event.GetId()
303 if id == wx.ID_UNDO:
304 event.Enable(self.GetCtrl().CanUndo())
305 event.SetText(_("&Undo\tCtrl+Z")) # replace menu string
306 return True
307 elif id == wx.ID_REDO:
308 event.Enable(self.GetCtrl().CanRedo())
309 event.SetText(_("&Redo\tCtrl+Y")) # replace menu string
310 return True
311 elif (id == wx.ID_CUT
312 or id == wx.ID_COPY
313 or id == wx.ID_CLEAR):
314 hasSelection = self.GetCtrl().GetSelectionStart() != self.GetCtrl().GetSelectionEnd()
315 event.Enable(hasSelection)
316 return True
317 elif id == wx.ID_PASTE:
318 event.Enable(self.GetCtrl().CanPaste())
319 return True
320 elif id == wx.ID_SELECTALL:
321 hasText = self.GetCtrl().GetTextLength() > 0
322 event.Enable(hasText)
323 return True
324 elif id == TEXT_ID:
325 event.Enable(True)
326 return True
327 elif id == VIEW_WHITESPACE_ID:
328 hasText = self.GetCtrl().GetTextLength() > 0
329 event.Enable(hasText)
330 event.Check(self.GetCtrl().GetViewWhiteSpace())
331 return True
332 elif id == VIEW_EOL_ID:
333 hasText = self.GetCtrl().GetTextLength() > 0
334 event.Enable(hasText)
335 event.Check(self.GetCtrl().GetViewEOL())
336 return True
337 elif id == VIEW_INDENTATION_GUIDES_ID:
338 hasText = self.GetCtrl().GetTextLength() > 0
339 event.Enable(hasText)
340 event.Check(self.GetCtrl().GetIndentationGuides())
341 return True
342 elif id == VIEW_RIGHT_EDGE_ID:
343 hasText = self.GetCtrl().GetTextLength() > 0
344 event.Enable(hasText)
345 event.Check(self.GetCtrl().GetViewRightEdge())
346 return True
347 elif id == VIEW_LINE_NUMBERS_ID:
348 hasText = self.GetCtrl().GetTextLength() > 0
349 event.Enable(hasText)
350 event.Check(self.GetCtrl().GetViewLineNumbers())
351 return True
352 elif id == ZOOM_ID:
353 event.Enable(True)
354 return True
355 elif id == ZOOM_NORMAL_ID:
356 event.Enable(self.GetCtrl().GetZoom() != 0)
357 return True
358 elif id == ZOOM_IN_ID:
359 event.Enable(self.GetCtrl().GetZoom() < 20)
360 return True
361 elif id == ZOOM_OUT_ID:
362 event.Enable(self.GetCtrl().GetZoom() > -10)
363 return True
364 elif id == CHOOSE_FONT_ID:
365 event.Enable(True)
366 return True
367 elif id == WORD_WRAP_ID:
368 event.Enable(self.GetCtrl().CanWordWrap())
369 event.Check(self.GetCtrl().CanWordWrap() and self.GetCtrl().GetWordWrap())
370 return True
371 elif id == FindService.FindService.FIND_ID:
372 hasText = self.GetCtrl().GetTextLength() > 0
373 event.Enable(hasText)
374 return True
375 elif id == FindService.FindService.FIND_PREVIOUS_ID:
376 hasText = self.GetCtrl().GetTextLength() > 0
377 event.Enable(hasText and
378 self._FindServiceHasString() and
379 self.GetCtrl().GetSelection()[0] > 0)
380 return True
381 elif id == FindService.FindService.FIND_NEXT_ID:
382 hasText = self.GetCtrl().GetTextLength() > 0
383 event.Enable(hasText and
384 self._FindServiceHasString() and
385 self.GetCtrl().GetSelection()[0] < self.GetCtrl().GetLength())
386 return True
387 elif id == FindService.FindService.REPLACE_ID:
388 hasText = self.GetCtrl().GetTextLength() > 0
389 event.Enable(hasText)
390 return True
391 elif id == FindService.FindService.GOTO_LINE_ID:
392 event.Enable(True)
393 return True
394 elif id == TEXT_STATUS_BAR_ID:
395 self.OnUpdateStatusBar(event)
396 return True
397 else:
398 return wx.lib.docview.View.ProcessUpdateUIEvent(self, event)
399
400
401 def _GetParentFrame(self):
402 return wx.GetTopLevelParent(self.GetFrame())
403
404 def _GetActiveCtrl(self, parent):
405 """ Walk through the MultiSash windows and find the active Control """
406 if isinstance(parent, wx.lib.multisash.MultiClient) and parent.selected:
407 return parent.child
408 if hasattr(parent, "GetChildren"):
409 for child in parent.GetChildren():
410 found = self._GetActiveCtrl(child)
411 if found:
412 return found
413 return None
414
415
416 def _FindCtrl(self, parent):
417 """ Walk through the MultiSash windows and find the first TextCtrl """
418 if isinstance(parent, self.GetCtrlClass()):
419 return parent
420 if hasattr(parent, "GetChildren"):
421 for child in parent.GetChildren():
422 found = self._FindCtrl(child)
423 if found:
424 return found
425 return None
426
427
428 #----------------------------------------------------------------------------
429 # Methods for TextDocument to call
430 #----------------------------------------------------------------------------
431
432 def IsModified(self):
433 if not self.GetCtrl():
434 return False
435 return self.GetCtrl().GetModify()
436
437
438 def SetModifyFalse(self):
439 self.GetCtrl().SetSavePoint()
440
441
442 def GetValue(self):
443 if self.GetCtrl():
444 return self.GetCtrl().GetText()
445 else:
446 return None
447
448
449 def SetValue(self, value):
450 self.GetCtrl().SetText(value)
451 self.GetCtrl().UpdateLineNumberMarginWidth()
452 self.GetCtrl().EmptyUndoBuffer()
453
454
455 #----------------------------------------------------------------------------
456 # STC events
457 #----------------------------------------------------------------------------
458
459 def OnUpdateStatusBar(self, event):
460 statusBar = self._GetParentFrame().GetStatusBar()
461 statusBar.SetInsertMode(self.GetCtrl().GetOvertype() == 0)
462 statusBar.SetLineNumber(self.GetCtrl().GetCurrentLine() + 1)
463 statusBar.SetColumnNumber(self.GetCtrl().GetColumn(self.GetCtrl().GetCurrentPos()) + 1)
464
465
466 #----------------------------------------------------------------------------
467 # Format methods
468 #----------------------------------------------------------------------------
469
470 def OnChooseFont(self):
471 data = wx.FontData()
472 data.EnableEffects(True)
473 data.SetInitialFont(self.GetCtrl().GetFont())
474 data.SetColour(self.GetCtrl().GetFontColor())
475 fontDialog = wx.FontDialog(self.GetFrame(), data)
476 fontDialog.CenterOnParent()
477 if fontDialog.ShowModal() == wx.ID_OK:
478 data = fontDialog.GetFontData()
479 self.GetCtrl().SetFont(data.GetChosenFont())
480 self.GetCtrl().SetFontColor(data.GetColour())
481 self.GetCtrl().UpdateStyles()
482 fontDialog.Destroy()
483
484
485 #----------------------------------------------------------------------------
486 # Find methods
487 #----------------------------------------------------------------------------
488
489 def OnFind(self, replace = False):
490 findService = wx.GetApp().GetService(FindService.FindService)
491 if findService:
492 findService.ShowFindReplaceDialog(findString = self.GetCtrl().GetSelectedText(), replace = replace)
493
494
495 def DoFind(self, forceFindNext = False, forceFindPrevious = False, replace = False, replaceAll = False):
496 findService = wx.GetApp().GetService(FindService.FindService)
497 if not findService:
498 return
499 findString = findService.GetFindString()
500 if len(findString) == 0:
501 return -1
502 replaceString = findService.GetReplaceString()
503 flags = findService.GetFlags()
504 startLoc, endLoc = self.GetCtrl().GetSelection()
505
506 wholeWord = flags & wx.FR_WHOLEWORD > 0
507 matchCase = flags & wx.FR_MATCHCASE > 0
508 regExp = flags & FindService.FindService.FR_REGEXP > 0
509 down = flags & wx.FR_DOWN > 0
510 wrap = flags & FindService.FindService.FR_WRAP > 0
511
512 if forceFindPrevious: # this is from function keys, not dialog box
513 down = False
514 wrap = False # user would want to know they're at the end of file
515 elif forceFindNext:
516 down = True
517 wrap = False # user would want to know they're at the end of file
518
519 badSyntax = False
520
521 # On replace dialog operations, user is allowed to replace the currently highlighted text to determine if it should be replaced or not.
522 # Typically, it is the text from a previous find operation, but we must check to see if it isn't, user may have moved the cursor or selected some other text accidentally.
523 # If the text is a match, then replace it.
524 if replace:
525 result, start, end, replText = findService.DoFind(findString, replaceString, self.GetCtrl().GetSelectedText(), 0, 0, True, matchCase, wholeWord, regExp, replace)
526 if result > 0:
527 self.GetCtrl().ReplaceSelection(replText)
528 self.GetDocument().Modify(True)
529 wx.GetApp().GetTopWindow().PushStatusText(_("1 occurrence of \"%s\" replaced") % findString)
530 if down:
531 startLoc += len(replText) # advance start location past replacement string to new text
532 endLoc = startLoc
533 elif result == FindService.FIND_SYNTAXERROR:
534 badSyntax = True
535 wx.GetApp().GetTopWindow().PushStatusText(_("Invalid regular expression \"%s\"") % findString)
536
537 if not badSyntax:
538 text = self.GetCtrl().GetText()
539
540 # Find the next matching text occurance or if it is a ReplaceAll, replace all occurances
541 # Even if the user is Replacing, we should replace here, but only select the text and let the user replace it with the next Replace operation
542 result, start, end, text = findService.DoFind(findString, replaceString, text, startLoc, endLoc, down, matchCase, wholeWord, regExp, False, replaceAll, wrap)
543 if result > 0:
544 self.GetCtrl().SetTargetStart(0)
545 self.GetCtrl().SetTargetEnd(self.GetCtrl().GetLength())
546 self.GetCtrl().ReplaceTarget(text) # Doing a SetText causes a clear document to be shown when undoing, so using replacetarget instead
547 self.GetDocument().Modify(True)
548 if result == 1:
549 wx.GetApp().GetTopWindow().PushStatusText(_("1 occurrence of \"%s\" replaced") % findString)
550 else:
551 wx.GetApp().GetTopWindow().PushStatusText(_("%i occurrences of \"%s\" replaced") % (result, findString))
552 elif result == 0:
553 self.GetCtrl().SetSelection(start, end)
554 self.GetCtrl().EnsureVisible(self.GetCtrl().LineFromPosition(end)) # show bottom then scroll up to top
555 self.GetCtrl().EnsureVisible(self.GetCtrl().LineFromPosition(start)) # do this after ensuring bottom is visible
556 wx.GetApp().GetTopWindow().PushStatusText(_("Found \"%s\".") % findString)
557 elif result == FindService.FIND_SYNTAXERROR:
558 # Dialog for this case gets popped up by the FindService.
559 wx.GetApp().GetTopWindow().PushStatusText(_("Invalid regular expression \"%s\"") % findString)
560 else:
561 wx.MessageBox(_("Can't find \"%s\".") % findString, "Find",
562 wx.OK | wx.ICON_INFORMATION)
563
564
565 def _FindServiceHasString(self):
566 findService = wx.GetApp().GetService(FindService.FindService)
567 if not findService or not findService.GetFindString():
568 return False
569 return True
570
571
572 def OnGotoLine(self, event):
573 findService = wx.GetApp().GetService(FindService.FindService)
574 if findService:
575 line = findService.GetLineNumber(self.GetDocumentManager().FindSuitableParent())
576 if line > -1:
577 line = line - 1
578 self.GetCtrl().EnsureVisible(line)
579 self.GetCtrl().GotoLine(line)
580
581
582 def GotoLine(self, lineNum):
583 if lineNum > -1:
584 lineNum = lineNum - 1 # line numbering for editor is 0 based, we are 1 based.
585 self.GetCtrl().EnsureVisibleEnforcePolicy(lineNum)
586 self.GetCtrl().GotoLine(lineNum)
587
588
589 def SetSelection(self, start, end):
590 self.GetCtrl().SetSelection(start, end)
591
592
593 def EnsureVisible(self, line):
594 self.GetCtrl().EnsureVisible(line-1) # line numbering for editor is 0 based, we are 1 based.
595
596
597 def EnsureVisibleEnforcePolicy(self, line):
598 self.GetCtrl().EnsureVisibleEnforcePolicy(line-1) # line numbering for editor is 0 based, we are 1 based.
599
600
601 def LineFromPosition(self, pos):
602 return self.GetCtrl().LineFromPosition(pos)+1 # line numbering for editor is 0 based, we are 1 based.
603
604
605 def PositionFromLine(self, line):
606 return self.GetCtrl().PositionFromLine(line-1) # line numbering for editor is 0 based, we are 1 based.
607
608
609 def GetLineEndPosition(self, line):
610 return self.GetCtrl().GetLineEndPosition(line-1) # line numbering for editor is 0 based, we are 1 based.
611
612
613 def GetLine(self, lineNum):
614 return self.GetCtrl().GetLine(lineNum-1) # line numbering for editor is 0 based, we are 1 based.
615
616
617 def MarkerDefine(self):
618 """ This must be called after the texteditor is instantiated """
619 self.GetCtrl().MarkerDefine(TextView.MARKER_NUM, wx.stc.STC_MARK_CIRCLE, wx.BLACK, wx.BLUE)
620
621
622 def MarkerToggle(self, lineNum = -1, marker_index=MARKER_NUM, mask=MARKER_MASK):
623 if lineNum == -1:
624 lineNum = self.GetCtrl().GetCurrentLine()
625 if self.GetCtrl().MarkerGet(lineNum) & mask:
626 self.GetCtrl().MarkerDelete(lineNum, marker_index)
627 self._markerCount -= 1
628 else:
629 self.GetCtrl().MarkerAdd(lineNum, marker_index)
630 self._markerCount += 1
631
632
633 def MarkerAdd(self, lineNum = -1, marker_index=MARKER_NUM, mask=MARKER_MASK):
634 if lineNum == -1:
635 lineNum = self.GetCtrl().GetCurrentLine()
636 self.GetCtrl().MarkerAdd(lineNum, marker_index)
637 self._markerCount += 1
638
639
640 def MarkerDelete(self, lineNum = -1, marker_index=MARKER_NUM, mask=MARKER_MASK):
641 if lineNum == -1:
642 lineNum = self.GetCtrl().GetCurrentLine()
643 if self.GetCtrl().MarkerGet(lineNum) & mask:
644 self.GetCtrl().MarkerDelete(lineNum, marker_index)
645 self._markerCount -= 1
646
647 def MarkerDeleteAll(self, marker_num=MARKER_NUM):
648 self.GetCtrl().MarkerDeleteAll(marker_num)
649 if marker_num == self.MARKER_NUM:
650 self._markerCount = 0
651
652
653 def MarkerNext(self, lineNum = -1):
654 if lineNum == -1:
655 lineNum = self.GetCtrl().GetCurrentLine() + 1 # start search below current line
656 foundLine = self.GetCtrl().MarkerNext(lineNum, self.MARKER_MASK)
657 if foundLine == -1:
658 # wrap to top of file
659 foundLine = self.GetCtrl().MarkerNext(0, self.MARKER_MASK)
660 if foundLine == -1:
661 wx.GetApp().GetTopWindow().PushStatusText(_("No markers"))
662 return
663
664 self.GotoLine(foundLine + 1)
665
666
667 def MarkerPrevious(self, lineNum = -1):
668 if lineNum == -1:
669 lineNum = self.GetCtrl().GetCurrentLine() - 1 # start search above current line
670 if lineNum == -1:
671 lineNum = self.GetCtrl().GetLineCount()
672
673 foundLine = self.GetCtrl().MarkerPrevious(lineNum, self.MARKER_MASK)
674 if foundLine == -1:
675 # wrap to bottom of file
676 foundLine = self.GetCtrl().MarkerPrevious(self.GetCtrl().GetLineCount(), self.MARKER_MASK)
677 if foundLine == -1:
678 wx.GetApp().GetTopWindow().PushStatusText(_("No markers"))
679 return
680
681 self.GotoLine(foundLine + 1)
682
683
684 def MarkerExists(self, lineNum = -1, mask=MARKER_MASK):
685 if lineNum == -1:
686 lineNum = self.GetCtrl().GetCurrentLine()
687 if self.GetCtrl().MarkerGet(lineNum) & mask:
688 return True
689 else:
690 return False
691
692 def GetMarkerLines(self, mask=MARKER_MASK):
693 retval = []
694 for lineNum in range(self.GetCtrl().GetLineCount()):
695 if self.GetCtrl().MarkerGet(lineNum) & mask:
696 retval.append(lineNum)
697 return retval
698
699 def GetMarkerCount(self):
700 return self._markerCount
701
702
703 class TextService(wx.lib.pydocview.DocService):
704
705
706 def __init__(self):
707 wx.lib.pydocview.DocService.__init__(self)
708
709
710 def InstallControls(self, frame, menuBar = None, toolBar = None, statusBar = None, document = None):
711 if document and document.GetDocumentTemplate().GetDocumentType() != TextDocument:
712 return
713 if not document and wx.GetApp().GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
714 return
715
716 statusBar = TextStatusBar(frame, TEXT_STATUS_BAR_ID)
717 frame.SetStatusBar(statusBar)
718 wx.EVT_UPDATE_UI(frame, TEXT_STATUS_BAR_ID, frame.ProcessUpdateUIEvent)
719
720 viewMenu = menuBar.GetMenu(menuBar.FindMenu(_("&View")))
721
722 viewMenu.AppendSeparator()
723 textMenu = wx.Menu()
724 textMenu.AppendCheckItem(VIEW_WHITESPACE_ID, _("&Whitespace"), _("Shows or hides whitespace"))
725 wx.EVT_MENU(frame, VIEW_WHITESPACE_ID, frame.ProcessEvent)
726 wx.EVT_UPDATE_UI(frame, VIEW_WHITESPACE_ID, frame.ProcessUpdateUIEvent)
727 textMenu.AppendCheckItem(VIEW_EOL_ID, _("&End of Line Markers"), _("Shows or hides indicators at the end of each line"))
728 wx.EVT_MENU(frame, VIEW_EOL_ID, frame.ProcessEvent)
729 wx.EVT_UPDATE_UI(frame, VIEW_EOL_ID, frame.ProcessUpdateUIEvent)
730 textMenu.AppendCheckItem(VIEW_INDENTATION_GUIDES_ID, _("&Indentation Guides"), _("Shows or hides indentations"))
731 wx.EVT_MENU(frame, VIEW_INDENTATION_GUIDES_ID, frame.ProcessEvent)
732 wx.EVT_UPDATE_UI(frame, VIEW_INDENTATION_GUIDES_ID, frame.ProcessUpdateUIEvent)
733 textMenu.AppendCheckItem(VIEW_RIGHT_EDGE_ID, _("&Right Edge"), _("Shows or hides the right edge marker"))
734 wx.EVT_MENU(frame, VIEW_RIGHT_EDGE_ID, frame.ProcessEvent)
735 wx.EVT_UPDATE_UI(frame, VIEW_RIGHT_EDGE_ID, frame.ProcessUpdateUIEvent)
736 textMenu.AppendCheckItem(VIEW_LINE_NUMBERS_ID, _("&Line Numbers"), _("Shows or hides the line numbers"))
737 wx.EVT_MENU(frame, VIEW_LINE_NUMBERS_ID, frame.ProcessEvent)
738 wx.EVT_UPDATE_UI(frame, VIEW_LINE_NUMBERS_ID, frame.ProcessUpdateUIEvent)
739
740 viewMenu.AppendMenu(TEXT_ID, _("&Text"), textMenu)
741 wx.EVT_UPDATE_UI(frame, TEXT_ID, frame.ProcessUpdateUIEvent)
742
743 isWindows = (wx.Platform == '__WXMSW__')
744
745 zoomMenu = wx.Menu()
746 zoomMenu.Append(ZOOM_NORMAL_ID, _("Normal Size"), _("Sets the document to its normal size"))
747 wx.EVT_MENU(frame, ZOOM_NORMAL_ID, frame.ProcessEvent)
748 wx.EVT_UPDATE_UI(frame, ZOOM_NORMAL_ID, frame.ProcessUpdateUIEvent)
749 if isWindows:
750 zoomMenu.Append(ZOOM_IN_ID, _("Zoom In\tCtrl+Page Up"), _("Zooms the document to a larger size"))
751 else:
752 zoomMenu.Append(ZOOM_IN_ID, _("Zoom In"), _("Zooms the document to a larger size"))
753 wx.EVT_MENU(frame, ZOOM_IN_ID, frame.ProcessEvent)
754 wx.EVT_UPDATE_UI(frame, ZOOM_IN_ID, frame.ProcessUpdateUIEvent)
755 if isWindows:
756 zoomMenu.Append(ZOOM_OUT_ID, _("Zoom Out\tCtrl+Page Down"), _("Zooms the document to a smaller size"))
757 else:
758 zoomMenu.Append(ZOOM_OUT_ID, _("Zoom Out"), _("Zooms the document to a smaller size"))
759 wx.EVT_MENU(frame, ZOOM_OUT_ID, frame.ProcessEvent)
760 wx.EVT_UPDATE_UI(frame, ZOOM_OUT_ID, frame.ProcessUpdateUIEvent)
761
762 viewMenu.AppendMenu(ZOOM_ID, _("&Zoom"), zoomMenu)
763 wx.EVT_UPDATE_UI(frame, ZOOM_ID, frame.ProcessUpdateUIEvent)
764
765 formatMenuIndex = menuBar.FindMenu(_("&Format"))
766 if formatMenuIndex > -1:
767 formatMenu = menuBar.GetMenu(formatMenuIndex)
768 else:
769 formatMenu = wx.Menu()
770 if not menuBar.FindItemById(CHOOSE_FONT_ID):
771 formatMenu.Append(CHOOSE_FONT_ID, _("&Font..."), _("Sets the font to use"))
772 wx.EVT_MENU(frame, CHOOSE_FONT_ID, frame.ProcessEvent)
773 wx.EVT_UPDATE_UI(frame, CHOOSE_FONT_ID, frame.ProcessUpdateUIEvent)
774 if not menuBar.FindItemById(WORD_WRAP_ID):
775 formatMenu.AppendCheckItem(WORD_WRAP_ID, _("Word Wrap"), _("Wraps text horizontally when checked"))
776 wx.EVT_MENU(frame, WORD_WRAP_ID, frame.ProcessEvent)
777 wx.EVT_UPDATE_UI(frame, WORD_WRAP_ID, frame.ProcessUpdateUIEvent)
778 if formatMenuIndex == -1:
779 viewMenuIndex = menuBar.FindMenu(_("&View"))
780 menuBar.Insert(viewMenuIndex + 1, formatMenu, _("&Format"))
781
782 # wxBug: wxToolBar::GetToolPos doesn't exist, need it to find cut tool and then insert find in front of it.
783 toolBar.AddSeparator()
784 toolBar.AddTool(ZOOM_IN_ID, getZoomInBitmap(), shortHelpString = _("Zoom In"), longHelpString = _("Zooms the document to a larger size"))
785 toolBar.AddTool(ZOOM_OUT_ID, getZoomOutBitmap(), shortHelpString = _("Zoom Out"), longHelpString = _("Zooms the document to a smaller size"))
786 toolBar.Realize()
787
788
789 def ProcessUpdateUIEvent(self, event):
790 id = event.GetId()
791 if (id == TEXT_ID
792 or id == VIEW_WHITESPACE_ID
793 or id == VIEW_EOL_ID
794 or id == VIEW_INDENTATION_GUIDES_ID
795 or id == VIEW_RIGHT_EDGE_ID
796 or id == VIEW_LINE_NUMBERS_ID
797 or id == ZOOM_ID
798 or id == ZOOM_NORMAL_ID
799 or id == ZOOM_IN_ID
800 or id == ZOOM_OUT_ID
801 or id == CHOOSE_FONT_ID
802 or id == WORD_WRAP_ID):
803 event.Enable(False)
804 return True
805 else:
806 return False
807
808
809 class TextStatusBar(wx.StatusBar):
810
811 # wxBug: Would be nice to show num key status in statusbar, but can't figure out how to detect if it is enabled or disabled
812
813 def __init__(self, parent, id, style = wx.ST_SIZEGRIP, name = "statusBar"):
814 wx.StatusBar.__init__(self, parent, id, style, name)
815 self.SetFieldsCount(4)
816 self.SetStatusWidths([-1, 50, 50, 55])
817
818 def SetInsertMode(self, insert = True):
819 if insert:
820 newText = _("Ins")
821 else:
822 newText = _("")
823 if self.GetStatusText(1) != newText: # wxBug: Need to check if the text has changed, otherwise it flickers under win32
824 self.SetStatusText(newText, 1)
825
826 def SetLineNumber(self, lineNumber):
827 newText = _("Ln %i") % lineNumber
828 if self.GetStatusText(2) != newText:
829 self.SetStatusText(newText, 2)
830
831 def SetColumnNumber(self, colNumber):
832 newText = _("Col %i") % colNumber
833 if self.GetStatusText(3) != newText:
834 self.SetStatusText(newText, 3)
835
836
837 class TextOptionsPanel(wx.Panel):
838
839
840 def __init__(self, parent, id, configPrefix = "Text", label = "Text", hasWordWrap = True, hasTabs = False, addPage=True, hasFolding=False):
841 wx.Panel.__init__(self, parent, id)
842 self._configPrefix = configPrefix
843 self._hasWordWrap = hasWordWrap
844 self._hasTabs = hasTabs
845 self._hasFolding = hasFolding
846 SPACE = 10
847 HALF_SPACE = 5
848 config = wx.ConfigBase_Get()
849 self._textFont = wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL)
850 fontData = config.Read(self._configPrefix + "EditorFont", "")
851 if fontData:
852 nativeFont = wx.NativeFontInfo()
853 nativeFont.FromString(fontData)
854 self._textFont.SetNativeFontInfo(nativeFont)
855 self._originalTextFont = self._textFont
856 self._textColor = wx.BLACK
857 colorData = config.Read(self._configPrefix + "EditorColor", "")
858 if colorData:
859 red = int("0x" + colorData[0:2], 16)
860 green = int("0x" + colorData[2:4], 16)
861 blue = int("0x" + colorData[4:6], 16)
862 self._textColor = wx.Color(red, green, blue)
863 self._originalTextColor = self._textColor
864 fontLabel = wx.StaticText(self, -1, _("Font:"))
865 self._sampleTextCtrl = wx.TextCtrl(self, -1, "", size = (125, 21))
866 self._sampleTextCtrl.SetEditable(False)
867 chooseFontButton = wx.Button(self, -1, _("Choose Font..."))
868 wx.EVT_BUTTON(self, chooseFontButton.GetId(), self.OnChooseFont)
869 if self._hasWordWrap:
870 self._wordWrapCheckBox = wx.CheckBox(self, -1, _("Wrap words inside text area"))
871 self._wordWrapCheckBox.SetValue(wx.ConfigBase_Get().ReadInt(self._configPrefix + "EditorWordWrap", False))
872 self._viewWhitespaceCheckBox = wx.CheckBox(self, -1, _("Show whitespace"))
873 self._viewWhitespaceCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewWhitespace", False))
874 self._viewEOLCheckBox = wx.CheckBox(self, -1, _("Show end of line markers"))
875 self._viewEOLCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewEOL", False))
876 self._viewIndentationGuideCheckBox = wx.CheckBox(self, -1, _("Show indentation guides"))
877 self._viewIndentationGuideCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewIndentationGuides", False))
878 self._viewRightEdgeCheckBox = wx.CheckBox(self, -1, _("Show right edge"))
879 self._viewRightEdgeCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewRightEdge", False))
880 self._viewLineNumbersCheckBox = wx.CheckBox(self, -1, _("Show line numbers"))
881 self._viewLineNumbersCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewLineNumbers", True))
882 if self._hasFolding:
883 self._viewFoldingCheckBox = wx.CheckBox(self, -1, _("Show folding"))
884 self._viewFoldingCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewFolding", True))
885 if self._hasTabs:
886 self._hasTabsCheckBox = wx.CheckBox(self, -1, _("Use spaces instead of tabs"))
887 self._hasTabsCheckBox.SetValue(not wx.ConfigBase_Get().ReadInt(self._configPrefix + "EditorUseTabs", False))
888 indentWidthLabel = wx.StaticText(self, -1, _("Indent Width:"))
889 self._indentWidthChoice = wx.Choice(self, -1, choices = ["2", "4", "6", "8", "10"])
890 self._indentWidthChoice.SetStringSelection(str(config.ReadInt(self._configPrefix + "EditorIndentWidth", 4)))
891 textPanelBorderSizer = wx.BoxSizer(wx.VERTICAL)
892 textPanelSizer = wx.BoxSizer(wx.VERTICAL)
893 textFontSizer = wx.BoxSizer(wx.HORIZONTAL)
894 textFontSizer.Add(fontLabel, 0, wx.ALIGN_LEFT | wx.RIGHT | wx.TOP, HALF_SPACE)
895 textFontSizer.Add(self._sampleTextCtrl, 1, wx.ALIGN_LEFT | wx.EXPAND | wx.RIGHT, HALF_SPACE)
896 textFontSizer.Add(chooseFontButton, 0, wx.ALIGN_RIGHT | wx.LEFT, HALF_SPACE)
897 textPanelSizer.Add(textFontSizer, 0, wx.ALL|wx.EXPAND, HALF_SPACE)
898 if self._hasWordWrap:
899 textPanelSizer.Add(self._wordWrapCheckBox, 0, wx.ALL, HALF_SPACE)
900 textPanelSizer.Add(self._viewWhitespaceCheckBox, 0, wx.ALL, HALF_SPACE)
901 textPanelSizer.Add(self._viewEOLCheckBox, 0, wx.ALL, HALF_SPACE)
902 textPanelSizer.Add(self._viewIndentationGuideCheckBox, 0, wx.ALL, HALF_SPACE)
903 textPanelSizer.Add(self._viewRightEdgeCheckBox, 0, wx.ALL, HALF_SPACE)
904 textPanelSizer.Add(self._viewLineNumbersCheckBox, 0, wx.ALL, HALF_SPACE)
905 if self._hasFolding:
906 textPanelSizer.Add(self._viewFoldingCheckBox, 0, wx.ALL, HALF_SPACE)
907 if self._hasTabs:
908 textPanelSizer.Add(self._hasTabsCheckBox, 0, wx.ALL, HALF_SPACE)
909 textIndentWidthSizer = wx.BoxSizer(wx.HORIZONTAL)
910 textIndentWidthSizer.Add(indentWidthLabel, 0, wx.ALIGN_LEFT | wx.RIGHT | wx.TOP, HALF_SPACE)
911 textIndentWidthSizer.Add(self._indentWidthChoice, 0, wx.ALIGN_LEFT | wx.EXPAND, HALF_SPACE)
912 textPanelSizer.Add(textIndentWidthSizer, 0, wx.ALL, HALF_SPACE)
913 textPanelBorderSizer.Add(textPanelSizer, 0, wx.ALL|wx.EXPAND, SPACE)
914 ## styleButton = wx.Button(self, -1, _("Choose Style..."))
915 ## wx.EVT_BUTTON(self, styleButton.GetId(), self.OnChooseStyle)
916 ## textPanelBorderSizer.Add(styleButton, 0, wx.ALL, SPACE)
917 self.SetSizer(textPanelBorderSizer)
918 self.UpdateSampleFont()
919 if addPage:
920 parent.AddPage(self, _(label))
921
922 def UpdateSampleFont(self):
923 nativeFont = wx.NativeFontInfo()
924 nativeFont.FromString(self._textFont.GetNativeFontInfoDesc())
925 font = wx.NullFont
926 font.SetNativeFontInfo(nativeFont)
927 font.SetPointSize(self._sampleTextCtrl.GetFont().GetPointSize()) # Use the standard point size
928 self._sampleTextCtrl.SetFont(font)
929 self._sampleTextCtrl.SetForegroundColour(self._textColor)
930 self._sampleTextCtrl.SetValue(str(self._textFont.GetPointSize()) + _(" pt. ") + self._textFont.GetFaceName())
931 self._sampleTextCtrl.Refresh()
932 self.Layout()
933
934
935 ## def OnChooseStyle(self, event):
936 ## import STCStyleEditor
937 ## import os
938 ## base = os.path.split(__file__)[0]
939 ## config = os.path.abspath(os.path.join(base, 'stc-styles.rc.cfg'))
940 ##
941 ## dlg = STCStyleEditor.STCStyleEditDlg(None,
942 ## 'Python', 'python',
943 ## #'HTML', 'html',
944 ## #'XML', 'xml',
945 ## config)
946 ## dlg.CenterOnParent()
947 ## try:
948 ## dlg.ShowModal()
949 ## finally:
950 ## dlg.Destroy()
951
952
953 def OnChooseFont(self, event):
954 data = wx.FontData()
955 data.EnableEffects(True)
956 data.SetInitialFont(self._textFont)
957 data.SetColour(self._textColor)
958 fontDialog = wx.FontDialog(self, data)
959 fontDialog.CenterOnParent()
960 if fontDialog.ShowModal() == wx.ID_OK:
961 data = fontDialog.GetFontData()
962 self._textFont = data.GetChosenFont()
963 self._textColor = data.GetColour()
964 self.UpdateSampleFont()
965 fontDialog.Destroy()
966
967
968 def OnOK(self, optionsDialog):
969 config = wx.ConfigBase_Get()
970 doViewStuffUpdate = config.ReadInt(self._configPrefix + "EditorViewWhitespace", False) != self._viewWhitespaceCheckBox.GetValue()
971 config.WriteInt(self._configPrefix + "EditorViewWhitespace", self._viewWhitespaceCheckBox.GetValue())
972 doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorViewEOL", False) != self._viewEOLCheckBox.GetValue()
973 config.WriteInt(self._configPrefix + "EditorViewEOL", self._viewEOLCheckBox.GetValue())
974 doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorViewIndentationGuides", False) != self._viewIndentationGuideCheckBox.GetValue()
975 config.WriteInt(self._configPrefix + "EditorViewIndentationGuides", self._viewIndentationGuideCheckBox.GetValue())
976 doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorViewRightEdge", False) != self._viewRightEdgeCheckBox.GetValue()
977 config.WriteInt(self._configPrefix + "EditorViewRightEdge", self._viewRightEdgeCheckBox.GetValue())
978 doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorViewLineNumbers", True) != self._viewLineNumbersCheckBox.GetValue()
979 config.WriteInt(self._configPrefix + "EditorViewLineNumbers", self._viewLineNumbersCheckBox.GetValue())
980 if self._hasFolding:
981 doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorViewFolding", True) != self._viewFoldingCheckBox.GetValue()
982 config.WriteInt(self._configPrefix + "EditorViewFolding", self._viewFoldingCheckBox.GetValue())
983 if self._hasWordWrap:
984 doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorWordWrap", False) != self._wordWrapCheckBox.GetValue()
985 config.WriteInt(self._configPrefix + "EditorWordWrap", self._wordWrapCheckBox.GetValue())
986 if self._hasTabs:
987 doViewStuffUpdate = doViewStuffUpdate or not config.ReadInt(self._configPrefix + "EditorUseTabs", True) != self._hasTabsCheckBox.GetValue()
988 config.WriteInt(self._configPrefix + "EditorUseTabs", not self._hasTabsCheckBox.GetValue())
989 newIndentWidth = int(self._indentWidthChoice.GetStringSelection())
990 oldIndentWidth = config.ReadInt(self._configPrefix + "EditorIndentWidth", 4)
991 if newIndentWidth != oldIndentWidth:
992 doViewStuffUpdate = True
993 config.WriteInt(self._configPrefix + "EditorIndentWidth", newIndentWidth)
994 doFontUpdate = self._originalTextFont != self._textFont or self._originalTextColor != self._textColor
995 config.Write(self._configPrefix + "EditorFont", self._textFont.GetNativeFontInfoDesc())
996 config.Write(self._configPrefix + "EditorColor", "%02x%02x%02x" % (self._textColor.Red(), self._textColor.Green(), self._textColor.Blue()))
997 if doViewStuffUpdate or doFontUpdate:
998 for document in optionsDialog.GetDocManager().GetDocuments():
999 if issubclass(document.GetDocumentTemplate().GetDocumentType(), TextDocument):
1000 if doViewStuffUpdate:
1001 document.UpdateAllViews(hint = "ViewStuff")
1002 if doFontUpdate:
1003 document.UpdateAllViews(hint = "Font")
1004
1005
1006 def GetIcon(self):
1007 return getTextIcon()
1008
1009
1010 class TextCtrl(wx.stc.StyledTextCtrl):
1011
1012 def __init__(self, parent, id=-1, style=wx.NO_FULL_REPAINT_ON_RESIZE):
1013 wx.stc.StyledTextCtrl.__init__(self, parent, id, style=style)
1014
1015 if isinstance(parent, wx.gizmos.DynamicSashWindow):
1016 self._dynSash = parent
1017 self.SetupDSScrollBars()
1018 self.Bind(wx.gizmos.EVT_DYNAMIC_SASH_SPLIT, self.OnDSSplit)
1019 self.Bind(wx.gizmos.EVT_DYNAMIC_SASH_UNIFY, self.OnDSUnify)
1020
1021 self._font = None
1022 self._fontColor = None
1023
1024 self.SetVisiblePolicy(wx.stc.STC_VISIBLE_STRICT,1)
1025
1026 self.CmdKeyClear(wx.stc.STC_KEY_ADD, wx.stc.STC_SCMOD_CTRL)
1027 self.CmdKeyClear(wx.stc.STC_KEY_SUBTRACT, wx.stc.STC_SCMOD_CTRL)
1028 self.CmdKeyAssign(wx.stc.STC_KEY_PRIOR, wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMIN)
1029 self.CmdKeyAssign(wx.stc.STC_KEY_NEXT, wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMOUT)
1030 self.Bind(wx.stc.EVT_STC_ZOOM, self.OnUpdateLineNumberMarginWidth) # auto update line num width on zoom
1031 wx.EVT_KEY_DOWN(self, self.OnKeyPressed)
1032 wx.EVT_KILL_FOCUS(self, self.OnKillFocus)
1033 wx.EVT_SET_FOCUS(self, self.OnFocus)
1034 self.SetMargins(0,0)
1035
1036 self.SetUseTabs(0)
1037 self.SetTabWidth(4)
1038 self.SetIndent(4)
1039
1040 self.SetViewWhiteSpace(False)
1041 self.SetEOLMode(wx.stc.STC_EOL_LF)
1042 self.SetEdgeMode(wx.stc.STC_EDGE_NONE)
1043 self.SetEdgeColumn(78)
1044
1045 self.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER)
1046 self.SetMarginWidth(1, self.EstimatedLineNumberMarginWidth())
1047 self.UpdateStyles()
1048
1049 self.SetCaretForeground("BLACK")
1050
1051 self.SetViewDefaults()
1052 font, color = self.GetFontAndColorFromConfig()
1053 self.SetFont(font)
1054 self.SetFontColor(color)
1055 self.MarkerDefineDefault()
1056
1057 # for multisash initialization
1058 if isinstance(parent, wx.lib.multisash.MultiClient):
1059 while parent.GetParent():
1060 parent = parent.GetParent()
1061 if hasattr(parent, "GetView"):
1062 break
1063 if hasattr(parent, "GetView"):
1064 textEditor = parent.GetView()._textEditor
1065 if textEditor:
1066 doc = textEditor.GetDocPointer()
1067 if doc:
1068 self.SetDocPointer(doc)
1069
1070
1071 def OnFocus(self, event):
1072 # wxBug: On Mac, the STC control may fire a focus/kill focus event
1073 # on shutdown even if the control is in an invalid state. So check
1074 # before handling the event.
1075 if self.IsBeingDeleted():
1076 return
1077
1078 self.SetSelBackground(1, "BLUE")
1079 self.SetSelForeground(1, "WHITE")
1080 if hasattr(self, "_dynSash"):
1081 self._dynSash._view.SetCtrl(self)
1082 event.Skip()
1083
1084
1085 def OnKillFocus(self, event):
1086 # wxBug: On Mac, the STC control may fire a focus/kill focus event
1087 # on shutdown even if the control is in an invalid state. So check
1088 # before handling the event.
1089 if self.IsBeingDeleted():
1090 return
1091 self.SetSelBackground(0, "BLUE")
1092 self.SetSelForeground(0, "WHITE")
1093 self.SetSelBackground(1, "#C0C0C0")
1094 # Don't set foreground color, use syntax highlighted default colors.
1095 event.Skip()
1096
1097
1098 def SetViewDefaults(self, configPrefix="Text", hasWordWrap=True, hasTabs=False, hasFolding=False):
1099 config = wx.ConfigBase_Get()
1100 self.SetViewWhiteSpace(config.ReadInt(configPrefix + "EditorViewWhitespace", False))
1101 self.SetViewEOL(config.ReadInt(configPrefix + "EditorViewEOL", False))
1102 self.SetIndentationGuides(config.ReadInt(configPrefix + "EditorViewIndentationGuides", False))
1103 self.SetViewRightEdge(config.ReadInt(configPrefix + "EditorViewRightEdge", False))
1104 self.SetViewLineNumbers(config.ReadInt(configPrefix + "EditorViewLineNumbers", True))
1105 if hasFolding:
1106 self.SetViewFolding(config.ReadInt(configPrefix + "EditorViewFolding", True))
1107 if hasWordWrap:
1108 self.SetWordWrap(config.ReadInt(configPrefix + "EditorWordWrap", False))
1109 if hasTabs: # These methods do not exist in STCTextEditor and are meant for subclasses
1110 self.SetUseTabs(config.ReadInt(configPrefix + "EditorUseTabs", False))
1111 self.SetIndent(config.ReadInt(configPrefix + "EditorIndentWidth", 4))
1112 self.SetTabWidth(config.ReadInt(configPrefix + "EditorIndentWidth", 4))
1113 else:
1114 self.SetUseTabs(True)
1115 self.SetIndent(4)
1116 self.SetTabWidth(4)
1117
1118
1119 def GetDefaultFont(self):
1120 """ Subclasses should override this """
1121 return wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL)
1122
1123
1124 def GetDefaultColor(self):
1125 """ Subclasses should override this """
1126 return wx.BLACK
1127
1128
1129 def GetFontAndColorFromConfig(self, configPrefix = "Text"):
1130 font = self.GetDefaultFont()
1131 config = wx.ConfigBase_Get()
1132 fontData = config.Read(configPrefix + "EditorFont", "")
1133 if fontData:
1134 nativeFont = wx.NativeFontInfo()
1135 nativeFont.FromString(fontData)
1136 font.SetNativeFontInfo(nativeFont)
1137 color = self.GetDefaultColor()
1138 colorData = config.Read(configPrefix + "EditorColor", "")
1139 if colorData:
1140 red = int("0x" + colorData[0:2], 16)
1141 green = int("0x" + colorData[2:4], 16)
1142 blue = int("0x" + colorData[4:6], 16)
1143 color = wx.Color(red, green, blue)
1144 return font, color
1145
1146
1147 def GetFont(self):
1148 return self._font
1149
1150
1151 def SetFont(self, font):
1152 self._font = font
1153 self.StyleSetFont(wx.stc.STC_STYLE_DEFAULT, self._font)
1154
1155
1156 def GetFontColor(self):
1157 return self._fontColor
1158
1159
1160 def SetFontColor(self, fontColor = wx.BLACK):
1161 self._fontColor = fontColor
1162 self.StyleSetForeground(wx.stc.STC_STYLE_DEFAULT, "#%02x%02x%02x" % (self._fontColor.Red(), self._fontColor.Green(), self._fontColor.Blue()))
1163
1164
1165 def UpdateStyles(self):
1166 self.StyleClearAll()
1167 return
1168
1169
1170 def EstimatedLineNumberMarginWidth(self):
1171 MARGIN = 4
1172 baseNumbers = "000"
1173 lineNum = self.GetLineCount()
1174 lineNum = lineNum/100
1175 while lineNum >= 10:
1176 lineNum = lineNum/10
1177 baseNumbers = baseNumbers + "0"
1178
1179 return self.TextWidth(wx.stc.STC_STYLE_LINENUMBER, baseNumbers) + MARGIN
1180
1181
1182 def OnUpdateLineNumberMarginWidth(self, event):
1183 self.UpdateLineNumberMarginWidth()
1184
1185
1186 def UpdateLineNumberMarginWidth(self):
1187 if self.GetViewLineNumbers():
1188 self.SetMarginWidth(1, self.EstimatedLineNumberMarginWidth())
1189
1190 def MarkerDefineDefault(self):
1191 """ This must be called after the textcontrol is instantiated """
1192 self.MarkerDefine(TextView.MARKER_NUM, wx.stc.STC_MARK_ROUNDRECT, wx.BLACK, wx.BLUE)
1193
1194
1195 def OnClear(self):
1196 # Used when Delete key is hit.
1197 sel = self.GetSelection()
1198
1199 # Delete the selection or if no selection, the character after the caret.
1200 if sel[0] == sel[1]:
1201 self.SetSelection(sel[0], sel[0] + 1)
1202 else:
1203 # remove any folded lines also.
1204 startLine = self.LineFromPosition(sel[0])
1205 endLine = self.LineFromPosition(sel[1])
1206 endLineStart = self.PositionFromLine(endLine)
1207 if startLine != endLine and sel[1] - endLineStart == 0:
1208 while not self.GetLineVisible(endLine):
1209 endLine += 1
1210 self.SetSelectionEnd(self.PositionFromLine(endLine))
1211
1212 self.Clear()
1213
1214
1215 def OnPaste(self):
1216 # replace any folded lines also.
1217 sel = self.GetSelection()
1218 startLine = self.LineFromPosition(sel[0])
1219 endLine = self.LineFromPosition(sel[1])
1220 endLineStart = self.PositionFromLine(endLine)
1221 if startLine != endLine and sel[1] - endLineStart == 0:
1222 while not self.GetLineVisible(endLine):
1223 endLine += 1
1224 self.SetSelectionEnd(self.PositionFromLine(endLine))
1225
1226 self.Paste()
1227
1228
1229 def OnKeyPressed(self, event):
1230 key = event.GetKeyCode()
1231 if key == wx.WXK_NUMPAD_ADD: #wxBug: For whatever reason, the key accelerators for numpad add and subtract with modifiers are not working so have to trap them here
1232 if event.ControlDown():
1233 self.ToggleFoldAll(expand = True, topLevelOnly = True)
1234 elif event.ShiftDown():
1235 self.ToggleFoldAll(expand = True)
1236 else:
1237 self.ToggleFold(self.GetCurrentLine())
1238 elif key == wx.WXK_NUMPAD_SUBTRACT:
1239 if event.ControlDown():
1240 self.ToggleFoldAll(expand = False, topLevelOnly = True)
1241 elif event.ShiftDown():
1242 self.ToggleFoldAll(expand = False)
1243 else:
1244 self.ToggleFold(self.GetCurrentLine())
1245 else:
1246 event.Skip()
1247
1248
1249 #----------------------------------------------------------------------------
1250 # View Text methods
1251 #----------------------------------------------------------------------------
1252
1253 def GetViewRightEdge(self):
1254 return self.GetEdgeMode() != wx.stc.STC_EDGE_NONE
1255
1256
1257 def SetViewRightEdge(self, viewRightEdge):
1258 if viewRightEdge:
1259 self.SetEdgeMode(wx.stc.STC_EDGE_LINE)
1260 else:
1261 self.SetEdgeMode(wx.stc.STC_EDGE_NONE)
1262
1263
1264 def GetViewLineNumbers(self):
1265 return self.GetMarginWidth(1) > 0
1266
1267
1268 def SetViewLineNumbers(self, viewLineNumbers = True):
1269 if viewLineNumbers:
1270 self.SetMarginWidth(1, self.EstimatedLineNumberMarginWidth())
1271 else:
1272 self.SetMarginWidth(1, 0)
1273
1274
1275 def GetViewFolding(self):
1276 return self.GetMarginWidth(2) > 0
1277
1278
1279 def SetViewFolding(self, viewFolding = True):
1280 if viewFolding:
1281 self.SetMarginWidth(2, 12)
1282 else:
1283 self.SetMarginWidth(2, 0)
1284
1285
1286 def CanWordWrap(self):
1287 return True
1288
1289
1290 def GetWordWrap(self):
1291 return self.GetWrapMode() == wx.stc.STC_WRAP_WORD
1292
1293
1294 def SetWordWrap(self, wordWrap):
1295 if wordWrap:
1296 self.SetWrapMode(wx.stc.STC_WRAP_WORD)
1297 else:
1298 self.SetWrapMode(wx.stc.STC_WRAP_NONE)
1299
1300
1301 #----------------------------------------------------------------------------
1302 # DynamicSashWindow methods
1303 #----------------------------------------------------------------------------
1304
1305 def SetupDSScrollBars(self):
1306 # hook the scrollbars provided by the wxDynamicSashWindow
1307 # to this view
1308 v_bar = self._dynSash.GetVScrollBar(self)
1309 h_bar = self._dynSash.GetHScrollBar(self)
1310 v_bar.Bind(wx.EVT_SCROLL, self.OnDSSBScroll)
1311 h_bar.Bind(wx.EVT_SCROLL, self.OnDSSBScroll)
1312 v_bar.Bind(wx.EVT_SET_FOCUS, self.OnDSSBFocus)
1313 h_bar.Bind(wx.EVT_SET_FOCUS, self.OnDSSBFocus)
1314
1315 # And set the wxStyledText to use these scrollbars instead
1316 # of its built-in ones.
1317 self.SetVScrollBar(v_bar)
1318 self.SetHScrollBar(h_bar)
1319
1320
1321 def OnDSSplit(self, evt):
1322 newCtrl = self._dynSash._view.GetCtrlClass()(self._dynSash, -1, style=wx.NO_BORDER)
1323 newCtrl.SetDocPointer(self.GetDocPointer()) # use the same document
1324 self.SetupDSScrollBars()
1325 if self == self._dynSash._view.GetCtrl(): # originally had focus
1326 wx.CallAfter(self.SetFocus) # do this to set colors correctly. wxBug: for some reason, if we don't do a CallAfter, it immediately calls OnKillFocus right after our SetFocus.
1327
1328
1329 def OnDSUnify(self, evt):
1330 self.SetupDSScrollBars()
1331 self.SetFocus() # do this to set colors correctly
1332
1333
1334 def OnDSSBScroll(self, evt):
1335 # redirect the scroll events from the _dynSash's scrollbars to the STC
1336 self.GetEventHandler().ProcessEvent(evt)
1337
1338
1339 def OnDSSBFocus(self, evt):
1340 # when the scrollbar gets the focus move it back to the STC
1341 self.SetFocus()
1342
1343
1344 def DSProcessEvent(self, event):
1345 # wxHack: Needed for customized right mouse click menu items.
1346 if hasattr(self, "_dynSash"):
1347 if event.GetId() == wx.ID_SELECTALL:
1348 # force focus so that select all occurs in the window user right clicked on.
1349 self.SetFocus()
1350
1351 return self._dynSash._view.ProcessEvent(event)
1352 return False
1353
1354
1355 def DSProcessUpdateUIEvent(self, event):
1356 # wxHack: Needed for customized right mouse click menu items.
1357 if hasattr(self, "_dynSash"):
1358 id = event.GetId()
1359 if (id == wx.ID_SELECTALL # allow select all even in non-active window, then force focus to it, see above ProcessEvent
1360 or id == wx.ID_UNDO
1361 or id == wx.ID_REDO):
1362 pass # allow these actions even in non-active window
1363 else: # disallow events in non-active windows. Cut/Copy/Paste/Delete is too confusing user experience.
1364 if self._dynSash._view.GetCtrl() != self:
1365 event.Enable(False)
1366 return True
1367
1368 return self._dynSash._view.ProcessUpdateUIEvent(event)
1369 return False
1370
1371
1372 class TextPrintout(wx.lib.docview.DocPrintout):
1373 """ for Print Preview and Print """
1374
1375
1376 def OnPreparePrinting(self):
1377 """ initialization """
1378 dc = self.GetDC()
1379
1380 ppiScreenX, ppiScreenY = self.GetPPIScreen()
1381 ppiPrinterX, ppiPrinterY = self.GetPPIPrinter()
1382 scaleX = float(ppiPrinterX)/ppiScreenX
1383 scaleY = float(ppiPrinterY)/ppiScreenY
1384
1385 pageWidth, pageHeight = self.GetPageSizePixels()
1386 self._scaleFactorX = scaleX/pageWidth
1387 self._scaleFactorY = scaleY/pageHeight
1388
1389 w, h = dc.GetSize()
1390 overallScaleX = self._scaleFactorX * w
1391 overallScaleY = self._scaleFactorY * h
1392
1393 txtCtrl = self._printoutView.GetCtrl()
1394 font, color = txtCtrl.GetFontAndColorFromConfig()
1395
1396 self._margin = 40
1397 self._fontHeight = font.GetPointSize() + 1
1398 self._pageLines = int((h/overallScaleY - (2 * self._margin))/self._fontHeight)
1399 self._maxLines = txtCtrl.GetLineCount()
1400 self._numPages, remainder = divmod(self._maxLines, self._pageLines)
1401 if remainder != 0:
1402 self._numPages += 1
1403
1404 spaces = 1
1405 lineNum = self._maxLines
1406 while lineNum >= 10:
1407 lineNum = lineNum/10
1408 spaces += 1
1409 self._printFormat = "%%0%sd: %%s" % spaces
1410
1411
1412 def OnPrintPage(self, page):
1413 """ Prints the given page of the view """
1414 dc = self.GetDC()
1415
1416 txtCtrl = self._printoutView.GetCtrl()
1417 font, color = txtCtrl.GetFontAndColorFromConfig()
1418 dc.SetFont(font)
1419
1420 w, h = dc.GetSize()
1421 dc.SetUserScale(self._scaleFactorX * w, self._scaleFactorY * h)
1422
1423 dc.BeginDrawing()
1424
1425 dc.DrawText("%s - page %s" % (self.GetTitle(), page), self._margin, self._margin/2)
1426
1427 startY = self._margin
1428 startLine = (page - 1) * self._pageLines
1429 endLine = min((startLine + self._pageLines), self._maxLines)
1430 for i in range(startLine, endLine):
1431 text = txtCtrl.GetLine(i).rstrip()
1432 startY += self._fontHeight
1433 if txtCtrl.GetViewLineNumbers():
1434 dc.DrawText(self._printFormat % (i+1, text), self._margin, startY)
1435 else:
1436 dc.DrawText(text, self._margin, startY)
1437
1438 dc.EndDrawing()
1439
1440 return True
1441
1442
1443 def HasPage(self, pageNum):
1444 return pageNum <= self._numPages
1445
1446
1447 def GetPageInfo(self):
1448 minPage = 1
1449 maxPage = self._numPages
1450 selPageFrom = 1
1451 selPageTo = self._numPages
1452 return (minPage, maxPage, selPageFrom, selPageTo)
1453
1454
1455 #----------------------------------------------------------------------------
1456 # Icon Bitmaps - generated by encode_bitmaps.py
1457 #----------------------------------------------------------------------------
1458 from wx import ImageFromStream, BitmapFromImage
1459 import cStringIO
1460
1461
1462 def getTextData():
1463 return \
1464 "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
1465 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
1466 \x00\x015IDAT8\x8d\xad\x90\xb1N\xc2P\x14\x86\xbf\x02/\xe0\xec#\x18g\xc3\xe6T\
1467 \x13':1\x18H\x98\x14\x12\x17G\x177\x17\x9c4a\xc5\xc0d0\xc2\xccdLx\x02^@+\t\
1468 \xc1\x90\xf6r\xdb\xc6\x94\xe5:\\\xdbP)\xc5DOr\x92\x9b{\xff\xfb\xfd\xff9\xc6h\
1469 l+\xbek.\x02\x00\xec\x99\x03\x80\xeb\xf8\\\x9d\x1d\x1bd\xd5hl\xab\xd7O\x15\
1470 \xf7x\xa1\xfb\xeeq\xa4^>\x94\xba\xb8yRF.\xcf\xa6.D\xa0Nw\x18C\xad\xb2\x19\
1471 \x9f\x0f\xca\x165\xd1V\xed\xebZj\x92\xc2\\\x04\xec\x02\xd5\x8a\x89\xb7\xd4\
1472 \x97n\xa8\xe3?\x0f\x86\x08\x19dNP\x00\xf0\x96\xd0\x7f\xd0\t\x84\x0c(U-\x0eK&\
1473 \xd3P\x8bz\xcdV6 \x8a\xed\x86\x99f\xe9\x00{\xe6\xb0\x13\xc2\xa0\xd3\xd7\t\
1474 \x84\x9f\x10\xec\x9dTp\x1d\xb1=A\xa9j\x01\xc4\xb1\x01&\xfe\x9a~\x1d\xe0:Zu\
1475 \x7f\xdb\x05@J/!(\xd6\x1bL\xde\xec\xcd\x00!\x03\xa6!\x1c\x9dVR\x9d\xdf\xe5\
1476 \x96\x04\xd1au\xd3\xab3\xef\x9f_f\x03\xa2\xa5\x15\xeb\x8d\xc4\xc36\xe7\x18 \
1477 \xa5G\xaf\xd9J\xb8f\xcd\xfc\xb3\x0c#\x97\xff\xb58\xadr\x7f\xfa\xfd\x1f\x80/\
1478 \x04\x1f\x8fW\x0e^\xc3\x12\x00\x00\x00\x00IEND\xaeB`\x82"
1479
1480
1481 def getTextBitmap():
1482 return BitmapFromImage(getTextImage())
1483
1484 def getTextImage():
1485 stream = cStringIO.StringIO(getTextData())
1486 return ImageFromStream(stream)
1487
1488 def getTextIcon():
1489 return wx.IconFromBitmap(getTextBitmap())
1490
1491
1492 #----------------------------------------------------------------------------
1493 # Menu Bitmaps - generated by encode_bitmaps.py
1494 #----------------------------------------------------------------------------
1495 #----------------------------------------------------------------------
1496 def getZoomInData():
1497 return \
1498 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
1499 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
1500 \x00\x01TIDAT8\x8d\x8d\x93\xbbJ\x03A\x14\x86\xbf\xd9,\xc6\xd8E%`)VF[{\xc1v\
1501 \xf1\x82\x8f\xb0\xb94\xda\xa5\x13\x11\x8b`\xa9h\x10F\xe3#H.\xa6\x15\xccKhg\
1502 \x10\xc1B\x8bTF\x90\xc0X\x8c3\xbb\xd9\xcdF\x7f\x18\xf6\xec\x9cs\xbe\xfd\xe70\
1503 +\x84\x93"\xacb\xc1W\xe1\xf7\xeb\xfa\x8d`\x82\xdcXcI\x8e\x02AM\x02\t\xe1\xa4\
1504 (\x16|uz)y\x19\xc0\xc9\xdd;\x99\xee!\x00\xd9\xbd\x00\xd6\xaf\x95\xc7B\xac\
1505 \x03\xd3\x1c\xd6\xc2t\x10\xf7\x13\x8e\xe0\x14\x0b\xbe\xa2$m\xf3\xca\xea\xacM\
1506 \xe6\xd2\xc1\xcaWdl>#\x0e\x8c\xed\xe7n\x90|\xa8\x96m\xbc~ y\x04Z\xcd\x86\xda\
1507 \xda\xde\xb1Gq\x00\xb2S\t\xfeB\x9aK\xa8\xb1\x0e\xf2\x15I.\xad\x0bo\x8f\xf4\
1508 \x97\xab\xe7z\x88\x1f\xdf\xf0\xfa9\x1e\xe0x\x9eG\xbf\x16X\xcd\xb8Ar\xc6\xd5\
1509 \x0b4\xd4\xf3\xbcd\x07F_\xc3 \x1e\x0c\xa3Y\x08\x9f\x1f~\xefA\xab\xd9P\x9dN\
1510 \x07\x80\xddcI\xc6\x85\xf9\xb4.8\xabhwK\xbd+6\x16\xf5\xdeZ=%F\x00\xa0\xa7\
1511 \x0b`@F\xc6\xf6\xd3\xc5&@\x0c"\xa2\xff\x82\x01\x85-\xb7\x9a\re\x00QH\x0c0N\
1512 \x06\x1a\x85\xbcym}\x0f\xfe\x92\x19\xdc\xf2~\xdb\xee\xdd\xf7\xf4\xf3_\x0e\
1513 \xa2N\xc2\xfa\x01MYp\xbc\xe4a\x0f\xa9\x00\x00\x00\x00IEND\xaeB`\x82'
1514
1515 def getZoomInBitmap():
1516 return BitmapFromImage(getZoomInImage())
1517
1518 def getZoomInImage():
1519 stream = cStringIO.StringIO(getZoomInData())
1520 return ImageFromStream(stream)
1521
1522 #----------------------------------------------------------------------
1523 def getZoomOutData():
1524 return \
1525 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
1526 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
1527 \x00\x01RIDAT8\x8d\x8d\x93\xbbJ\x03A\x14\x86\xbf\xd9\x04\x93\x90J\x0cj#Dl\
1528 \xf4\x01\xec\x05\xdb\xc5\x0b>B\x92]\x1b+\xed,D\xb0\xb4\x08\x9afc|\x04\xc9\
1529 \x85\xb4>\x84\x95`\x93\x80`\x15\xd8*\x98\x84\xc0X\xcc\xce\xde7\xf8\xc30\x97=\
1530 \xf3\xcd\x7f\xce\xcc\na\xe4\x08\xabQ\xaf\xc9\xf0\xfc\xa5\xf3*X\xa1|b\xa3\xe5\
1531 D\x81 W\x81\x840r4\xea5\xf9\xf0\xe40Y@\xf3+\xf8\xb8\xbe\x16\x8c\xdd\x96\x9d\
1532 \n1\xf4\xc0\xdf\xdc\xb6\x01\xa8\xca\x19[\x05\xfc\x96%aY\x96\x0c\xdb\xae\xca\
1533 \x99\xea7\x8b\x91@w.\xf9x\xbcL\xb8\xf0k\xa0O\x1e{\xd31Q\x1d\xdd\xaaC\xfa\xbd\
1534 \xae<=;\xf7!F<\xd7,md\xc4\xf8\x0e\xf6\xaf\x1d\xb6\x8b*p\xa7\x0c\x95\xd0\x86\
1535 \xc9\x02\xbe\xa7\xe9\x00\xc34M\xdc\x96MA\xa8[,y\xc8r>h\x00ow6\xa6if;\x98K\
1536 \x95\xd6\xef\x12(\xc0t\x99~b8\x7f\xf0\xdeA\xbf\xd7\x95\xc3\xe1\x10\x80\x8b{\
1537 \x87R\x1e*\xde\xd55oTq\xf7Fm\x8ew\xd5\xdaa\'\'"\x00P\xd5\x05\xd0 -m\xfb\xf3\
1538 \xf9\x04 \x01\x11\xf1\x7fA\x83\xc2\x96\xfb\xbd\xae\xd4\x808$\x01H\x93\x86\
1539 \xc6!?\xe6 x\xca\xab\xa4\x0bwp5\xf0\xd7\xdeG\xaa\xff\x97\x83\xb8\x93\xb0\xfe\
1540 \x00\xc3\xa8ov\xfd\xe4\x9c\xa2\x00\x00\x00\x00IEND\xaeB`\x82'
1541
1542
1543 def getZoomOutBitmap():
1544 return BitmapFromImage(getZoomOutImage())
1545
1546 def getZoomOutImage():
1547 stream = cStringIO.StringIO(getZoomOutData())
1548 return ImageFromStream(stream)
1549
1550
1551