Linter reformat

This commit is contained in:
Christopher T. Johnson
2024-04-01 10:12:12 -04:00
parent 77b0daa30d
commit 55dbac5102
2 changed files with 319 additions and 221 deletions

View File

@@ -168,7 +168,8 @@ SQL_CMDS = [
"PRAGMA foreign_keys=ON", "PRAGMA foreign_keys=ON",
# #
"CREATE TABLE IF NOT EXISTS words " "CREATE TABLE IF NOT EXISTS words "
"(word_id INTEGER PRIMARY KEY AUTOINCREMENT, word TEXT, definition TEXT)", "(word_id INTEGER PRIMARY KEY AUTOINCREMENT, word TEXT, "
"source TEXT, definition TEXT)",
# #
"CREATE TABLE IF NOT EXISTS books " "CREATE TABLE IF NOT EXISTS books "
"(book_id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, author TEXT, " "(book_id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, author TEXT, "

View File

@@ -3,8 +3,19 @@ import json
import re import re
from typing import Any, Optional, cast from typing import Any, Optional, cast
import requests from PyQt6.QtCore import (
from PyQt6.QtCore import QMargins, QPoint, QRect, QSize, QUrl, Qt, pyqtSignal QByteArray,
QEventLoop,
QMargins,
QPoint,
QRect,
QSize,
Qt,
QThread,
QUrl,
pyqtSignal,
pyqtSlot,
)
from PyQt6.QtGui import ( from PyQt6.QtGui import (
QBrush, QBrush,
QColor, QColor,
@@ -28,27 +39,28 @@ from PyQt6.QtWidgets import QScrollArea, QWidget
from lib import query_error from lib import query_error
class Fragment: class Fragment:
"""A fragment of text to be displayed""" """A fragment of text to be displayed"""
def __init__(self, def __init__(
text:str, self,
font:QFont, text: str,
audio:str = '', font: QFont,
color: Optional[QColor] = None, audio: str = "",
asis: bool = False, color: Optional[QColor] = None,
) -> None: asis: bool = False,
) -> None:
self._text = text self._text = text
self._font = font self._font = font
self._audio:QUrl = QUrl(audio) self._audio: QUrl = QUrl(audio)
self._align = QTextOption( self._align = QTextOption(
Qt.AlignmentFlag.AlignLeft Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignBaseline
| Qt.AlignmentFlag.AlignBaseline
) )
self._padding = QMargins() self._padding = QMargins()
self._border = QMargins() self._border = QMargins()
self._margin = QMargins() self._margin = QMargins()
self._wref = '' self._wref = ""
self._position = QPoint() self._position = QPoint()
self._rect = QRect() self._rect = QRect()
self._borderRect = QRect() self._borderRect = QRect()
@@ -64,9 +76,13 @@ class Fragment:
def __str__(self) -> str: def __str__(self) -> str:
return self.__repr__() return self.__repr__()
def size(self, width:int) -> QSize: def size(self, width: int) -> QSize:
rect = QRect(self._position,QSize(width,2000)) rect = QRect(self._position, QSize(width, 2000))
flags = Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignBaseline | Qt.TextFlag.TextWordWrap flags = (
Qt.AlignmentFlag.AlignLeft
| Qt.AlignmentFlag.AlignBaseline
| Qt.TextFlag.TextWordWrap
)
fm = QFontMetrics(self._font) fm = QFontMetrics(self._font)
bounding = fm.boundingRect(rect, flags, self._text) bounding = fm.boundingRect(rect, flags, self._text)
size = bounding.size() size = bounding.size()
@@ -78,70 +94,80 @@ class Fragment:
def height(self, width: int) -> int: def height(self, width: int) -> int:
return self.size(width).height() return self.size(width).height()
def width(self, width:int) -> int: def width(self, width: int) -> int:
return self.size(width).width() return self.size(width).width()
def __repr__(self) -> str: def __repr__(self) -> str:
return f'({self._position.x()}, {self._position.y()}): {self._text}' return f"({self._position.x()}, {self._position.y()}): {self._text}"
def repaintEvent(self, painter:QPainter) -> int: def repaintEvent(self, painter: QPainter) -> int:
painter.save() painter.save()
painter.setFont(self._font) painter.setFont(self._font)
painter.setPen(self._color) painter.setPen(self._color)
rect = QRect() rect = QRect()
rect.setLeft(self._position.x()) rect.setLeft(self._position.x())
rect.setTop(self._position.y() + painter.fontMetrics().descent() - painter.fontMetrics().height()) rect.setTop(
self._position.y()
+ painter.fontMetrics().descent()
- painter.fontMetrics().height()
)
rect.setWidth(painter.viewport().width() - self._position.x()) rect.setWidth(painter.viewport().width() - self._position.x())
rect.setHeight(2000) rect.setHeight(2000)
flags = Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignBaseline | Qt.TextFlag.TextWordWrap flags = (
bounding = painter.boundingRect(rect,flags, self._text) Qt.AlignmentFlag.AlignLeft
| Qt.AlignmentFlag.AlignBaseline
| Qt.TextFlag.TextWordWrap
)
bounding = painter.boundingRect(rect, flags, self._text)
size = bounding.size() size = bounding.size()
painter.setPen(QColor("#f00")) painter.setPen(QColor("#f00"))
if self._audio.isValid(): if self._audio.isValid():
radius = self._borderRect.height() /2 radius = self._borderRect.height() / 2
painter.drawRoundedRect(self._borderRect, radius, radius) painter.drawRoundedRect(self._borderRect, radius, radius)
if self._wref: if self._wref:
start = bounding.bottomLeft() start = bounding.bottomLeft()
end = bounding.bottomRight() end = bounding.bottomRight()
painter.drawLine(start,end) painter.drawLine(start, end)
painter.setPen(self._color) painter.setPen(self._color)
painter.drawText( painter.drawText(rect, flags, self._text)
rect,
flags,
self._text
)
painter.restore() painter.restore()
size = size.grownBy(self._margin) size = size.grownBy(self._margin)
size = size.grownBy(self._border) size = size.grownBy(self._border)
size = size.grownBy(self._padding) size = size.grownBy(self._padding)
return size.height() return size.height()
# #
# Setters # Setters
# #
def setText(self, text:str) -> None: def setText(self, text: str) -> None:
self._text = text self._text = text
return return
def setFont(self, font:QFont) -> None:
def setFont(self, font: QFont) -> None:
self._font = font self._font = font
return return
def setAudio(self, audio:str|QUrl) -> None:
def setAudio(self, audio: str | QUrl) -> None:
if type(audio) is str: if type(audio) is str:
self._audio = QUrl(audio) self._audio = QUrl(audio)
else: else:
self._audio = cast(QUrl,audio) self._audio = cast(QUrl, audio)
return return
def setAlign(self, align:QTextOption) -> None:
def setAlign(self, align: QTextOption) -> None:
self._align = align self._align = align
return return
def setRect(self,rect:QRect) -> None:
def setRect(self, rect: QRect) -> None:
self._rect = rect self._rect = rect
return return
def setPadding(self, *args:int, **kwargs:int) -> None:
top = kwargs.get('top', -1) def setPadding(self, *args: int, **kwargs: int) -> None:
right = kwargs.get('right', -1) top = kwargs.get("top", -1)
bottom = kwargs.get('bottom', -1) right = kwargs.get("right", -1)
left = kwargs.get('left', -1) bottom = kwargs.get("bottom", -1)
left = kwargs.get("left", -1)
if top > -1 or right > -1 or bottom > -1 or left > -1: if top > -1 or right > -1 or bottom > -1 or left > -1:
if top >= 0: if top >= 0:
self._padding.setTop(top) self._padding.setTop(top)
@@ -164,12 +190,12 @@ class Fragment:
raise Exception("argument error") raise Exception("argument error")
self._padding = QMargins(left, top, right, bottom) self._padding = QMargins(left, top, right, bottom)
return return
def setBorder(self, *args:int, **kwargs:int) -> None: def setBorder(self, *args: int, **kwargs: int) -> None:
top = kwargs.get('top', -1) top = kwargs.get("top", -1)
right = kwargs.get('right', -1) right = kwargs.get("right", -1)
bottom = kwargs.get('bottom', -1) bottom = kwargs.get("bottom", -1)
left = kwargs.get('left', -1) left = kwargs.get("left", -1)
if top > -1 or right > -1 or bottom > -1 or left > -1: if top > -1 or right > -1 or bottom > -1 or left > -1:
if top >= 0: if top >= 0:
self._border.setTop(top) self._border.setTop(top)
@@ -192,12 +218,13 @@ class Fragment:
raise Exception("argument error") raise Exception("argument error")
self._border = QMargins(left, top, right, bottom) self._border = QMargins(left, top, right, bottom)
return return
def setMargin(self, *args:int, **kwargs:int) -> None:
top = kwargs.get('top', -1) def setMargin(self, *args: int, **kwargs: int) -> None:
right = kwargs.get('right', -1) top = kwargs.get("top", -1)
bottom = kwargs.get('bottom', -1) right = kwargs.get("right", -1)
left = kwargs.get('left', -1) bottom = kwargs.get("bottom", -1)
left = kwargs.get("left", -1)
if top > -1 or right > -1 or bottom > -1 or left > -1: if top > -1 or right > -1 or bottom > -1 or left > -1:
if top >= 0: if top >= 0:
self._margin.setTop(top) self._margin.setTop(top)
@@ -209,7 +236,7 @@ class Fragment:
self._margin.setLeft(left) self._margin.setLeft(left)
return return
if len(args) == 4: if len(args) == 4:
(top, right, bottom, left) =[args[0], args[1], args[2], args[3]] (top, right, bottom, left) = [args[0], args[1], args[2], args[3]]
elif len(args) == 3: elif len(args) == 3:
(top, right, bottom, left) = [args[0], args[1], args[2], args[1]] (top, right, bottom, left) = [args[0], args[1], args[2], args[1]]
elif len(args) == 2: elif len(args) == 2:
@@ -220,58 +247,79 @@ class Fragment:
raise Exception("argument error") raise Exception("argument error")
self._margin = QMargins(left, top, right, bottom) self._margin = QMargins(left, top, right, bottom)
return return
def setWRef(self, ref:str) -> None:
def setWRef(self, ref: str) -> None:
self._wref = ref self._wref = ref
return return
def setPosition(self, pnt:QPoint) -> None:
def setPosition(self, pnt: QPoint) -> None:
self._position = pnt self._position = pnt
return return
def setBorderRect(self, rect:QRect) -> None:
def setBorderRect(self, rect: QRect) -> None:
self._borderRect = rect self._borderRect = rect
return return
def setClickRect(self, rect:QRect) -> None:
def setClickRect(self, rect: QRect) -> None:
self._clickRect = rect self._clickRect = rect
return return
def setColor(self,color:QColor) -> None:
def setColor(self, color: QColor) -> None:
self._color = color self._color = color
return return
def setLeft(self, left:int) -> None:
def setLeft(self, left: int) -> None:
self._left = left self._left = left
return return
# #
# Getters # Getters
# #
def wRef(self) -> str: def wRef(self) -> str:
return self._wref return self._wref
def text(self) -> str: def text(self) -> str:
return self._text return self._text
def font(self) -> QFont: def font(self) -> QFont:
return self._font return self._font
def audio(self) -> QUrl: def audio(self) -> QUrl:
return self._audio return self._audio
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) -> QMargins: def padding(self) -> QMargins:
return self._padding return self._padding
def border(self) -> QMargins: def border(self) -> QMargins:
return self._border return self._border
def margin(self) -> QMargins: def margin(self) -> QMargins:
return self._margin return self._margin
def position(self) -> QPoint: def position(self) -> QPoint:
return self._position return self._position
def borderRect(self) -> QRect: def borderRect(self) -> QRect:
return self._borderRect return self._borderRect
def clickRect(self) -> QRect: def clickRect(self) -> QRect:
return self._clickRect return self._clickRect
def color(self) -> QColor: def color(self) -> QColor:
return self._color return self._color
def asis(self) -> bool: def asis(self) -> bool:
return self._asis return self._asis
def left(self) -> int: def left(self) -> int:
return self._left return self._left
API = "https://api.dictionaryapi.dev/api/v2/entries/en/{word}" API = "https://api.dictionaryapi.dev/api/v2/entries/en/{word}"
MWAPI = "https://www.dictionaryapi.com/api/v3/references/collegiate/json/{word}?key=51d9df34-ee13-489e-8656-478c215e846c" MWAPI = "https://www.dictionaryapi.com/api/v3/references/collegiate/json/{word}?key=51d9df34-ee13-489e-8656-478c215e846c"
@@ -280,21 +328,22 @@ MWAPI = "https://www.dictionaryapi.com/api/v3/references/collegiate/json/{word}?
class Word: class Word:
"""All processing of a dictionary word.""" """All processing of a dictionary word."""
_words: dict[str, Any] = {} _words: dict[str, Any] = {}
class Line: class Line:
def __init__(self) -> None: def __init__(self) -> None:
self._maxHeight = -1 self._maxHeight = -1
self._baseLine = -1 self._baseLine = -1
self._leading = -1 self._leading = -1
self._fragments:list[Fragment] = [] self._fragments: list[Fragment] = []
return return
def __repr__(self) -> str: def __repr__(self) -> str:
return '|'.join([x.text() for x in self._fragments])+f'|{self._maxHeight}' return (
"|".join([x.text() for x in self._fragments])
+ f"|{self._maxHeight}"
)
def repaintEvent(self, painter: QPainter) -> int: def repaintEvent(self, painter: QPainter) -> int:
# #
# we do not have an event field because we are not a true widget # we do not have an event field because we are not a true widget
@@ -320,12 +369,12 @@ class Word:
smallCaps = QFont(frag.font()) smallCaps = QFont(frag.font())
smallCaps.setCapitalization(QFont.Capitalization.SmallCaps) 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))
results: list[Fragment] = [] results: list[Fragment] = []
while True: while True:
text = frag.text() text = frag.text()
start = text.find('{') start = text.find("{")
if start < 0: if start < 0:
results.append(frag) results.append(frag)
return results return results
@@ -342,84 +391,107 @@ class Word:
# #
# If the token is an end-token, return now. # If the token is an end-token, return now.
# #
if text.startswith('{/'): if text.startswith("{/"):
results.append(frag) results.append(frag)
return results return results
# #
# extract this token # extract this token
# #
end = text.find('}') end = text.find("}")
token = text[1:end] token = text[1:end]
frag.setText(text[end+1:]) frag.setText(text[end + 1 :])
newFrag = copy.copy(frag) newFrag = copy.copy(frag)
oldFont = QFont(frag.font()) oldFont = QFont(frag.font())
if token == 'bc': if token == "bc":
results.append(Fragment(': ', bold, color=QColor('#fff'))) results.append(Fragment(": ", bold, color=QColor("#fff")))
continue continue
if token in ['b', 'inf', 'it', 'sc', 'sup', 'phrase', 'parahw', 'gloss', if token in [
'qword', 'wi', 'dx', 'dx_def', 'dx_ety', 'ma']: "b",
if token == 'b': "inf",
"it",
"sc",
"sup",
"phrase",
"parahw",
"gloss",
"qword",
"wi",
"dx",
"dx_def",
"dx_ety",
"ma",
]:
if token == "b":
frag.setFont(bold) frag.setFont(bold)
elif token in ['it', 'qword', 'wi']: elif token in ["it", "qword", "wi"]:
frag.setFont(italic) frag.setFont(italic)
elif token == 'sc': elif token == "sc":
frag.setFont(smallCaps) frag.setFont(smallCaps)
elif token in ['inf', 'sup']: elif token in ["inf", "sup"]:
frag.setFont(script) frag.setFont(script)
elif token == 'phrase': elif token == "phrase":
font = QFont(bold) font = QFont(bold)
font.setItalic(True) font.setItalic(True)
frag.setFont(font) frag.setFont(font)
elif token == 'parahw': elif token == "parahw":
font = QFont(smallCaps) font = QFont(smallCaps)
font.setWeight(QFont.Weight.Bold) font.setWeight(QFont.Weight.Bold)
frag.setFont(font) frag.setFont(font)
elif token == 'gloss': elif token == "gloss":
frag.setText('[' + frag.text()) frag.setText("[" + frag.text())
elif token in ['dx', 'dx_ety']: elif token in ["dx", "dx_ety"]:
frag.setText('\u2014'+frag.text()) frag.setText("\u2014" + frag.text())
elif token == 'ma': elif token == "ma":
frag.setText('\u2014 more at '+frag.text()) frag.setText("\u2014 more at " + frag.text())
elif token == 'dx_def': elif token == "dx_def":
frag.setText('('+frag.text()) frag.setText("(" + frag.text())
else: else:
raise Exception(f"Unknown block marker: {token}") raise Exception(f"Unknown block marker: {token}")
results += self.parseText(frag) results += self.parseText(frag)
frag = results.pop() frag = results.pop()
frag.setFont(oldFont) frag.setFont(oldFont)
text = frag.text() text = frag.text()
if not text.startswith('{/'+token+'}'): if not text.startswith("{/" + token + "}"):
raise Exception(f"No matching close for {token} in {org}") raise Exception(
if token == 'gloss': f"No matching close for {token} in {org}"
results[-1].setText(results[-1].text() + ']') )
elif token == 'dx_def': if token == "gloss":
results[-1].setText(results[-1].text() + ')') results[-1].setText(results[-1].text() + "]")
end = text.find('}') elif token == "dx_def":
text = text[end+1:] results[-1].setText(results[-1].text() + ")")
end = text.find("}")
text = text[end + 1 :]
frag.setText(text) frag.setText(text)
continue continue
# #
# These are codes that include all information within the token # These are codes that include all information within the token
# #
fields = token.split('|') fields = token.split("|")
token = fields[0] token = fields[0]
if token in [ 'a_line', 'd_link', 'dxt', 'et_link', 'i_link', if token in [
'mat', 'sx']: "a_line",
wref = '' "d_link",
"dxt",
"et_link",
"i_link",
"mat",
"sx",
]:
wref = ""
htext = fields[1] htext = fields[1]
oldFont = QFont(frag.font()) oldFont = QFont(frag.font())
if token == 'a_link': if token == "a_link":
wref = fields[1] wref = fields[1]
elif token in ['d_link', 'et_link', 'mat', 'sx', 'i_link']: elif token in ["d_link", "et_link", "mat", "sx", "i_link"]:
if fields[2] == '': if fields[2] == "":
wref = fields[1] wref = fields[1]
else: else:
wref = fields[2] wref = fields[2]
if token == 'i_link': if token == "i_link":
frag.setFont(italic) frag.setFont(italic)
elif token == 'i_link': elif token == "i_link":
if fields[2] == '': if fields[2] == "":
wref = fields[1] wref = fields[1]
else: else:
wref = fields[2] wref = fields[2]
@@ -432,14 +504,18 @@ class Word:
frag.setFont(oldFont) frag.setFont(oldFont)
text = frag.text() text = frag.text()
continue continue
raise Exception(f"Unable to locate a known token {token} in {org}") raise Exception(
f"Unable to locate a known token {token} in {org}"
)
def addFragment(
def addFragment(self, frag: Fragment,) -> None: self,
frag: Fragment,
) -> None:
SPEAKER = "\U0001F508" SPEAKER = "\U0001F508"
if frag.audio().isValid(): if frag.audio().isValid():
frag.setText(frag.text() + ' ' + SPEAKER) frag.setText(frag.text() + " " + SPEAKER)
text = frag.text() text = frag.text()
text = re.sub(r"\*", "\u2022", text) text = re.sub(r"\*", "\u2022", text)
@@ -447,14 +523,14 @@ class Word:
text = re.sub(r"\{rdquo\}", "\u201d", text) text = re.sub(r"\{rdquo\}", "\u201d", text)
frag.setText(text) frag.setText(text)
if frag.audio().isValid(): if frag.audio().isValid():
frag.setPadding(3,0,0,5) frag.setPadding(3, 0, 0, 5)
frag.setBorder(1) frag.setBorder(1)
frag.setMargin(0,0,0,0) frag.setMargin(0, 0, 0, 0)
items = self.parseText(frag) items = self.parseText(frag)
self._fragments += items self._fragments += items
return return
def finalizeLine(self, width: int, base:int ) -> None: def finalizeLine(self, width: int, base: int) -> None:
"""Create all of the positions for all the fragments.""" """Create all of the positions for all the fragments."""
# #
# Find the maximum hight and max baseline # Find the maximum hight and max baseline
@@ -486,8 +562,12 @@ class Word:
# #
size = frag.size(width) size = frag.size(width)
fm = QFontMetrics(frag.font()) fm = QFontMetrics(frag.font())
offset = frag.margin().left() + frag.border().left() + frag.padding().left() offset = (
frag.setPosition(QPoint(x+offset, self._baseLine)) frag.margin().left()
+ frag.border().left()
+ frag.padding().left()
)
frag.setPosition(QPoint(x + offset, self._baseLine))
if not frag.border().isNull() or not frag.wRef(): if not frag.border().isNull() or not frag.wRef():
# #
# self._baseLine is where the text will be drawn # self._baseLine is where the text will be drawn
@@ -497,16 +577,16 @@ class Word:
# + fm.descent - rect.height # + fm.descent - rect.height
# The border is drawn at top-padding-border-margin+marin # The border is drawn at top-padding-border-margin+marin
# #
top = self._baseLine + fm.descent() - fm.height() top = self._baseLine + fm.descent() - fm.height()
y = top - frag.padding().top() - frag.border().top() y = top - frag.padding().top() - frag.border().top()
pos = QPoint(x, y) pos = QPoint(x, y)
rect = QRect(pos, size.shrunkBy(frag.margin())) rect = QRect(pos, size.shrunkBy(frag.margin()))
frag.setBorderRect(rect) frag.setBorderRect(rect)
pos.setY(pos.y()+base) pos.setY(pos.y() + base)
frag.setClickRect(QRect(pos, size.shrunkBy(frag.margin()))) frag.setClickRect(QRect(pos, size.shrunkBy(frag.margin())))
x += size.width() x += size.width()
return return
def getLine(self) -> list[Fragment]: def getLine(self) -> list[Fragment]:
return self._fragments return self._fragments
@@ -532,9 +612,9 @@ class Word:
query_error(query) query_error(query)
if query.next(): if query.next():
Word._words[word] = { Word._words[word] = {
'word': word, "word": word,
'source': query.value('source'), "source": query.value("source"),
'definition': json.loads(query.value("definition")), "definition": json.loads(query.value("definition")),
} }
self.current = Word._words[word] self.current = Word._words[word]
return return
@@ -556,30 +636,30 @@ class Word:
data = json.loads(content.data().decode("utf-8")) data = json.loads(content.data().decode("utf-8"))
print(data) print(data)
self._words[word] = { self._words[word] = {
'word': word, "word": word,
'source': source, "source": source,
'definition': data, "definition": data,
} }
self.current = Word._words[word] self.current = Word._words[word]
query.prepare( query.prepare(
"INSERT INTO words " "INSERT INTO words "
"(word, source, definition) " "(word, source, definition) "
"VALUES (:word, :source, :definition)" "VALUES (:word, :source, :definition)"
) )
query.bindValue(":word", self.current['word']) query.bindValue(":word", self.current["word"])
query.bindValue(":source", self.current['source']) query.bindValue(":source", self.current["source"])
query.bindValue(":definition", json.dumps(self.current['definition'])) query.bindValue(":definition", json.dumps(self.current["definition"]))
if not query.exec(): if not query.exec():
query_error(query) query_error(query)
return return
def getWord(self) -> str: def getWord(self) -> str:
return self.current['word'] return self.current["word"]
def get_html(self) -> str | None: def get_html(self) -> str | None:
if self.current['source'] == 'mw': if self.current["source"] == "mw":
return self.mw_html() return self.mw_html()
elif self.current['source'] == 'apidictionary': elif self.current["source"] == "apidictionary":
return self.apidictionary_html() return self.apidictionary_html()
else: else:
raise Exception(f"Unknown source: {self.current['source']}") raise Exception(f"Unknown source: {self.current['source']}")
@@ -603,170 +683,186 @@ class Word:
headerFont.setWeight(QFont.Weight.Bold) headerFont.setWeight(QFont.Weight.Bold)
boldFont.setBold(True) boldFont.setBold(True)
italicFont.setItalic(True) italicFont.setItalic(True)
phonicFont = QFontDatabase.font("Gentium", None, 10) phonicFont = QFontDatabase.font("Gentium", None, 10)
phonicFont.setPixelSize(20) phonicFont.setPixelSize(20)
self.resources = { self.resources = {
'colors': { "colors": {
'base':QColor(Qt.GlobalColor.white), "base": QColor(Qt.GlobalColor.white),
'blue': QColor("#4a7d95"), "blue": QColor("#4a7d95"),
}, },
'fonts': { "fonts": {
'header': headerFont, "header": headerFont,
'label': labelFont, "label": labelFont,
'phonic': phonicFont, "phonic": phonicFont,
'bold': boldFont, "bold": boldFont,
'italic': italicFont, "italic": italicFont,
'text': textFont, "text": textFont,
} },
} }
if self.current['source'] == 'mw': if self.current["source"] == "mw":
return self.mw_def() return self.mw_def()
elif self.current['source'] == 'apidictionary': elif self.current["source"] == "apidictionary":
return None return None
else: else:
raise Exception(f"Unknown source: {self.current['source']}") raise Exception(f"Unknown source: {self.current['source']}")
def mw_def(self) -> list[Line]: def mw_def(self) -> list[Line]:
lines: list[Word.Line] = [] lines: list[Word.Line] = []
for entry in self.current['definition']: for entry in self.current["definition"]:
line = Word.Line()
meta = json.dumps(entry['meta'])
line.addFragment(
Fragment(
meta,
self.resources['fonts']['text'],asis=True
)
)
lines.append(line)
lines += self.mw_def_entry(entry) lines += self.mw_def_entry(entry)
self._lines = lines self._lines = lines
return lines return lines
def mw_seq(self, seq: list[Any]) -> list[Line]: def mw_seq(self, seq: list[Any]) -> list[Line]:
lines: list[Word.Line] = [] lines: list[Word.Line] = []
outer = ' ' outer = " "
inner = ' ' inner = " "
for value in seq: for value in seq:
sense = value[1] sense = value[1]
# #
# The optional 'sn' field tells us what sort of labeling to do # The optional 'sn' field tells us what sort of labeling to do
# #
sn = sense.get('sn', '') sn = sense.get("sn", "")
sns = sn.split(' ') sns = sn.split(" ")
if len(sns) == 2: if len(sns) == 2:
outer = sns[0] outer = sns[0]
inner = sns[1] inner = sns[1]
elif len(sns) == 1: elif len(sns) == 1:
if inner == ' ': if inner == " ":
outer = sns[0] outer = sns[0]
else: else:
inner = sns[0] inner = sns[0]
for dt in sense['dt']: for dt in sense["dt"]:
if dt[0] == 'text': if dt[0] == "text":
line = Word.Line() line = Word.Line()
frag = Fragment( frag = Fragment(
f"{outer} {inner} ", f"{outer} {inner} ",
self.resources['fonts']['bold'], self.resources["fonts"]["bold"],
color = self.resources['colors']['base'] color=self.resources["colors"]["base"],
) )
outer = ' ' outer = " "
frag.setLeft(10) frag.setLeft(10)
line.addFragment(frag) line.addFragment(frag)
frag = Fragment( frag = Fragment(
dt[1], dt[1],
self.resources['fonts']['text'], self.resources["fonts"]["text"],
color = self.resources['colors']['base'] color=self.resources["colors"]["base"],
) )
frag.setLeft(30) frag.setLeft(30)
line.addFragment(frag) line.addFragment(frag)
lines.append(line) lines.append(line)
elif dt[0] == 'vis': elif dt[0] == "vis":
for vis in dt[1]: for vis in dt[1]:
line = Word.Line() line = Word.Line()
frag =Fragment(f" ", frag = Fragment(
self.resources['fonts']['bold'], f" ",
) self.resources["fonts"]["bold"],
)
frag.setLeft(45) frag.setLeft(45)
line.addFragment(frag) line.addFragment(frag)
line.addFragment( line.addFragment(
Fragment(vis['t'], Fragment(
self.resources['fonts']['text'], vis["t"],
color = QColor('#aaa') self.resources["fonts"]["text"],
) color=QColor("#aaa"),
)
) )
lines.append(line) lines.append(line)
return lines return lines
def mw_def_entry(self, entry) -> list[Line]: def mw_def_entry(self, entry) -> list[Line]:
# #
# Easy reference to colors # Easy reference to colors
# #
base = self.resources['colors']['base'] base = self.resources["colors"]["base"]
blue = self.resources['colors']['blue'] blue = self.resources["colors"]["blue"]
lines: list[Word.Line] = [] lines: list[Word.Line] = []
line = Word.Line() line = Word.Line()
hw = re.sub(r'\*', '', entry['hwi']['hw']) hw = re.sub(r"\*", "", entry["hwi"]["hw"])
frag = Fragment(hw, self.resources['fonts']['header'], color=base) frag = Fragment(hw, self.resources["fonts"]["header"], color=base)
line.addFragment(frag) line.addFragment(frag)
frag = Fragment(' '+entry["fl"], self.resources['fonts']['label'], color=blue) frag = Fragment(
" " + entry["fl"], self.resources["fonts"]["label"], color=blue
)
line.addFragment(frag) line.addFragment(frag)
lines.append(line) lines.append(line)
if "vrs" in entry.keys(): if "vrs" in entry.keys():
line = self.Line() line = self.Line()
space = '' space = ""
for vrs in entry["vrs"]: for vrs in entry["vrs"]:
frag = Fragment(space + vrs["va"], self.resources['fonts']['label'], color=base) frag = Fragment(
space = ' ' space + vrs["va"],
self.resources["fonts"]["label"],
color=base,
)
space = " "
line.addFragment(frag) line.addFragment(frag)
lines.append(line) lines.append(line)
if "prs" in entry["hwi"].keys(): if "prs" in entry["hwi"].keys():
line = self.Line() line = self.Line()
frag = Fragment(entry['hwi']['hw'] + ' ', self.resources['fonts']['phonic'], color=base) frag = Fragment(
entry["hwi"]["hw"] + " ",
self.resources["fonts"]["phonic"],
color=base,
)
line.addFragment(frag) line.addFragment(frag)
for prs in entry["hwi"]["prs"]: for prs in entry["hwi"]["prs"]:
audio = self.mw_sound_url(prs) audio = self.mw_sound_url(prs)
if audio is None: if audio is None:
audio = "" audio = ""
frag = Fragment(prs['mw'], self.resources['fonts']['phonic'], color=blue) frag = Fragment(
prs["mw"], self.resources["fonts"]["phonic"], color=blue
)
frag.setAudio(audio) frag.setAudio(audio)
line.addFragment(frag) line.addFragment(frag)
lines.append(line) lines.append(line)
if "ins" in entry.keys(): if "ins" in entry.keys():
line = self.Line() line = self.Line()
space = '' space = ""
for ins in entry['ins']: for ins in entry["ins"]:
try: try:
frag = Fragment(ins['il'], self.resources['fonts']['text'], color=base) frag = Fragment(
ins["il"], self.resources["fonts"]["text"], color=base
)
line.addFragment(frag) line.addFragment(frag)
space = ' ' space = " "
except KeyError: except KeyError:
pass pass
frag = Fragment(space + ins['if'], self.resources['fonts']['bold'], color=base) frag = Fragment(
space + ins["if"],
self.resources["fonts"]["bold"],
color=base,
)
line.addFragment(frag) line.addFragment(frag)
space = '; ' space = "; "
lines.append(line) lines.append(line)
if 'lbs' in entry.keys(): if "lbs" in entry.keys():
line = self.Line() line = self.Line()
frag = Fragment('; '.join(entry['lbs']), self.resources['fonts']['bold'], color=base) frag = Fragment(
"; ".join(entry["lbs"]),
self.resources["fonts"]["bold"],
color=base,
)
line.addFragment(frag) line.addFragment(frag)
lines.append(line) lines.append(line)
for value in entry['def']: # has multiple 'sseg' or 'vd' init for value in entry["def"]: # has multiple 'sseg' or 'vd' init
for k,v in value.items(): for k, v in value.items():
if k == 'sseq': # has multiple 'senses' if k == "sseq": # has multiple 'senses'
for seq in v: for seq in v:
r = self.mw_seq(seq) r = self.mw_seq(seq)
lines += r lines += r
elif k == 'vd': elif k == "vd":
line = self.Line() line = self.Line()
line.addFragment(Fragment( line.addFragment(
v, Fragment(
self.resources['fonts']['italic'], v, self.resources["fonts"]["italic"], color=blue
color=blue )
)) )
lines.append(line) lines.append(line)
return lines return lines
@@ -867,13 +963,13 @@ class Definition(QWidget):
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)
self._word:str = w.getWord() self._word: str = w.getWord()
lines = w.get_def() lines = w.get_def()
assert lines is not None assert lines is not None
self._lines = lines self._lines = lines
self._buttons:list[Fragment] = [] self._buttons: list[Fragment] = []
base = 0 base = 0
for line in self._lines: for line in self._lines:
line.finalizeLine(self.width(), base) line.finalizeLine(self.width(), base)
for frag in line.getLine(): for frag in line.getLine():
@@ -889,18 +985,18 @@ class Definition(QWidget):
def resizeEvent(self, event: QResizeEvent) -> None: def resizeEvent(self, event: QResizeEvent) -> None:
base = 0 base = 0
for line in self._lines: for line in self._lines:
line.finalizeLine(self.width(),base) line.finalizeLine(self.width(), base)
base += line.getLineSpacing() base += line.getLineSpacing()
self.setFixedHeight(base) self.setFixedHeight(base)
super(Definition,self).resizeEvent(event) super(Definition, self).resizeEvent(event)
return return
_downFrag: Optional[Fragment|None] = None _downFrag: Optional[Fragment | None] = None
def mousePressEvent(self, event: Optional[QMouseEvent]) -> None: def mousePressEvent(self, event: Optional[QMouseEvent]) -> None:
if not event: if not event:
return super().mousePressEvent(event) return super().mousePressEvent(event)
print(f'mousePressEvent: {event.pos()}') print(f"mousePressEvent: {event.pos()}")
for frag in self._buttons: for frag in self._buttons:
rect = frag.clickRect() rect = frag.clickRect()
if rect.contains(event.pos()): if rect.contains(event.pos()):
@@ -911,11 +1007,13 @@ class Definition(QWidget):
def mouseReleaseEvent(self, event: Optional[QMouseEvent]) -> None: def mouseReleaseEvent(self, event: Optional[QMouseEvent]) -> None:
if not event: if not event:
return super().mouseReleaseEvent(event) return super().mouseReleaseEvent(event)
if self._downFrag is not None and self._downFrag.clickRect().contains(event.pos()): if self._downFrag is not None and self._downFrag.clickRect().contains(
event.pos()
):
audio = self._downFrag.audio().url() audio = self._downFrag.audio().url()
print(audio) print(audio)
self.pronounce.emit(audio) self.pronounce.emit(audio)
print('emit done') print("emit done")
self._downFrag = None self._downFrag = None
return return
self._downFrag = None self._downFrag = None
@@ -945,13 +1043,12 @@ class Definition(QWidget):
painter.restore() painter.restore()
return return
class DefinitionArea(QScrollArea): class DefinitionArea(QScrollArea):
def __init__(self, w: Word, *args: Any, **kwargs: Any) -> None: def __init__(self, w: Word, *args: Any, **kwargs: Any) -> None:
super(DefinitionArea,self).__init__(*args,*kwargs) super(DefinitionArea, self).__init__(*args, *kwargs)
d = Definition(w) d = Definition(w)
self.setWidget(d) self.setWidget(d)
self.setWidgetResizable(True) self.setWidgetResizable(True)
self.setVerticalScrollBarPolicy( self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
Qt.ScrollBarPolicy.ScrollBarAlwaysOn
)
return return