1
###############################################################################
3
# Purpose: StyledTextCtrl Markers #
4
# Author: Cody Precord <cprecord@editra.org> #
5
# Copyright: (c) 2011 Cody Precord <staff@editra.org> #
6
# License: wxWindows License #
7
###############################################################################
10
Classes to represent Markers and associated data in a StyledTextCtrl
14
__author__ = "Cody Precord <cprecord@editra.org>"
15
__svnid__ = "$Id: ed_marker.py 67626 2011-04-27 02:51:39Z CJP $"
16
__revision__ = "$Revision: 67626 $"
18
#-----------------------------------------------------------------------------#
21
from extern.embeddedimage import PyEmbeddedImage
23
# NOTE: Must be 1 char per pixel for Scintilla to display
24
_BookmarkBmp = PyEmbeddedImage(
25
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dE"
26
"AP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDAQA0GON3MFgAAAEG"
27
"SURBVDjL7ZK9SgNBFIW/nd1SO1EbBUHQgD+g+AKSN9E2nY+RztfxOSwCAUEIFlHUsLPB7L3H"
28
"YjdjTBqxFG91mLnzzTlzB/4rA+j2+vpJ893tTba8VszF/dU1uQRWg2cU7uAiyMFgfTig2+tr"
29
"GRLmIjeDmVGYKGojmBHMoXawmsnuHs8n5ytuE4AyEqoSjxGmEY8VXpUQI0wrqCLvW9uMD4+4"
30
"XICkCDZ6BAQmXI19JILUaBMB5y0PTDrHKU4C+OgB97bZmwuCOyaBQ46n/YOX1/SgCfAxHIAc"
31
"1LpzgQA5OWJmgMTp2sa3aXxFGD81Qu1BFzlqUzkIznY6K6NMgIvN/V/9gz9Qn2ObnTkNCjcr"
34
_ArrowBmp = PyEmbeddedImage(
35
"iVBORw0KGgoAAAANSUhEUgAAAA8AAAAQCAYAAADJViUEAAAAAXNSR0IArs4c6QAAAAZiS0dE"
36
"AP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDAQEBO+Lj6asAAADR"
37
"SURBVCjPpZItEgIxDIUfTA+B3CNEItsbrOAQDIojLA6J4hSI3KDBIeOwOygEzOwNFgP7A/2B"
38
"Ia5pvte+eQH+qEmoycytqgIAiAhlWQbnpillEYGqgpnbn+GcgGHmtmmaUXN49n4H59adnaEF"
39
"o6oQkeTrMQEzHIgXwXv9EDDvQ2kBwLk+kRF8P+ezPewFi9XT8/DidsnDy62FtRZE1MPHTfzL"
40
"szlwPQGV9ODIcyU2CFZWgiAAGCJCURQfUF3XXYQhMLvbLzgEfrWeMTALp0AAeAAUy3GCxymX"
41
"vQAAAABJRU5ErkJggg==")
43
_BreakpointBmp = PyEmbeddedImage(
44
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dE"
45
"AP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDEgMQBqh6qrUAAAEf"
46
"SURBVDjLpZPNTsJQEIW/CxgJUStWJTRqEBZEiZqY6AOY2FdiaVz2Adz6IiY+gHFHGn82yI9V"
47
"UjUWFkKh1lUx1VKvYZZzc76cOzMHpiwR1axWND+qb5iW+BNQrWj+qrLE/maZQnYFgNeew63V"
48
"oGY9/IKIn+Kj3UP0wlak3fvnFudXlyGICIl3DtDzxdg/t95szq6/IalAnF9U0bMa9PuxgPXM"
49
"PMcbZQDfMC2RCh6214q89Bypye+peS6ad4wdAKhzCgnXl9vdaMTCzGwYMHCHdPsjaUAwvDGg"
50
"030n4yWlAc5wEAbU7UeU9LKUvvPRJXKNpVxJCvBkNzmpNUTkIeWS8S4cr8epWRexp4yXnpAc"
51
"F+OmLf4RpgT4gPicGKap6ws0jWfqOADTLwAAAABJRU5ErkJggg==")
53
_BreakpointDisabledBmp = PyEmbeddedImage(
54
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dE"
55
"AP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDEgMRGEtuppcAAABy"
56
"SURBVDjLY2TAAcq1pf4j8zuvPmPEpo6RGM2EDMHQjM0AXOIkKcIrT5QNuNQRqxmbekYYg6gA"
57
"whLQTAwUgoE3gOJAJCsaG3Xl/5OdkOq1FYlIjbqqmElZQ+l/uabMfxIzExMDw38GBgbGfzgz"
58
"EyOl2RkAwXRPWcN07zMAAAAASUVORK5CYII=")
60
_StackMarker = PyEmbeddedImage(
61
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAd1J"
62
"REFUOI2Fk09rE1EUxX930jSZJIaBkGJcKBilC0uxG+kkuIhKKdn5EfoREvwO7jprV+LahSuL"
63
"CKEQqCO6cJNFQ1qEFBJJKYSaPx1Br4sx00xG64EH79377rnnHe4TMWLMw66LChKKqSquo+Hg"
64
"H8iMwK6JrtxNkMvluJ3eJF9chqFF99sxrX6T06MffNj9FSERMWJB1+qjp+RzK2ANaU8aAGST"
65
"eQrGOnv7bxh0vIgSw9cI+TvLfO6+5dXrF3QPz1hNPQbg/OKU9qRBdWOHVDKDXRMNEZTqhooI"
66
"o5M4g46HqtLqN+kenpFN5i9vWkNu3c8iEn6FMds0nn8X11FxHZVBx6PVb1Iw1um1xwC0Jw0K"
67
"y/ciJhqqihJSheuojE7iANxYTQckZvxalADxPVjE1BuHzr322Dd4AUvuru+qXRNNJTPhwqFF"
68
"7+s4UlSqG0FLmR8kuyYqIlQePuHm9SIAe19eBvnqxg5AMBuDjhcmmFey+cDmeHrAdPgzyJlW"
69
"jLXsNvsH75lcjHAdFYMFuI7KxBvx8ZPLWnYb07psUDTLfrE3CgYqoiBQUhdNJTJUylu0zt9R"
70
"NMu+7COPmW9XEszMMhNpKuWtkOz5O1cSzHsy9cZ//UyIEfvvKj1b0n/lfgPWHMMhVFXV8gAA"
73
_ErrorBmp = PyEmbeddedImage(
74
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAc5J"
75
"REFUOI11kzFP20AUx3/nEBGLRFUr5CEIieoGhkRtVJVI3uIROiBgYWLzxgco3SulysjIF8iC"
76
"UJaspjOtRIEODKZZihBClcABW0I5d2h8shP3P53e6f977929J4RRIK3PahQLIciTEcd8NAqZ"
77
"S5EGtNUorklJy3VzAccHB/z0/QxEA9Lm3ycnPPt+xjxvmpTX16cgxqR50O3mZr8LQ4a9Hk3b"
78
"piYlbTWKAYzJzEUpebm/T1FKbS5KidXvc1+tonyflutqiKGEoOW6DHs9nn2fhZUVAMzNTYpS"
79
"amASuwtDBt0uTdtGCcFMusTkod4sLlJyHEqOo6uIPI+HTmf6ZyYDS5UKD50Okedl4nnmXEDS"
80
"czo7wNL2tj4PggA1/qUMYN40Mz1HnqcredrZwarXGQQBszc32jMD8HRxAcCv01MWdne1OV12"
81
"yXGIVleZPTqirJSOiy8Q16Skadv4h4cAvFpb40+/D8DQMCgrhdza4sfYXFleJri85DiK/k1i"
82
"W43iD40GVr2uIYkSQKLE/DUM2TMKIjPK7+bmeLuxMQVJ9LrR4PzsjO+Pj+yNRzl3md5bFvfV"
83
"Ki+urzOAb7e3nF9d8UkY08uUhqj/rLOIY5050V9UfNMzpyji5gAAAABJRU5ErkJggg==")
85
_LintBmpGreen = PyEmbeddedImage(
86
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAZNJ"
87
"REFUOI3Fk00ow2Ecxz/P/ogtYxNRaDIvlykvO4yThHJzUBx3lLujg6O75OQkB4lSJKSUVsMO"
88
"qI1lW15aJv5/85KXbX8na48R5eBbz+H5Pd/ft2/f3+8RwqDwFxj+1P2TQMd8q94y1qgDdM+5"
89
"9F8JOGeaJGKBw5SufYhlIudzoTjfhHPSoSev3jAm8njKecWWW0m/vZfVuw18BCS++CrED7tu"
90
"+yAAi8draIpKf0kfs3dLAOwM7AtJoHvOpd/4VQzPOpZmKz3l7QBEosG0sFcNk7x6wzceEFkZ"
91
"rA95RIHDhKXZits+SCQaxHvpJ5ZKYKuoo6OuCwClJk9yK4X4svtAcdLCxXWYWCoBQGeZi0g0"
92
"iKbGuT3SuPWq1A5XpcOUQkzlCzRFTd+d1no8IS9ms2DxZgVLoZG9iWOR2SM58I0HhPb8yHx4"
93
"k84yF4dnpziqa4nHdULbFwgla2jZe7DrPhAYBVsxD2azYHp5AX/ohNOpcwHQNtog7cKXY8wk"
94
"qvdPFJWapOQlCIPy47GP2PRv3//9N74DHQaLgsqg1M8AAAAASUVORK5CYII=")
96
_LintBmpRed = PyEmbeddedImage(
97
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAXJJ"
98
"REFUOI3Fk79Lw0AYhp9LhA4tFIyQQSg2oq2zRTPYrtLJjpLRVf8AxVnwD9C1o4OTBcVdC42i"
99
"jtpWjCIVGq1xsYiEek4NptQf0MEPDj7uvve9l+c4IRSVQUoZSP2bQbmwILdnZ2S3/5PBQS4b"
100
"DLZcl1FFYcVI9hUDDPVuxIeHKWam5ZuqMqLrACzqOgnLothoyKWzc/F1XvSD2I2bsCwA7nd2"
101
"ANBMk6ejI7yXFwoVW4QMyoUFeVirAZBPpdBMk/fHR14dh5hh8Oo4tFyXh48Plk9OgxQBg7m9"
102
"kphPJsmnUiQsKxB3SzNNAMYikVDaEMTdahUAz7YDsWaaQe/5PsfNJsXMdAA1BDHe4x4zDJ5t"
103
"G4BaqcRNu81m/ToEMZRg46oq9i8vuatUgptjhkHLdfF8n06nQ2/1fYWDXFb6vs+IrlNvNLjw"
104
"PLacW7E6OSFVVWXjqip+NABYn0pLgPFolJt2OyQKR1DUX9daOi2/Pf/33/gJL9aOTtHLtUIA"
107
_LintBmpYellow = PyEmbeddedImage(
108
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAblJ"
109
"REFUOI3FkzFIG2EUx39frmCStgpqIw0pJKGEpErViEIHoYtQcOjSTkJ1ky7irLM6ScVFbBeL"
110
"FBxEBAUHl6IirVMKFdseXE5yjSVGCzW53ImXr0Mh9DRiwaEPvuG9773/e/y+9wnhUbiOea5V"
111
"fZXA7FibHB6ISoD5yQ75TwLPntytJOpGEZ9PYag/Ik3LqdrkxvnA054gj5INMpM1CYduUiie"
112
"8eB+LV3dfYwYphyf+Sb+zhfVIM5PdkjTcnjc8wKAnc13AMQTrWxs7ZD/aTMxowqXwOxYm9xT"
113
"f1GWks6H9cQTrZxax2jpDIHGGgDefzikVHKYmtMqU1QYDI6mxL2gn+ZYHV3dfRwffkFLZwC4"
114
"dTtA/Z04AMaP0uUQ978X8XsV8sYGumFiWg6xeAuf93TK0kHVCyBg5GWsAtoF0SMEuSObaOSP"
115
"Hw75SaU+4fcqLK9uEwx4mX6bFnBQfYKpOU181U5YXd8l2Z4kl7dpSYTJHdmoegHLLl8AfmEP"
116
"Xi/sCzVdYGllk0BjDa/efCSTNVlcOxAAQ/0R10JVfUaA4YGoLEtJNmcRavK5yLtMeJQrz/Pe"
117
"kLz0/r//xt8H26DcJVZnmgAAAABJRU5ErkJggg==")
119
#-----------------------------------------------------------------------------#
123
"""Get a new marker id
124
@note: limited by stc to 16 possible ids. will assert when this threshold
130
assert __markerId < 24, "No more marker Ids available!"
133
#-----------------------------------------------------------------------------#
135
class Marker(object):
136
"""Marker Base class"""
140
super(Marker, self).__init__()
145
self._bmp = wx.NullBitmap
146
self._fore = wx.NullColour # Foreground colour
147
self._back = wx.NullColour # Background colour
149
Line = property(lambda self: self._line,
150
lambda self, line: setattr(self, '_line', line))
151
Handle = property(lambda self: self._handle,
152
lambda self, handle: setattr(self, '_handle', handle))
153
Bitmap = property(lambda self: self._bmp,
154
lambda self, bmp: setattr(self, '_bmp', bmp))
155
Foreground = property(lambda self: self._fore,
156
lambda self, fore: setattr(self, '_fore', fore))
157
Background = property(lambda self: self._back,
158
lambda self, back: setattr(self, '_back', back))
161
def AnySet(cls, stc, line):
162
"""Is any breakpoint set on the line"""
163
if not cls.IsSet(stc, line):
165
for bpoint in cls.__subclasses__():
166
if bpoint.IsSet(stc, line):
174
"""Get the list of marker IDs."""
179
"""Get the list of symbols"""
183
def IsSet(cls, stc, line):
184
"""Is the marker set on the given line"""
185
mask = stc.MarkerGet(line)
186
return True in [ bool(1<<marker & mask) for marker in cls.GetIds() ]
188
def Set(self, stc, line, delete=False):
189
"""Add/Delete the marker to the stc at the given line"""
190
for marker in self.GetIds():
192
mask = stc.MarkerGet(line)
193
if (1<<marker & mask):
194
stc.MarkerDelete(line, marker)
196
handle = stc.MarkerAdd(line, marker)
201
def DeleteAll(self, stc):
202
"""Remove all instances of this bookmark from the stc"""
203
for marker in self.GetIds():
204
stc.MarkerDeleteAll(marker)
206
def RegisterWithStc(self, stc):
207
"""Setup the STC to use this marker"""
209
if self.Bitmap.IsNull():
210
symbols = self.GetSymbols()
211
if len(ids) == len(symbols):
212
markers = zip(ids, symbols)
213
for marker, symbol in markers:
214
stc.MarkerDefine(marker, symbol,
215
self.Foreground, self.Background)
216
elif len(ids) == 1 and not self.Bitmap.IsNull():
217
stc.MarkerDefineBitmap(ids[0], self.Bitmap)
219
assert False, "Invalid Marker!"
221
#-----------------------------------------------------------------------------#
223
class Bookmark(Marker):
224
"""Class to store bookmark data"""
225
_ids = [NewMarkerId(),]
227
super(Bookmark, self).__init__()
230
self._name = u"" # Bookmark alias name
231
self._fname = u"" # Filename
232
self.Bitmap = _BookmarkBmp.Bitmap
234
def __eq__(self, other):
235
return (self.Filename, self.Line) == (other.Filename, other.Line)
237
#---- Properties ----#
238
Name = property(lambda self: self._name,
239
lambda self, name: setattr(self, '_name', name))
240
Filename = property(lambda self: self._fname,
241
lambda self, name: setattr(self, '_fname', name))
243
#-----------------------------------------------------------------------------#
245
class Breakpoint(Marker):
246
"""Marker object to represent a breakpoint in the EditraBaseStc"""
247
_ids = [NewMarkerId(),]
249
super(Breakpoint, self).__init__()
250
self.Bitmap = _BreakpointBmp.Bitmap
252
class BreakpointDisabled(Breakpoint):
253
"""Marker object to represent a disabled breakpoint in the EditraBaseStc"""
254
_ids = [NewMarkerId(),]
256
super(BreakpointDisabled, self).__init__()
257
self.Bitmap = _BreakpointDisabledBmp.Bitmap
259
class BreakpointStep(Breakpoint):
260
"""Marker object to represent debugger step breakpoint in the EditraBaseStc"""
261
_ids = [NewMarkerId(), NewMarkerId()]
263
super(BreakpointStep, self).__init__()
264
self.Bitmap = _ArrowBmp.Bitmap
266
def DeleteAll(self, stc):
267
"""Overrode to handle refresh issue"""
268
super(BreakpointStep, self).DeleteAll(stc)
269
stc.Colourise(0, stc.GetLength())
271
def RegisterWithStc(self, stc):
272
"""Register this compound marker with the given StyledTextCtrl"""
274
stc.MarkerDefineBitmap(ids[0], self.Bitmap)
275
stc.MarkerDefine(ids[1], wx.stc.STC_MARK_BACKGROUND,
276
background=self.Background)
278
def Set(self, stc, line, delete=False):
279
"""Add/Delete the marker to the stc at the given line
280
@note: overrode to ensure only one is set in a buffer at a time
284
super(BreakpointStep, self).Set(stc, line, delete)
285
start = stc.GetLineEndPosition(max(line-1, 0))
286
end = stc.GetLineEndPosition(line)
289
stc.Colourise(start, end) # Refresh for background marker
291
class StackMarker(Marker):
292
"""Marker object to mark a line in a callstack in the EditraBaseStc"""
293
_ids = [NewMarkerId(),]
295
super(StackMarker, self).__init__()
296
self.Bitmap = _StackMarker.Bitmap
298
#-----------------------------------------------------------------------------#
300
class FoldMarker(Marker):
301
"""Marker object class for managing the code folding markers"""
302
_ids = [wx.stc.STC_MARKNUM_FOLDEROPEN, wx.stc.STC_MARKNUM_FOLDER,
303
wx.stc.STC_MARKNUM_FOLDERSUB, wx.stc.STC_MARKNUM_FOLDERTAIL,
304
wx.stc.STC_MARKNUM_FOLDEREND, wx.stc.STC_MARKNUM_FOLDEROPENMID,
305
wx.stc.STC_MARKNUM_FOLDERMIDTAIL]
306
_symbols = [wx.stc.STC_MARK_BOXMINUS, wx.stc.STC_MARK_BOXPLUS,
307
wx.stc.STC_MARK_VLINE, wx.stc.STC_MARK_LCORNER,
308
wx.stc.STC_MARK_BOXPLUSCONNECTED,
309
wx.stc.STC_MARK_BOXMINUSCONNECTED, wx.stc.STC_MARK_TCORNER]
311
def RegisterWithStc(self, stc):
312
super(FoldMarker, self).RegisterWithStc(stc)
313
stc.SetFoldMarginHiColour(True, self.Foreground)
314
stc.SetFoldMarginColour(True, self.Foreground)
316
#-----------------------------------------------------------------------------#
318
class ErrorMarker(Marker):
319
"""Marker object to indicate an error line in the EditraBaseStc"""
320
_ids = [NewMarkerId(), NewMarkerId()]
322
super(ErrorMarker, self).__init__()
323
self.Bitmap = _ErrorBmp.Bitmap
325
def DeleteAll(self, stc):
326
"""Overrode to handle refresh issue"""
327
super(ErrorMarker, self).DeleteAll(stc)
328
stc.Colourise(0, stc.GetLength())
330
def RegisterWithStc(self, stc):
331
"""Register this compound marker with the given StyledTextCtrl"""
333
stc.MarkerDefineBitmap(ids[0], self.Bitmap)
334
stc.MarkerDefine(ids[1], wx.stc.STC_MARK_BACKGROUND,
335
# foreground=self.Foreground, #TODO
336
background=self.Foreground)
338
def Set(self, stc, line, delete=False):
339
"""Add/Delete the marker to the stc at the given line
340
@note: overrode to ensure only one is set in a buffer at a time
343
super(ErrorMarker, self).Set(stc, line, delete)
344
start = stc.GetLineEndPosition(max(line-1, 0))
345
end = stc.GetLineEndPosition(line)
348
stc.Colourise(start, end) # Refresh for background marker
350
#-----------------------------------------------------------------------------#
352
class LintMarker(Marker):
353
"""Marker object to represent a marker for coding issue in the EditraBaseStc"""
354
_ids = [NewMarkerId(),]
356
super(LintMarker, self).__init__()
357
self.Bitmap = _LintBmpGreen.Bitmap
359
class LintMarkerWarning(Marker):
360
"""Marker object to represent a marker for moderate severity
361
coding issue in the EditraBaseStc
364
_ids = [NewMarkerId(),]
366
super(LintMarkerWarning, self).__init__()
367
self.Bitmap = _LintBmpYellow.Bitmap
369
class LintMarkerError(Marker):
370
"""Marker object to represent a marker for a high severity
371
coding issue in the EditraBaseStc
374
_ids = [NewMarkerId(),]
376
super(LintMarkerError, self).__init__()
377
self.Bitmap = _LintBmpRed.Bitmap