QT-PyQt-PySide-Custom-Widgets-Pro 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- custom_widgets_pro/__init__.py +73 -0
- custom_widgets_pro/_catalog.py +25 -0
- custom_widgets_pro/_cli.py +132 -0
- custom_widgets_pro/_license.py +419 -0
- custom_widgets_pro/_version.py +14 -0
- custom_widgets_pro/datatable/__init__.py +17 -0
- custom_widgets_pro/datatable/datatable_pro.py +319 -0
- custom_widgets_pro/datatable/export.py +143 -0
- custom_widgets_pro/datatable/frozen_view.py +112 -0
- custom_widgets_pro/datatable/grouping.py +309 -0
- custom_widgets_pro/datatable/pivot.py +100 -0
- custom_widgets_pro/datatable/provider.py +98 -0
- custom_widgets_pro/datatable/virtual_model.py +451 -0
- custom_widgets_pro/widgets/__init__.py +7 -0
- custom_widgets_pro/widgets/charts/QCustomBeeswarm.py +317 -0
- custom_widgets_pro/widgets/charts/QCustomBubbleChart.py +655 -0
- custom_widgets_pro/widgets/charts/QCustomCandlestickChart.py +522 -0
- custom_widgets_pro/widgets/charts/QCustomDivergingBarChart.py +430 -0
- custom_widgets_pro/widgets/charts/QCustomDotMatrix.py +266 -0
- custom_widgets_pro/widgets/charts/QCustomFunnelChart.py +474 -0
- custom_widgets_pro/widgets/charts/QCustomGanttChart.py +376 -0
- custom_widgets_pro/widgets/charts/QCustomHeatmap.py +555 -0
- custom_widgets_pro/widgets/charts/QCustomRadarChart.py +600 -0
- custom_widgets_pro/widgets/charts/QCustomRadialBars.py +441 -0
- custom_widgets_pro/widgets/charts/QCustomRadialLines.py +554 -0
- custom_widgets_pro/widgets/charts/QCustomRangeBarChart.py +504 -0
- custom_widgets_pro/widgets/charts/QCustomSankey.py +539 -0
- custom_widgets_pro/widgets/charts/QCustomScatterChart.py +623 -0
- custom_widgets_pro/widgets/charts/__init__.py +1 -0
- custom_widgets_pro/widgets/data/QCustomCodeEditor.py +391 -0
- custom_widgets_pro/widgets/data/QCustomNodeGraph.py +1030 -0
- custom_widgets_pro/widgets/data/QCustomRichTextEditor.py +189 -0
- custom_widgets_pro/widgets/data/QCustomTableToolbar.py +566 -0
- custom_widgets_pro/widgets/data/__init__.py +1 -0
- custom_widgets_pro/widgets/media/QCustomImageViewer.py +300 -0
- custom_widgets_pro/widgets/media/QCustomMediaGrid.py +197 -0
- custom_widgets_pro/widgets/media/QCustomMediaTimeline.py +607 -0
- custom_widgets_pro/widgets/media/QCustomVideoPlayer.py +326 -0
- custom_widgets_pro/widgets/media/__init__.py +1 -0
- qt_pyqt_pyside_custom_widgets_pro-1.1.0.dist-info/METADATA +112 -0
- qt_pyqt_pyside_custom_widgets_pro-1.1.0.dist-info/RECORD +45 -0
- qt_pyqt_pyside_custom_widgets_pro-1.1.0.dist-info/WHEEL +5 -0
- qt_pyqt_pyside_custom_widgets_pro-1.1.0.dist-info/entry_points.txt +2 -0
- qt_pyqt_pyside_custom_widgets_pro-1.1.0.dist-info/licenses/LICENSE +91 -0
- qt_pyqt_pyside_custom_widgets_pro-1.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
# qtpy Custom Widgets #
|
|
2
|
+
# GPL 3.0 - Kadir Aksoy #
|
|
3
|
+
# https://github.com/kadir014/pyqt5-custom-widgets #
|
|
4
|
+
# DISCLAIMER: This class uses the JSON files in the #
|
|
5
|
+
# syntax and themes folders which has #
|
|
6
|
+
# pre-defined syntax rules and themes. #
|
|
7
|
+
# Don't forget to include them in your #
|
|
8
|
+
# package's folder if you're installing #
|
|
9
|
+
# this project manually.
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import pathlib
|
|
13
|
+
|
|
14
|
+
from qtpy.QtCore import QRegularExpression, Qt, Property
|
|
15
|
+
from qtpy.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QLabel, QPlainTextEdit
|
|
16
|
+
from qtpy.QtGui import QColor, QTextCharFormat, QFont, QSyntaxHighlighter, QPainter, QPen, QBrush
|
|
17
|
+
from Custom_Widgets._resources import packageDir
|
|
18
|
+
|
|
19
|
+
class QCustomCodeEditor(QWidget):
|
|
20
|
+
# Qt Designer contract. WIDGET_MODULE is the FLAT public path --
|
|
21
|
+
# Custom_Widgets.QCustomCodeEditor is what .ui files carry in <header>, not the
|
|
22
|
+
# subpackage this file now lives in.
|
|
23
|
+
__catalog__ = {
|
|
24
|
+
"name": "QCustomCodeEditor",
|
|
25
|
+
"props": {
|
|
26
|
+
"lang": {},
|
|
27
|
+
"theme": {},
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
WIDGET_MODULE = "Custom_Widgets.QCustomCodeEditor"
|
|
31
|
+
WIDGET_TOOLTIP = "A syntax-highlighted code editor"
|
|
32
|
+
WIDGET_DOM_XML = """
|
|
33
|
+
<ui language='c++'>
|
|
34
|
+
<widget class='QCustomCodeEditor' name='qCustomCodeEditor'>
|
|
35
|
+
<property name='geometry'><rect><x>0</x><y>0</y><width>420</width><height>300</height></rect></property>
|
|
36
|
+
</widget>
|
|
37
|
+
</ui>
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
LANG_DISPLAY = {
|
|
41
|
+
"plain" : "Plain text",
|
|
42
|
+
"python" : "Python",
|
|
43
|
+
"py" : "Python",
|
|
44
|
+
"cpp" : "C++",
|
|
45
|
+
"c++" : "C++",
|
|
46
|
+
"js" : "JavaScript",
|
|
47
|
+
"jsx" : "JavaScript",
|
|
48
|
+
"javascript" : "JavaScript",
|
|
49
|
+
"ts" : "TypeScript",
|
|
50
|
+
"tsx" : "TypeScript",
|
|
51
|
+
"typescript" : "TypeScript"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# Rich editors for the Designer "Custom Properties" dock (see
|
|
55
|
+
# DesignerTools.CustomPropertiesDock).
|
|
56
|
+
DESIGNER_CUSTOM_PROPS = [
|
|
57
|
+
{"name": "lang", "kind": "str", "group": "General"},
|
|
58
|
+
{"name": "theme", "kind": "str", "group": "General"},
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
# -- designer-facing properties (editable in the Custom Properties dock) --
|
|
62
|
+
@Property(str)
|
|
63
|
+
def lang(self):
|
|
64
|
+
return getattr(self, "_lang", "python")
|
|
65
|
+
|
|
66
|
+
@lang.setter
|
|
67
|
+
def lang(self, value):
|
|
68
|
+
self._lang = str(value)
|
|
69
|
+
if value in QCustomCodeEditor.LANG_DISPLAY:
|
|
70
|
+
self.setLang(value)
|
|
71
|
+
|
|
72
|
+
@Property(str)
|
|
73
|
+
def theme(self):
|
|
74
|
+
return getattr(self, "_theme", "default")
|
|
75
|
+
|
|
76
|
+
@theme.setter
|
|
77
|
+
def theme(self, value):
|
|
78
|
+
self._theme = str(value)
|
|
79
|
+
try:
|
|
80
|
+
self.setTheme(value)
|
|
81
|
+
except Exception:
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
def __init__(self, parent=None):
|
|
85
|
+
super().__init__(parent)
|
|
86
|
+
|
|
87
|
+
self.layout = QHBoxLayout()
|
|
88
|
+
self.layout.setContentsMargins(0, 0, 0, 0)
|
|
89
|
+
self.setLayout(self.layout)
|
|
90
|
+
|
|
91
|
+
self.layout.addSpacing(37)
|
|
92
|
+
|
|
93
|
+
self.editorlyt = QVBoxLayout()
|
|
94
|
+
self.editorlyt.setSpacing(0)
|
|
95
|
+
self.editorlyt.setContentsMargins(0, 0, 0, 0)
|
|
96
|
+
self.layout.addLayout(self.editorlyt)
|
|
97
|
+
|
|
98
|
+
self.editor = QPlainTextEdit()
|
|
99
|
+
self.editor.setLineWrapMode(QPlainTextEdit.NoWrap)
|
|
100
|
+
self.editorlyt.addWidget(self.editor)
|
|
101
|
+
|
|
102
|
+
self.setStyleSheet("QPlainTextEdit {font-family:Consolas; font-size:14px; color:#222222;}")
|
|
103
|
+
|
|
104
|
+
self.highlighter = QCustomSyntaxHighlighter(self.editor.document())
|
|
105
|
+
|
|
106
|
+
self.sliderVal = 0
|
|
107
|
+
self.lastdigit = 2
|
|
108
|
+
vs = self.editor.verticalScrollBar()
|
|
109
|
+
|
|
110
|
+
@vs.rangeChanged.connect
|
|
111
|
+
def slot(v):
|
|
112
|
+
self.sliderVal = self.editor.verticalScrollBar().value()
|
|
113
|
+
|
|
114
|
+
if len(str(vs.maximum()+15)) > self.lastdigit:
|
|
115
|
+
self.lastdigit = len(str(vs.maximum()+15))
|
|
116
|
+
self.layout.insertSpacing(0, 10)
|
|
117
|
+
|
|
118
|
+
self.update()
|
|
119
|
+
|
|
120
|
+
@vs.valueChanged.connect
|
|
121
|
+
def slot(v):
|
|
122
|
+
self.sliderVal = v
|
|
123
|
+
|
|
124
|
+
self.update()
|
|
125
|
+
|
|
126
|
+
self.statusbar = QWidget()
|
|
127
|
+
self.statusbar.setFixedHeight(26)
|
|
128
|
+
self.statusbarlyt = QHBoxLayout()
|
|
129
|
+
self.statusbarlyt.setContentsMargins(10, 0, 30, 0)
|
|
130
|
+
self.statusbar.setLayout(self.statusbarlyt)
|
|
131
|
+
self.editorlyt.addWidget(self.statusbar)
|
|
132
|
+
|
|
133
|
+
self.cursor_lbl = QLabel("0:0")
|
|
134
|
+
self.cursor_lbl.setStyleSheet("font-size:16px;")
|
|
135
|
+
self.statusbarlyt.addWidget(self.cursor_lbl, alignment=Qt.AlignLeft|Qt.AlignVCenter)
|
|
136
|
+
|
|
137
|
+
self.lang_lbl = QLabel("Plain text")
|
|
138
|
+
self.lang_lbl.setStyleSheet("font-size:16px;")
|
|
139
|
+
self.statusbarlyt.addWidget(self.lang_lbl, alignment=Qt.AlignRight|Qt.AlignVCenter)
|
|
140
|
+
|
|
141
|
+
@self.editor.cursorPositionChanged.connect
|
|
142
|
+
def slot():
|
|
143
|
+
self.cursor_lbl.setText(f"{self.editor.textCursor().blockNumber()}:{self.editor.textCursor().positionInBlock()}")
|
|
144
|
+
|
|
145
|
+
def __repr__(self):
|
|
146
|
+
return f"<Custom.CodeTextEdit({QCustomCodeEditor.LANG_DISPLAY(self.lang)})>"
|
|
147
|
+
|
|
148
|
+
def setTheme(self, theme):
|
|
149
|
+
self.highlighter.setTheme(theme)
|
|
150
|
+
self.highlighter.setRules()
|
|
151
|
+
|
|
152
|
+
c = self.highlighter.theme["background"]
|
|
153
|
+
rgb = f"rgb({c.red()}, {c.green()}, {c.blue()})"
|
|
154
|
+
|
|
155
|
+
cc = self.highlighter.theme["identifier"]
|
|
156
|
+
crgb = f"rgb({cc.red()}, {cc.green()}, {cc.blue()})"
|
|
157
|
+
|
|
158
|
+
self.editor.setStyleSheet(f"QPlainTextEdit {{background-color: {rgb}; color: {crgb};}}")
|
|
159
|
+
|
|
160
|
+
self.cursor_lbl.setStyleSheet(f"color: {crgb}; font-size:16px;")
|
|
161
|
+
self.lang_lbl.setStyleSheet(f"color: {crgb}; font-size:16px;")
|
|
162
|
+
|
|
163
|
+
self.highlighter.rehighlight()
|
|
164
|
+
self.update()
|
|
165
|
+
|
|
166
|
+
def setLang(self, lang):
|
|
167
|
+
self.lang_lbl.setText(QCustomCodeEditor.LANG_DISPLAY[lang])
|
|
168
|
+
|
|
169
|
+
self.highlighter.setLang(lang)
|
|
170
|
+
self.highlighter.setRules()
|
|
171
|
+
self.highlighter.rehighlight()
|
|
172
|
+
self.update()
|
|
173
|
+
|
|
174
|
+
def loadFile(self, filepath, encoding="utf-8"):
|
|
175
|
+
|
|
176
|
+
if filepath.endswith(".py"): lang = "python"
|
|
177
|
+
elif filepath.endswith(".cpp"): lang = "cpp"
|
|
178
|
+
else: lang = "plain"
|
|
179
|
+
|
|
180
|
+
with open(filepath, "r", encoding=encoding) as f:
|
|
181
|
+
self.editor.setPlainText(f.read())
|
|
182
|
+
|
|
183
|
+
self.setLang(lang)
|
|
184
|
+
|
|
185
|
+
def paintEvent(self, event):
|
|
186
|
+
pt = QPainter()
|
|
187
|
+
pt.begin(self)
|
|
188
|
+
pt.setRenderHint(QPainter.Antialiasing)
|
|
189
|
+
|
|
190
|
+
pt.setBrush(QBrush(self.highlighter.theme["lines-background"]))
|
|
191
|
+
|
|
192
|
+
pt.drawRect(0, 0, self.width(), self.height())
|
|
193
|
+
|
|
194
|
+
font = self.editor.font()
|
|
195
|
+
pt.setFont(font)
|
|
196
|
+
|
|
197
|
+
gap = font.pixelSize() + 3
|
|
198
|
+
|
|
199
|
+
for i in range((self.height()//gap)):
|
|
200
|
+
font = pt.font()
|
|
201
|
+
pt.setFont(font)
|
|
202
|
+
pt.setPen(QPen(self.highlighter.theme["lines"]))
|
|
203
|
+
|
|
204
|
+
pt.drawText(13, i*gap, str(i+self.sliderVal))
|
|
205
|
+
|
|
206
|
+
pt.setBrush(QBrush(self.highlighter.theme["background"]))
|
|
207
|
+
pt.setPen(QPen(QColor(0, 0, 0, 0)))
|
|
208
|
+
pt.drawRect(3, self.height()-self.statusbar.height(), 40, self.statusbar.height()-6)
|
|
209
|
+
|
|
210
|
+
pt.end()
|
|
211
|
+
|
|
212
|
+
class QCustomSyntaxHighlighter(QSyntaxHighlighter):
|
|
213
|
+
|
|
214
|
+
AVAILABLE_LANGS = {
|
|
215
|
+
"plain" : "plain",
|
|
216
|
+
"py" : "python",
|
|
217
|
+
"python" : "python",
|
|
218
|
+
"cpp" : "cpp",
|
|
219
|
+
"c++" : "cpp",
|
|
220
|
+
"js" : "javascript",
|
|
221
|
+
"jsx" : "javascript",
|
|
222
|
+
"javascript" : "javascript",
|
|
223
|
+
"ts" : "javascript",
|
|
224
|
+
"tsx" : "javascript",
|
|
225
|
+
"typescript" : "javascript"
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
def __init__(self, document, lang="python", theme="default"):
|
|
229
|
+
super().__init__(document)
|
|
230
|
+
|
|
231
|
+
self.setLang(lang)
|
|
232
|
+
self.setTheme(theme)
|
|
233
|
+
self.setRules()
|
|
234
|
+
|
|
235
|
+
def formatThemeKey(self, color, style="", returnColor=False):
|
|
236
|
+
_color = QColor()
|
|
237
|
+
if type(color) is not str:
|
|
238
|
+
_color.setRgb(color[0], color[1], color[2])
|
|
239
|
+
|
|
240
|
+
elif color.startswith("#"):
|
|
241
|
+
hexc = color.lstrip('#')
|
|
242
|
+
hexc = tuple(int(hexc[i:i+2], 16) for i in (0, 2, 4))
|
|
243
|
+
_color.setRgb(*hexc)
|
|
244
|
+
|
|
245
|
+
else:
|
|
246
|
+
_color = QColor(color)
|
|
247
|
+
|
|
248
|
+
if returnColor: return _color
|
|
249
|
+
|
|
250
|
+
_format = QTextCharFormat()
|
|
251
|
+
_format.setForeground(_color)
|
|
252
|
+
if "bold" in style: _format.setFontWeight(QFont.Bold)
|
|
253
|
+
if "italic" in style: _format.setFontItalic(True)
|
|
254
|
+
|
|
255
|
+
return _format
|
|
256
|
+
|
|
257
|
+
def setTheme(self, theme):
|
|
258
|
+
if isinstance(theme, dict):
|
|
259
|
+
pass
|
|
260
|
+
|
|
261
|
+
else:
|
|
262
|
+
path = pathlib.Path(packageDir()) / "CodeEditorThemes" / f"{theme}.json"
|
|
263
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
264
|
+
s = json.loads(f.read())
|
|
265
|
+
|
|
266
|
+
self.theme = dict()
|
|
267
|
+
|
|
268
|
+
for k in s:
|
|
269
|
+
p = s[k].split("-")
|
|
270
|
+
if len(p) == 2: self.theme[k] = self.formatThemeKey(s[k], p[1])
|
|
271
|
+
else: self.theme[k] = self.formatThemeKey(s[k])
|
|
272
|
+
|
|
273
|
+
self.theme["background"] = self.formatThemeKey(s["background"], returnColor=True)
|
|
274
|
+
self.theme["lines-background"] = self.formatThemeKey(s["lines-background"], returnColor=True)
|
|
275
|
+
self.theme["lines"] = self.formatThemeKey(s["lines"], returnColor=True)
|
|
276
|
+
self.theme["identifier"] = self.formatThemeKey(s["identifier"], returnColor=True)
|
|
277
|
+
|
|
278
|
+
def setLang(self, lang):
|
|
279
|
+
lang = lang.lower()
|
|
280
|
+
|
|
281
|
+
if lang in QCustomSyntaxHighlighter.AVAILABLE_LANGS:
|
|
282
|
+
self.lang = QCustomSyntaxHighlighter.AVAILABLE_LANGS[lang]
|
|
283
|
+
|
|
284
|
+
if self.lang == "plain": return
|
|
285
|
+
|
|
286
|
+
path = pathlib.Path(packageDir()) / "CodeEditorSyntax" / f"{self.lang}.json"
|
|
287
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
288
|
+
rr = json.loads(f.read())
|
|
289
|
+
|
|
290
|
+
self.keywords = rr["keywords"]
|
|
291
|
+
self.this = rr["this"]
|
|
292
|
+
self.comment = rr["comment"]
|
|
293
|
+
|
|
294
|
+
self.operators = operators = (
|
|
295
|
+
"=",
|
|
296
|
+
"==", "!=", "<", "<=", ">", ">=",
|
|
297
|
+
r"\+", "-", r"\*", "/", "//", r"\%", r"\*\*",
|
|
298
|
+
r"\+=", "-=", r"\*=", "/=", r"\%=",
|
|
299
|
+
r"\^", r"\|", r"\&", r"\~", ">>", "<<",
|
|
300
|
+
r"\+\+", "--", r"\&\&", r"\|\|"
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
self.braces = (
|
|
304
|
+
r"\{", r"\}", r"\(", r"\)", r"\[", r"\]",
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
else:
|
|
308
|
+
raise ValueError(f"Language '{lang}' is not supported.")
|
|
309
|
+
|
|
310
|
+
def setRules(self):
|
|
311
|
+
self.tri_single = (QRegularExpression("'''"), 1, self.theme["string"])
|
|
312
|
+
self.tri_double = (QRegularExpression('"""'), 2, self.theme["string"])
|
|
313
|
+
|
|
314
|
+
if self.lang == "plain":
|
|
315
|
+
self.rules = list()
|
|
316
|
+
return
|
|
317
|
+
|
|
318
|
+
rules = list()
|
|
319
|
+
|
|
320
|
+
rules += [(r'\b%s\b' % w, 0, self.theme["keyword"]) for w in self.keywords]
|
|
321
|
+
|
|
322
|
+
rules += [(r'%s' % o, 0, self.theme["operator"]) for o in self.operators]
|
|
323
|
+
|
|
324
|
+
rules += [(r'%s' % b, 0, self.theme["brace"]) for b in self.braces]
|
|
325
|
+
|
|
326
|
+
if self.lang in ("cpp", "c"):
|
|
327
|
+
rules.append( (r'\#[^\n]*', 0, self.theme["preprocessor"]) )
|
|
328
|
+
|
|
329
|
+
rules += [
|
|
330
|
+
(r"\b[A-Za-z0-9_]+(?=\()", 0, self.theme["function"]),
|
|
331
|
+
|
|
332
|
+
(r'\b%s\b' % self.this, 0, self.theme["this"]),
|
|
333
|
+
|
|
334
|
+
(r'"[^"\\]*(\\.[^"\\]*)*"', 0, self.theme["string"]),
|
|
335
|
+
|
|
336
|
+
(r"'[^'\\]*(\\.[^'\\]*)*'", 0, self.theme["string"]),
|
|
337
|
+
|
|
338
|
+
(r'%s[^\n]*' % self.comment, 0, self.theme["comment"]),
|
|
339
|
+
|
|
340
|
+
(r'\b[+-]?[0-9]+[lL]?\b', 0, self.theme["numeric"]),
|
|
341
|
+
(r'\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b', 0, self.theme["numeric"]),
|
|
342
|
+
(r'\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b', 0, self.theme["numeric"])
|
|
343
|
+
]
|
|
344
|
+
|
|
345
|
+
self.rules = [(QRegularExpression(pat), index, fmt) for (pat, index, fmt) in rules]
|
|
346
|
+
|
|
347
|
+
def highlightBlock(self, text):
|
|
348
|
+
for expression, nth, format in self.rules:
|
|
349
|
+
match = expression.match(text)
|
|
350
|
+
index = match.capturedStart(nth)
|
|
351
|
+
|
|
352
|
+
while index >= 0:
|
|
353
|
+
length = match.capturedLength(nth)
|
|
354
|
+
self.setFormat(index, length, format)
|
|
355
|
+
index = expression.match(text, index + length).capturedStart(nth)
|
|
356
|
+
|
|
357
|
+
self.setCurrentBlockState(0)
|
|
358
|
+
|
|
359
|
+
in_multiline = self.match_multiline(text, *self.tri_single)
|
|
360
|
+
if not in_multiline:
|
|
361
|
+
in_multiline = self.match_multiline(text, *self.tri_double)
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def match_multiline(self, text, delimiter, in_state, style):
|
|
366
|
+
if self.previousBlockState() == in_state:
|
|
367
|
+
start = 0
|
|
368
|
+
add = 0
|
|
369
|
+
|
|
370
|
+
else:
|
|
371
|
+
match = delimiter.match(text)
|
|
372
|
+
start = match.capturedStart()
|
|
373
|
+
add = match.capturedLength()
|
|
374
|
+
|
|
375
|
+
while start >= 0:
|
|
376
|
+
end = delimiter.indexIn(text, start + add)
|
|
377
|
+
|
|
378
|
+
if end >= add:
|
|
379
|
+
length = end - start + add + delimiter.matchedLength()
|
|
380
|
+
self.setCurrentBlockState(0)
|
|
381
|
+
|
|
382
|
+
else:
|
|
383
|
+
self.setCurrentBlockState(in_state)
|
|
384
|
+
length = len(text) - start + add
|
|
385
|
+
|
|
386
|
+
self.setFormat(start, length, style)
|
|
387
|
+
start = delimiter.indexIn(text, start + length)
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
if self.currentBlockState() == in_state: return True
|
|
391
|
+
else: return False
|