Checkpoint

This commit is contained in:
Christopher T. Johnson
2024-03-25 22:20:50 -04:00
parent 3e58e25297
commit e7b88c2c2e
2 changed files with 422 additions and 178 deletions

View File

@@ -36,7 +36,7 @@ def main() -> int:
): ):
query_error(query) query_error(query)
word = Word("lady") word = Word("boat")
snd = SoundOff() snd = SoundOff()
widget = Definition(word) # noqa: F841 widget = Definition(word) # noqa: F841
widget.pronounce.connect(snd.playSound) widget.pronounce.connect(snd.playSound)

View File

@@ -1,9 +1,10 @@
import copy
import json import json
import re import re
from typing import Any, Dict, List, Optional, Self, Type, cast from typing import Any, Dict, Optional, Self
import requests import requests
from PyQt6.QtCore import QPoint, QRect, Qt, pyqtSignal from PyQt6.QtCore import QPoint, QRect, QUrl, Qt, pyqtSignal
from PyQt6.QtGui import ( from PyQt6.QtGui import (
QBrush, QBrush,
QColor, QColor,
@@ -13,8 +14,8 @@ from PyQt6.QtGui import (
QMouseEvent, QMouseEvent,
QPainter, QPainter,
QPaintEvent, QPaintEvent,
QTextFormat,
QTextOption, QTextOption,
QTransform,
) )
from PyQt6.QtSql import QSqlQuery from PyQt6.QtSql import QSqlQuery
from PyQt6.QtWidgets import QWidget from PyQt6.QtWidgets import QWidget
@@ -28,41 +29,65 @@ MWAPI = "https://www.dictionaryapi.com/api/v3/references/collegiate/json/{word}?
class Word: class Word:
_instance = None _instance = None
_words: Dict[str, str] = {} _words: Dict[str, str] = {}
_current: Optional[Dict[str, Any]] = None _current: Dict[str, Any]
_currentWord: Optional[str] = None _currentWord: str
class Fragment: class Fragment:
_type: str """A structure to hold typed values of a fragment."""
_text: str
_font: QFont
_audio: str
_align: QTextOption
_rect: QRect
_type: str # Function of this fragment. Think text, span, button
_text: str # The simple utf-8 text
_content: list['Word.Fragment']
_audio: QUrl # Optional audio URL
_font: QFont # The font, with all options, to use for this fragment
_align: QTextOption # Alignment information
_rect: QRect # The rect that contains _text
_padding: list[int] # space to add around the text
_border: list[int] # Size of the border (all the same)
_margin: list[int] # Space outside of the border
_color: QColor # the pen color
_wref: str # a word used as a 'href'
_position: QPoint # where to drawText
_borderRect: QRect # where to drawRect
_radius: int # Radius for rounded rects
TYPES = [ 'text', 'span', 'button' ]
def __init__(self, def __init__(self,
text:str, text:str,
font:QFont, font:QFont,
t:str = 'text', t:str = 'text',
audio:str = '', audio:str = '',
align:QTextOption = QTextOption(Qt.AlignmentFlag.AlignLeft| color: QColor = None
Qt.AlignmentFlag.AlignBaseline),
rect:QRect = QRect(0,0,0,0)
) -> None: ) -> None:
self._type = t # or 'container' if t not in self.TYPES:
raise Exception(f"Unknown fragment type{t}")
self._type = t
self._text = text self._text = text
self._font = font self._font = font
self._audio = audio self._audio = QUrl(audio)
self._align = align self._align = QTextOption(
self._rect = rect Qt.AlignmentFlag.AlignLeft
return | Qt.AlignmentFlag.AlignBaseline
)
def setType(self, t:str) -> None: self._padding = [0, 0, 0, 0]
if t == 'text': self._border = [0, 0, 0, 0]
self._type = t self._margin = [0, 0, 0, 0]
elif t== 'container': self._wref = ''
self._type = t self._position = QPoint()
self._borderRect = QRect()
if color:
self._color = color
else: else:
raise Exception("Bad Value") self._color = QColor()
return
#
# Setters
#
def setType(self, t:str) -> None:
if t not in self.TYPES:
raise Exception(f"Unknown fragment type{t}")
self._type = t
return return
def setText(self, text:str) -> None: def setText(self, text:str) -> None:
self._text = text self._text = text
@@ -71,7 +96,7 @@ class Word:
self._font = font self._font = font
return return
def setAudio(self, audio:str) -> None: def setAudio(self, audio:str) -> None:
self._audio = audio self._audio = QUrl(audio)
return return
def setAlign(self, align:QTextOption) -> None: def setAlign(self, align:QTextOption) -> None:
self._align = align self._align = align
@@ -79,6 +104,89 @@ class Word:
def setRect(self,rect:QRect) -> None: def setRect(self,rect:QRect) -> None:
self._rect = rect self._rect = rect
return return
def setPadding(self, top:int = -1, right:int = -1, bottom:int = -1, left:int = -1, *args:int) -> None:
if top > -1 or right > -1 or bottom > -1 or left > -1:
if top >= 0:
self._padding[0] = top
if right >= 0:
self._padding[1] = right
if bottom >= 0:
self._padding[2] = bottom
if left >= 0:
self._padding[3] = left
return
if len(args) == 4:
self._padding = [args[0], args[1], args[2], args[3]]
elif len(args) == 3:
self._padding = [args[0], args[1], args[2], args[1]]
elif len(args) == 2:
self._padding = [args[0], args[1], args[0], args[1]]
elif len(args) == 1:
self._padding = [args[0], args[0], args[0], args[0]]
else:
raise Exception("argument error")
return
def setBorder(self, top:int = -1, right:int = -1, bottom:int = -1, left:int = -1, *args:int) -> None:
if top > -1 or right > -1 or bottom > -1 or left > -1:
if top >= 0:
self._border[0] = top
if right >= 0:
self._border[1] = right
if bottom >= 0:
self._border[2] = bottom
if left >= 0:
self._border[3] = left
return
if len(args) == 4:
self._border = [args[0], args[1], args[2], args[3]]
elif len(args) == 3:
self._border = [args[0], args[1], args[2], args[1]]
elif len(args) == 2:
self._border = [args[0], args[1], args[0], args[1]]
elif len(args) == 1:
self._border = [args[0], args[0], args[0], args[0]]
else:
raise Exception("argument error")
return
def setMargin(self, top:int = -1, right:int = -1, bottom:int = -1, left:int = -1, *args:int) -> None:
if top > -1 or right > -1 or bottom > -1 or left > -1:
if top >= 0:
self._margin[0] = top
if right >= 0:
self._margin[1] = right
if bottom >= 0:
self._margin[2] = bottom
if left >= 0:
self._margin[3] = left
return
if len(args) == 4:
self._margin = [args[0], args[1], args[2], args[3]]
elif len(args) == 3:
self._margin = [args[0], args[1], args[2], args[1]]
elif len(args) == 2:
self._margin = [args[0], args[1], args[0], args[1]]
elif len(args) == 1:
self._margin = [args[0], args[0], args[0], args[0]]
else:
raise Exception("argument error")
return
def setWRef(self, ref:str) -> None:
self._wref = ref
return
def setPosition(self, pnt:QPoint) -> None:
self._position = pnt
return
def setBorderRect(self, rect:QRect) -> None:
self._borderRect = rect
return
def setColor(self,color:QColor) -> None:
self._color = color
return
#
# Getters
#
def wRef(self) -> str:
return self._wref
def type(self) -> str: def type(self) -> str:
return self._type return self._type
def text(self) -> str: def text(self) -> str:
@@ -86,18 +194,30 @@ class Word:
def font(self) -> QFont: def font(self) -> QFont:
return self._font return self._font
def audio(self) -> str: def audio(self) -> str:
return self._audio return self._audio.url()
def align(self) -> QTextOption: def align(self) -> QTextOption:
return self._align return self._align
def rect(self) -> QRect: def rect(self) -> QRect:
return self._rect return self._rect
def padding(self) -> list[int]:
return self._padding
def border(self) -> list[int]:
return self._border
def margin(self) -> list[int]:
return self._margin
def position(self) -> QPoint:
return self._position
def borderRect(self) -> QRect:
return self._borderRect
def color(self) -> QColor:
return self._color
class Line: class Line:
_maxHeight: int _maxHeight: int
_leading: int _leading: int
_baseLine: int _baseLine: int
_fragments: List['Word.Fragment'] _fragments: list['Word.Fragment']
def __init__(self) -> None: def __init__(self) -> None:
self._maxHeight = -1 self._maxHeight = -1
@@ -106,126 +226,228 @@ class Word:
self._fragments = [] self._fragments = []
return return
def fixText(self, frag: 'Word.Fragment') -> List['Word.Fragment']: def parseText(self, frag: 'Word.Fragment') -> list['Word.Fragment']:
text = frag.text() org = frag.text()
text = re.sub(r"\*", "\u2022", text) print(org)
text = re.sub(r"\{ldquo\}", "\u201c", text)
text = re.sub(r"\{rdquo\}", "\u201d", text)
parts: List[str] = []
# #
# Break the text into parts based on brace markup # Needed Fonts
# #
while len(text) > 0:
start = text.find("{")
if start > 0:
parts.append(text[:start])
text = text[start:]
if start >= 0:
end = text.find("}")
parts.append(text[:end])
text = text[end:]
else:
parts.append(text)
text = ''
results: List[Word.Fragment] = []
bold = QFont(frag.font()) bold = QFont(frag.font())
bold.setBold(True) bold.setWeight(QFont.Weight.Bold)
italic = QFont(frag.font()) italic = QFont(frag.font())
italic.setItalic(True) italic.setItalic(True)
smallCaps = QFont(frag.font())
smallCaps.setCapitalization(QFont.Capitalization.SmallCaps)
script = QFont(frag.font()) script = QFont(frag.font())
script.setPixelSize(int(script.pixelSize() / 4)) script.setPixelSize(int(script.pixelSize()/4))
while len(parts) > 0:
if parts[0] == '{bc}': results: list['Word.Fragment'] = []
while True:
text = frag.text()
start = text.find('{')
if start < 0:
results.append(frag)
return results
if start > 0:
newFrag = copy.copy(frag)
newFrag.setText(text[:start])
results.append(newFrag)
frag.setText(text[start:])
continue
#
# Start == 0
#
#
# If the token is an end-token, return now.
#
if text.startswith('{/'):
results.append(frag)
return results
#
# extract this token
#
end = text.find('}')
token = text[1:end]
frag.setText(text[end+1:])
newFrag = copy.copy(frag)
oldFont = QFont(frag.font)
if token == 'bc':
results.append(Word.Fragment(': ', bold)) results.append(Word.Fragment(': ', bold))
elif parts[0] == '{inf}': continue
parts.pop(0) if token in ['b', 'inf', 'it', 'sc', 'sup', 'phrase', 'parahw', 'gloss',
results.append(Word.Fragment(parts[0], script)) # baseAdjust=??? 'qword', 'wi', 'dx', 'dx_def', 'dx_ety', 'ma']:
parts.pop(0) frag.setText(text)
elif parts[0] == '{sup}': if token == 'b':
parts.pop(0) frag.setFont(bold)
results.append(Word.Fragment(parts[0], script)) # baseAdjust=??? elif token in ['it', 'qword', 'wi']:
parts.pop(0) frag.setFont(italic)
elif parts[0] == '{it}' or parts[0] == '{wi}': elif token == 'sc':
parts.pop(0) frag.setFont(smallCaps)
results.append(Word.Fragment(parts[0], italic)) # baseAdjust=??? elif token in ['inf', 'sup']:
parts.pop(0) frag.setFont(script)
elif parts[0] == '{sc}' or parts[0] == '{parahw}': elif token == 'phrase':
parts.pop(0)
font = QFont(frag.font())
font.setCapitalization(QFont.Capitalization.SmallCaps)
results.append(Word.Fragment(parts[0], font))
parts.pop(0)
elif parts[0] == '{phrase}':
font = QFont(bold) font = QFont(bold)
font.setItalic(True) font.setItalic(True)
parts.pop(0) frag.setFont(font)
results.append(Word.Fragment(parts[0], font)) elif token == 'parahw':
parts.pop(0) font = QFont(smallCaps)
elif parts[0] == '{gloss}': font.setWeight(QFont.Weight.Bold)
parts.pop(0) frag.setFont(font)
results.append(Word.Fragment(f"[{parts[0]}]",frag.font())) elif token == 'gloss':
parts.pop(0) frag.setText('[' + frag.text())
elif token in ['dx', 'dx_ety']:
frag.setText('\u2014'+frag.text())
elif token == 'ma':
frag.setText('\u2014 more at '+frag.text())
elif token == 'dx_def':
frag.setText('('+frag.text())
else: else:
results.append(Word.Fragment(parts[0],frag.font())) raise Exception(f"Unknown block marker: {token}")
parts.pop(0) results += self.parseText(frag)
return results frag = results.pop()
frag.setFont(oldFont)
text = frag.text()
if not text.startswith('{/'+token+'}'):
raise Exception(f"No matching close for {token} in {org}")
if token == 'gloss':
results[-1].setText(results[-1].text() + ']')
elif token == 'dx_def':
results[-1].setText(results[-1].text() + ')')
end = text.find('}')
text = text[end+1:]
frag.setText(text)
continue
#
# These are codes that include all information within the token
#
fields = token.split('|')
token = fields[0]
if token in [ 'a_line', 'd_link', 'dxt', 'et_link', 'i_link',
'mat', 'sx']:
wref = ''
htext = fields[1]
oldFont = QFont(frag.font())
if token == 'a_link':
wref = fields[1]
elif token in ['d_link', 'et_link', 'mat', 'sx', 'i_link']:
if fields[2] == '':
wref = fields[1]
else:
wref = fields[2]
if token == 'i_link':
frag.setFont(italic)
elif token == 'i_link':
if fields[2] == '':
wref = fields[1]
else:
wref = fields[2]
else:
raise Exception(f"Unknown code: {token} in {org}")
newFrag = copy.copy(frag)
newFrag.setText(htext)
newFrag.setWRef(wref)
results.append(newFrag)
frag.setFont(oldFont)
text = frag.text()
continue
raise Exception(f"Unable to locate a known token {token} in {org}")
def addFragment(self, frag: 'Word.Fragment',) -> None: def addFragment(self, frag: 'Word.Fragment',) -> None:
SPEAKER = "\U0001F508" SPEAKER = "\U0001F508"
if len(self._fragments) > 0: if frag.audio():
frag._text = ' ' + frag._text frag.setText(frag.text() + ' ' + SPEAKER)
if frag._audio is not None:
frag._audio += ' ' + SPEAKER text = frag.text()
items = self.fixText(frag)) text = re.sub(r"\*", "\u2022", text)
for item in items: text = re.sub(r"\{ldquo\}", "\u201c", text)
self._fragments.append(item) text = re.sub(r"\{rdquo\}", "\u201d", text)
frag.setText(text)
if frag.type() == 'btn':
frag.setPadding(3)
frag.setBorder(1)
frag.setMargin(2)
items = self.parseText(frag)
self._fragments += items
return return
def getLine(self) -> List['Word.Fragment']: def finalizeLine(self, width:int) -> None:
for fragment in self._fragments: """Create all of the positions for all the fragments."""
font = fragment.font() #
fm = QFontMetrics(font) # Find the maximum hight and max baseline
if fm.leading() > self._leading: #
self._leading = fm.leading() maxHeight = -1
rect = fm.boundingRect(fragment.text(), fragment.align()) baseLine = -1
leading = -1
for frag in self._fragments:
fm = QFontMetrics(frag.font())
rect = fm.boundingRect(frag.text(), frag.align())
height = rect.height() height = rect.height()
baseLine = height - fm.descent() baseLine = height - fm.descent()
if fragment.type() == "btn": #
height += 6 # Add the padding, border and margin to adjust the baseline and height
baseLine += 3 #
if baseLine > self._baseLine: b = frag.padding()
height += b[0] + b[2]
baseLine += b[2]
b = frag.border()
height += b[0] + b[2]
baseLine += b[2]
b = frag.margin()
height += b[0] + b[2]
baseLine += b[2]
if height > maxHeight:
maxHeight = height
if baseLine > baseLine:
baseLine = baseLine
self._baseLine = baseLine self._baseLine = baseLine
if rect.height() > self._maxHeight: self._maxHeight = maxHeight
self._maxHeight = rect.height() self._leading = 0 # XXX - How should this be calculated?
x = 0 x = 0
for fragment in self._fragments: for frag in self._fragments:
fragment.setPosition(QPoint(x,self._baseLine)) #
fm = QFontMetrics(fragment.font()) # TODO - Wordwrap
rect = fm.boundingRect(fragment.text(),fragment.align()) # TODO - indent
x += rect.width() fm = QFontMetrics(frag.font())
if fragment.type() == "btn": rect = fm.boundingRect(frag.text())
x += 6 width = rect.width()
padding = frag.padding()
offset = padding[3] # Left margin
width += padding[1] + padding[3]
border = frag.border()
offset += border[3]
width += border[1] + border[3]
margin = frag.margin()
offset += margin[3]
width += margin[1] + margin[3]
frag.setPosition(QPoint(x+offset, self._baseLine))
if frag.border()[0] != 0:
#
# self._baseLine is where the text will be drawn
# fm.descent is the distance from the baseline of the
# text to the bottom of the rect
# The top of the bounding rect is at self._baseLine
# + fm.descent - rect.height
# The border is drawn at top-padding-border-margin+marin
#
top = self._baseLine + fm.descent() - rect.height() -1
y = top - padding[0] - border[0]
frag.setBorderRect(QRect(x+margin[3], y, width, height))
x += width
return
def getLine(self) -> list['Word.Fragment']:
return self._fragments return self._fragments
def getLeading(self) -> int: def getLeading(self) -> int:
return self._leading + self._maxHeight return self._leading + self._maxHeight
def getBtnRect( _lines: list[Line] = []
self, frag: Dict[str, str | QTextOption | QFont | int]
) -> QRect:
fm = QFontMetrics(cast(QFont, frag["font"]))
rect = fm.boundingRect(
cast(str, frag["text"]), cast(QTextOption, frag["align"])
)
rect.setHeight(rect.height() + 6)
rect.setWidth(rect.width() + 6)
return rect
_lines: List[Line] = [] def __new__(cls: type[Self], _: str) -> Self: # flycheck: ignore
def __new__(cls: Type[Self], word: str) -> Self: # flycheck: ignore
if cls._instance: if cls._instance:
return cls._instance return cls._instance
cls._instance = super(Word, cls).__new__(cls) cls._instance = super(Word, cls).__new__(cls)
@@ -286,7 +508,7 @@ class Word:
else: else:
return self.apidictionary_html() return self.apidictionary_html()
def get_def(self) -> List[Line] | None: def get_def(self) -> list[Line] | None:
if not self._current: if not self._current:
return None return None
if "meta" in self._current.keys(): if "meta" in self._current.keys():
@@ -294,53 +516,80 @@ class Word:
else: else:
return None return None
def mw_def(self) -> List[Line]: def mw_def(self) -> list[Line]:
if len(self._lines) > 0: if len(self._lines) > 0:
return self._lines return self._lines
assert self._current is not None assert self._current is not None
line = self.Line() line = self.Line()
#
# Colors we used
#
base = QColor(Qt.GlobalColor.white)
blue = QColor("#4a7d95")
headerFont = QFontDatabase.font("OpenDyslexic", None, 10) headerFont = QFontDatabase.font("OpenDyslexic", None, 10)
headerFont.setPixelSize(48) headerFont.setPixelSize(48)
headerFont.setWeight(QFont.Weight.Bold) headerFont.setWeight(QFont.Weight.Bold)
labelFont = QFontDatabase.font("OpenDyslexic", None, 10) labelFont = QFontDatabase.font("OpenDyslexic", None, 10)
labelFont.setPixelSize(32) labelFont.setPixelSize(30)
phonicFont = QFontDatabase.font("Gentium", None, 10) phonicFont = QFontDatabase.font("Gentium", None, 10)
phonicFont.setPixelSize(32) phonicFont.setPixelSize(20)
boldFont = QFontDatabase.font("OpenDyslexic", None, 10) boldFont = QFontDatabase.font("OpenDyslexic", None, 10)
boldFont.setPixelSize(24) boldFont.setPixelSize(20)
boldFont.setBold(True) boldFont.setBold(True)
textFont = QFontDatabase.font("OpenDyslexic", None, 10) textFont = QFontDatabase.font("OpenDyslexic", None, 10)
textFont.setPixelSize(24) textFont.setPixelSize(20)
line.addFragment(self._current["hwi"]["hw"], headerFont) hw = re.sub(r'\*', '', self._current['hwi']['hw'])
line.addFragment(self._current["fl"], labelFont, color="#4a7d95") frag = Word.Fragment(hw, headerFont, color=base)
line.addFragment(frag)
frag = Word.Fragment(' '+self._current["fl"], labelFont, color=blue)
line.addFragment(frag)
self._lines.append(line) self._lines.append(line)
if "vrs" in self._current.keys(): if "vrs" in self._current.keys():
line = self.Line() line = self.Line()
space = ''
for vrs in self._current["vrs"]: for vrs in self._current["vrs"]:
line.addFragment(vrs["va"], labelFont) frag = Word.Fragment(space + vrs["va"], labelFont, color=base)
space = ' '
line.addFragment(frag)
self._lines.append(line) self._lines.append(line)
if "prs" in self._current["hwi"].keys(): if "prs" in self._current["hwi"].keys():
line = self.Line() line = self.Line()
frag = Word.Fragment(self._current['hwi']['hw'] + ' ', phonicFont, color=base)
line.addFragment(frag)
for prs in self._current["hwi"]["prs"]: for prs in self._current["hwi"]["prs"]:
audio = self.sound_url(prs) audio = self.sound_url(prs)
if audio is None: if audio is None:
audio = "" audio = ""
line.addFragment( frag = Word.Fragment(prs['mw'], phonicFont, color=blue)
prs["mw"], frag.setAudio(audio)
phonicFont, frag.setPadding(0,10,3,12)
opt="btn", frag.setBorder(1)
audio=audio, frag.setMargin(0,3,0,3)
color="#4a7d95", line.addFragment(frag)
)
self._lines.append(line) self._lines.append(line)
if "ins" in self._current.keys(): if "ins" in self._current.keys():
line = self.Line() line = self.Line()
line.addFragment( space = ''
"; ".join([x["if"] for x in self._current["ins"]]), boldFont for ins in self._current['ins']:
) try:
frag = Word.Fragment(ins['il'], textFont, color=base)
line.addFragment(frag)
space = ' '
except KeyError:
space = ''
frag = Word.Fragment(space + ins['if'], boldFont, color=base)
line.addFragment(frag)
space = '; '
self._lines.append(line) self._lines.append(line)
if 'lbs' in self._current.keys():
print('lbs')
line = self.Line()
frag = Word.Fragment('; '.join(self._current['lbs']), boldFont, color=base)
line.addFragment(frag)
self._lines.append(line)
return self._lines return self._lines
def sound_url(self, prs: Dict[str, Any], fmt: str = "ogg") -> str | None: def sound_url(self, prs: Dict[str, Any], fmt: str = "ogg") -> str | None:
@@ -443,8 +692,8 @@ class Word:
class Definition(QWidget): class Definition(QWidget):
pronounce = pyqtSignal(str) pronounce = pyqtSignal(str)
_word: str _word: str
_lines: List[Word.Line] _lines: list[Word.Line]
_buttons: List[QRect] _buttons: list[QRect]
def __init__(self, w: Word, *args: Any, **kwargs: Any) -> None: def __init__(self, w: Word, *args: Any, **kwargs: Any) -> None:
super(Definition, self).__init__(*args, **kwargs) super(Definition, self).__init__(*args, **kwargs)
@@ -456,11 +705,7 @@ class Definition(QWidget):
assert self._lines is not None assert self._lines is not None
base = 0 base = 0
for line in self._lines: for line in self._lines:
for frag in line.getLine(): line.finalizeLine(80)
if frag["opt"] == "btn":
rect = line.getBtnRect(frag)
rect.moveTop(base)
self._buttons.append(rect)
base += line.getLeading() base += line.getLeading()
return return
@@ -487,7 +732,7 @@ class Definition(QWidget):
self._downRect = None self._downRect = None
return super().mouseReleaseEvent(event) return super().mouseReleaseEvent(event)
def paintEvent(self, event: Optional[QPaintEvent]) -> None: # noqa def paintEvent(self, _: Optional[QPaintEvent]) -> None: # noqa
painter = QPainter(self) painter = QPainter(self)
painter.save() painter.save()
painter.setBrush(QBrush()) painter.setBrush(QBrush())
@@ -504,30 +749,29 @@ class Definition(QWidget):
assert self._lines is not None assert self._lines is not None
base = 0 base = 0
for line in self._lines: for line in self._lines:
transform = QTransform()
transform.translate(0, base)
painter.setTransform(transform)
for frag in line.getLine(): for frag in line.getLine():
keys = frag.keys()
font = cast(QFont, frag["font"])
painter.setFont(font)
if "color" in keys:
painter.save() painter.save()
painter.setPen(QColor(frag["color"])) painter.setFont(frag.font())
if frag["opt"] == "btn": painter.setPen(frag.color())
rect = line.getBtnRect(frag) #
rect.moveTop(base) # Is this a button?
painter.drawRoundedRect(rect, 10.0, 10.0) #
painter.drawText( href = frag.audio()
cast(int, frag["x"]) + 3, if href:
base + 3 + cast(int, frag["y"]), radius = frag.borderRect().height()/2
cast(str, frag["text"]), painter.drawRoundedRect(frag.borderRect(), radius, radius)
) #
else: # is it an anchor?
painter.drawText( #
cast(int, frag["x"]), elif frag.wRef():
base + cast(int, frag["y"]), painter.drawLine(frag.borderRect().bottomLeft(), frag.borderRect().bottomRight())
cast(str, frag["text"]), print(base, painter.pen().color().name(), frag.position(), frag.text())
) painter.drawText(frag.position(), frag.text())
if "color" in keys:
painter.restore() painter.restore()
painter.resetTransform()
base += line.getLeading() base += line.getLeading()
painter.restore() painter.restore()
return return