Almost working version of words
This commit is contained in:
13
deftest.py
13
deftest.py
@@ -1,15 +1,17 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
from PyQt6.QtCore import QResource
|
from PyQt6.QtCore import QResource
|
||||||
from PyQt6.QtGui import QFontDatabase
|
from PyQt6.QtGui import QFontDatabase
|
||||||
from PyQt6.QtSql import QSqlDatabase, QSqlQuery
|
from PyQt6.QtSql import QSqlDatabase, QSqlQuery
|
||||||
from PyQt6.QtWidgets import QApplication
|
from PyQt6.QtWidgets import QApplication
|
||||||
|
|
||||||
from lib import Definition, Word
|
from lib import DefinitionArea, Word
|
||||||
from lib.sounds import SoundOff
|
from lib.sounds import SoundOff
|
||||||
from lib.utils import query_error
|
from lib.utils import query_error
|
||||||
|
from lib.words import Definition
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
@@ -32,14 +34,17 @@ def main() -> int:
|
|||||||
query = QSqlQuery()
|
query = QSqlQuery()
|
||||||
if not query.exec(
|
if not query.exec(
|
||||||
"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)"
|
||||||
):
|
):
|
||||||
query_error(query)
|
query_error(query)
|
||||||
|
|
||||||
word = Word("boat")
|
word = Word("boat")
|
||||||
snd = SoundOff()
|
snd = SoundOff()
|
||||||
widget = Definition(word) # noqa: F841
|
widget = DefinitionArea(word) # xnoqa: F841
|
||||||
widget.pronounce.connect(snd.playSound)
|
d = cast(Definition,widget.widget())
|
||||||
|
assert d is not None
|
||||||
|
d.pronounce.connect(snd.playSound)
|
||||||
widget.show()
|
widget.show()
|
||||||
return app.exec()
|
return app.exec()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
# pyright: ignore
|
||||||
from .utils import query_error # isort: skip
|
from .utils import query_error # isort: skip
|
||||||
from .books import Book
|
from .books import Book
|
||||||
from .person import PersonDialog
|
from .person import PersonDialog
|
||||||
from .read import ReadDialog
|
from .read import ReadDialog
|
||||||
from .session import SessionDialog
|
from .session import SessionDialog
|
||||||
|
from .words import Definition, Word, DefinitionArea
|
||||||
|
|||||||
359
lib/words.py
359
lib/words.py
@@ -1,10 +1,10 @@
|
|||||||
import copy
|
import copy
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
from typing import Any, Dict, Optional, Self
|
from typing import Any, Optional, Self
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from PyQt6.QtCore import QPoint, QRect, QUrl, Qt, pyqtSignal
|
from PyQt6.QtCore import QPoint, QRect, QSize, QUrl, Qt, pyqtSignal
|
||||||
from PyQt6.QtGui import (
|
from PyQt6.QtGui import (
|
||||||
QBrush,
|
QBrush,
|
||||||
QColor,
|
QColor,
|
||||||
@@ -14,11 +14,12 @@ from PyQt6.QtGui import (
|
|||||||
QMouseEvent,
|
QMouseEvent,
|
||||||
QPainter,
|
QPainter,
|
||||||
QPaintEvent,
|
QPaintEvent,
|
||||||
|
QResizeEvent,
|
||||||
QTextOption,
|
QTextOption,
|
||||||
QTransform,
|
QTransform,
|
||||||
)
|
)
|
||||||
from PyQt6.QtSql import QSqlQuery
|
from PyQt6.QtSql import QSqlQuery
|
||||||
from PyQt6.QtWidgets import QWidget
|
from PyQt6.QtWidgets import QScrollArea, QScrollBar, QSizePolicy, QWidget
|
||||||
|
|
||||||
from lib import query_error
|
from lib import query_error
|
||||||
|
|
||||||
@@ -28,8 +29,8 @@ 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, Any] = {}
|
||||||
_current: Dict[str, Any]
|
_current: dict[str, Any] = {}
|
||||||
_currentWord: str
|
_currentWord: str
|
||||||
|
|
||||||
class Fragment:
|
class Fragment:
|
||||||
@@ -50,6 +51,8 @@ class Word:
|
|||||||
_position: QPoint # where to drawText
|
_position: QPoint # where to drawText
|
||||||
_borderRect: QRect # where to drawRect
|
_borderRect: QRect # where to drawRect
|
||||||
_radius: int # Radius for rounded rects
|
_radius: int # Radius for rounded rects
|
||||||
|
_asis: bool = False
|
||||||
|
_left: int = 0
|
||||||
|
|
||||||
|
|
||||||
TYPES = [ 'text', 'span', 'button' ]
|
TYPES = [ 'text', 'span', 'button' ]
|
||||||
@@ -58,7 +61,8 @@ class Word:
|
|||||||
font:QFont,
|
font:QFont,
|
||||||
t:str = 'text',
|
t:str = 'text',
|
||||||
audio:str = '',
|
audio:str = '',
|
||||||
color: QColor = None
|
color: Optional[QColor] = None,
|
||||||
|
asis: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
if t not in self.TYPES:
|
if t not in self.TYPES:
|
||||||
raise Exception(f"Unknown fragment type{t}")
|
raise Exception(f"Unknown fragment type{t}")
|
||||||
@@ -80,7 +84,10 @@ class Word:
|
|||||||
self._color = color
|
self._color = color
|
||||||
else:
|
else:
|
||||||
self._color = QColor()
|
self._color = QColor()
|
||||||
|
self._asis = asis
|
||||||
return
|
return
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self._text
|
||||||
#
|
#
|
||||||
# Setters
|
# Setters
|
||||||
#
|
#
|
||||||
@@ -182,6 +189,9 @@ class Word:
|
|||||||
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:
|
||||||
|
self._left = left
|
||||||
|
return
|
||||||
#
|
#
|
||||||
# Getters
|
# Getters
|
||||||
#
|
#
|
||||||
@@ -211,6 +221,10 @@ class Word:
|
|||||||
return self._borderRect
|
return self._borderRect
|
||||||
def color(self) -> QColor:
|
def color(self) -> QColor:
|
||||||
return self._color
|
return self._color
|
||||||
|
def asis(self) -> bool:
|
||||||
|
return self._asis
|
||||||
|
def left(self) -> int:
|
||||||
|
return self._left
|
||||||
|
|
||||||
class Line:
|
class Line:
|
||||||
|
|
||||||
@@ -226,9 +240,13 @@ class Word:
|
|||||||
self._fragments = []
|
self._fragments = []
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return '|'.join([x.text() for x in self._fragments])+f'|{self._maxHeight}'
|
||||||
|
|
||||||
def parseText(self, frag: 'Word.Fragment') -> list['Word.Fragment']:
|
def parseText(self, frag: 'Word.Fragment') -> list['Word.Fragment']:
|
||||||
org = frag.text()
|
org = frag.text()
|
||||||
print(org)
|
if frag.asis():
|
||||||
|
return [frag]
|
||||||
#
|
#
|
||||||
# Needed Fonts
|
# Needed Fonts
|
||||||
#
|
#
|
||||||
@@ -272,13 +290,12 @@ class Word:
|
|||||||
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(Word.Fragment(': ', bold))
|
results.append(Word.Fragment(': ', bold, color=QColor('#fff')))
|
||||||
continue
|
continue
|
||||||
if token in ['b', 'inf', 'it', 'sc', 'sup', 'phrase', 'parahw', 'gloss',
|
if token in ['b', 'inf', 'it', 'sc', 'sup', 'phrase', 'parahw', 'gloss',
|
||||||
'qword', 'wi', 'dx', 'dx_def', 'dx_ety', 'ma']:
|
'qword', 'wi', 'dx', 'dx_def', 'dx_ety', 'ma']:
|
||||||
frag.setText(text)
|
|
||||||
if token == 'b':
|
if token == 'b':
|
||||||
frag.setFont(bold)
|
frag.setFont(bold)
|
||||||
elif token in ['it', 'qword', 'wi']:
|
elif token in ['it', 'qword', 'wi']:
|
||||||
@@ -374,7 +391,7 @@ class Word:
|
|||||||
self._fragments += items
|
self._fragments += items
|
||||||
return
|
return
|
||||||
|
|
||||||
def finalizeLine(self, width:int) -> None:
|
def finalizeLine(self, maxWidth: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
|
||||||
@@ -386,23 +403,23 @@ class Word:
|
|||||||
fm = QFontMetrics(frag.font())
|
fm = QFontMetrics(frag.font())
|
||||||
rect = fm.boundingRect(frag.text(), frag.align())
|
rect = fm.boundingRect(frag.text(), frag.align())
|
||||||
height = rect.height()
|
height = rect.height()
|
||||||
baseLine = height - fm.descent()
|
bl = height - fm.descent()
|
||||||
#
|
#
|
||||||
# Add the padding, border and margin to adjust the baseline and height
|
# Add the padding, border and margin to adjust the baseline and height
|
||||||
#
|
#
|
||||||
b = frag.padding()
|
b = frag.padding()
|
||||||
height += b[0] + b[2]
|
height += b[0] + b[2]
|
||||||
baseLine += b[2]
|
bl += b[2]
|
||||||
b = frag.border()
|
b = frag.border()
|
||||||
height += b[0] + b[2]
|
height += b[0] + b[2]
|
||||||
baseLine += b[2]
|
bl += b[2]
|
||||||
b = frag.margin()
|
b = frag.margin()
|
||||||
height += b[0] + b[2]
|
height += b[0] + b[2]
|
||||||
baseLine += b[2]
|
bl += b[2]
|
||||||
if height > maxHeight:
|
if height > maxHeight:
|
||||||
maxHeight = height
|
maxHeight = height
|
||||||
if baseLine > baseLine:
|
if bl > baseLine:
|
||||||
baseLine = baseLine
|
baseLine = bl
|
||||||
self._baseLine = baseLine
|
self._baseLine = baseLine
|
||||||
self._maxHeight = maxHeight
|
self._maxHeight = maxHeight
|
||||||
self._leading = 0 # XXX - How should this be calculated?
|
self._leading = 0 # XXX - How should this be calculated?
|
||||||
@@ -410,10 +427,11 @@ class Word:
|
|||||||
for frag in self._fragments:
|
for frag in self._fragments:
|
||||||
#
|
#
|
||||||
# TODO - Wordwrap
|
# TODO - Wordwrap
|
||||||
# TODO - indent
|
#
|
||||||
|
if x < frag.left():
|
||||||
|
x = frag.left()
|
||||||
fm = QFontMetrics(frag.font())
|
fm = QFontMetrics(frag.font())
|
||||||
rect = fm.boundingRect(frag.text())
|
width = fm.horizontalAdvance(frag.text())
|
||||||
width = rect.width()
|
|
||||||
padding = frag.padding()
|
padding = frag.padding()
|
||||||
offset = padding[3] # Left margin
|
offset = padding[3] # Left margin
|
||||||
width += padding[1] + padding[3]
|
width += padding[1] + padding[3]
|
||||||
@@ -436,6 +454,8 @@ class Word:
|
|||||||
top = self._baseLine + fm.descent() - rect.height() -1
|
top = self._baseLine + fm.descent() - rect.height() -1
|
||||||
y = top - padding[0] - border[0]
|
y = top - padding[0] - border[0]
|
||||||
frag.setBorderRect(QRect(x+margin[3], y, width, height))
|
frag.setBorderRect(QRect(x+margin[3], y, width, height))
|
||||||
|
if x + width > maxWidth:
|
||||||
|
print(f'Wrap text: {frag.text()}, {x}+{width} = {x + width}')
|
||||||
x += width
|
x += width
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -454,7 +474,14 @@ class Word:
|
|||||||
return cls._instance
|
return cls._instance
|
||||||
|
|
||||||
def __init__(self, word: str) -> None:
|
def __init__(self, word: str) -> None:
|
||||||
self._currentWord = word
|
#
|
||||||
|
# reset the current definition
|
||||||
|
#
|
||||||
|
try:
|
||||||
|
if word != self._current['word']:
|
||||||
|
self._lines = []
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
#
|
#
|
||||||
# Have we already retrieved this word?
|
# Have we already retrieved this word?
|
||||||
#
|
#
|
||||||
@@ -469,130 +496,240 @@ class Word:
|
|||||||
if not query.exec():
|
if not query.exec():
|
||||||
query_error(query)
|
query_error(query)
|
||||||
if query.next():
|
if query.next():
|
||||||
self._words[word] = query.value("definition")
|
self._words[word] = {
|
||||||
self._current = json.loads(self._words[word])
|
'word': word,
|
||||||
|
'source': query.value('source'),
|
||||||
|
'definition': json.loads(query.value("definition")),
|
||||||
|
}
|
||||||
|
self._current = self._words[word]
|
||||||
return
|
return
|
||||||
|
source = 'mw'
|
||||||
response = requests.get(MWAPI.format(word=word))
|
response = requests.get(MWAPI.format(word=word))
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
self._current = None
|
self._current = {}
|
||||||
return
|
return
|
||||||
data = json.loads(response.content.decode("utf-8"))
|
data = json.loads(response.content.decode("utf-8"))
|
||||||
#
|
print(data)
|
||||||
# XXX - The first entry should be the correct entry. There could be more
|
self._words[word] = {
|
||||||
# if there is a "hom" entry, then that will be appended to meta.id
|
'word': word,
|
||||||
# word = "lady", hom=1, meta.id = "lady:1";
|
'source': source,
|
||||||
#
|
'definition': data,
|
||||||
print(response.content.decode("utf-8"))
|
}
|
||||||
self._words[word] = json.dumps(data[0])
|
self._current = self._words[word]
|
||||||
self._current = data[0]
|
|
||||||
query.prepare(
|
query.prepare(
|
||||||
"INSERT INTO words "
|
"INSERT INTO words "
|
||||||
"(word, definition) "
|
"(word, source, definition) "
|
||||||
"VALUES (:word, :definition)"
|
"VALUES (:word, :source, :definition)"
|
||||||
)
|
)
|
||||||
query.bindValue(":word", word)
|
query.bindValue(":word", self._current['word'])
|
||||||
query.bindValue(":definition", self._words[word])
|
query.bindValue(":source", self._current['source'])
|
||||||
|
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 getCurrent(self) -> str:
|
def getCurrent(self) -> str:
|
||||||
assert self._currentWord is not None
|
return self._current['word']
|
||||||
return self._currentWord
|
|
||||||
|
|
||||||
def get_html(self) -> str | None:
|
def get_html(self) -> str | None:
|
||||||
if not self._current:
|
if self._current['source'] == 'mw':
|
||||||
return None
|
|
||||||
if "meta" in self._current.keys():
|
|
||||||
return self.mw_html()
|
return self.mw_html()
|
||||||
else:
|
elif self._current['source'] == 'apidictionary':
|
||||||
return self.apidictionary_html()
|
return self.apidictionary_html()
|
||||||
|
|
||||||
def get_def(self) -> list[Line] | None:
|
|
||||||
if not self._current:
|
|
||||||
return None
|
|
||||||
if "meta" in self._current.keys():
|
|
||||||
return self.mw_def()
|
|
||||||
else:
|
else:
|
||||||
return None
|
raise Exception(f"Unknown source: {self._current['source']}")
|
||||||
|
|
||||||
def mw_def(self) -> list[Line]:
|
_resources:dict[str,Any] = {}
|
||||||
|
def get_def(self) -> list[Line] | None:
|
||||||
if len(self._lines) > 0:
|
if len(self._lines) > 0:
|
||||||
return self._lines
|
return self._lines
|
||||||
assert self._current is not None
|
if len(self._resources.keys()) < 1:
|
||||||
line = self.Line()
|
#
|
||||||
#
|
# Colors we used
|
||||||
# Colors we used
|
#
|
||||||
#
|
headerFont = QFontDatabase.font("OpenDyslexic", None, 10)
|
||||||
base = QColor(Qt.GlobalColor.white)
|
headerFont.setPixelSize(48)
|
||||||
blue = QColor("#4a7d95")
|
labelFont = QFont(headerFont)
|
||||||
headerFont = QFontDatabase.font("OpenDyslexic", None, 10)
|
labelFont.setPixelSize(30)
|
||||||
headerFont.setPixelSize(48)
|
boldFont = QFont(headerFont)
|
||||||
headerFont.setWeight(QFont.Weight.Bold)
|
boldFont.setPixelSize(20)
|
||||||
labelFont = QFontDatabase.font("OpenDyslexic", None, 10)
|
textFont = QFont(boldFont)
|
||||||
labelFont.setPixelSize(30)
|
italicFont = QFont(boldFont)
|
||||||
phonicFont = QFontDatabase.font("Gentium", None, 10)
|
|
||||||
phonicFont.setPixelSize(20)
|
|
||||||
boldFont = QFontDatabase.font("OpenDyslexic", None, 10)
|
|
||||||
boldFont.setPixelSize(20)
|
|
||||||
boldFont.setBold(True)
|
|
||||||
textFont = QFontDatabase.font("OpenDyslexic", None, 10)
|
|
||||||
textFont.setPixelSize(20)
|
|
||||||
|
|
||||||
hw = re.sub(r'\*', '', self._current['hwi']['hw'])
|
headerFont.setWeight(QFont.Weight.Bold)
|
||||||
frag = Word.Fragment(hw, headerFont, color=base)
|
boldFont.setBold(True)
|
||||||
line.addFragment(frag)
|
italicFont.setItalic(True)
|
||||||
frag = Word.Fragment(' '+self._current["fl"], labelFont, color=blue)
|
|
||||||
line.addFragment(frag)
|
phonicFont = QFontDatabase.font("Gentium", None, 10)
|
||||||
self._lines.append(line)
|
phonicFont.setPixelSize(20)
|
||||||
|
|
||||||
|
self._resources = {
|
||||||
|
'colors': {
|
||||||
|
'base':QColor(Qt.GlobalColor.white),
|
||||||
|
'blue': QColor("#4a7d95"),
|
||||||
|
},
|
||||||
|
'fonts': {
|
||||||
|
'header': headerFont,
|
||||||
|
'label': labelFont,
|
||||||
|
'phonic': phonicFont,
|
||||||
|
'bold': boldFont,
|
||||||
|
'italic': italicFont,
|
||||||
|
'text': textFont,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if self._current['source'] == 'mw':
|
||||||
|
return self.mw_def()
|
||||||
|
elif self._current['source'] == 'apidictionary':
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
raise Exception(f"Unknown source: {self._current['source']}")
|
||||||
|
|
||||||
if "vrs" in self._current.keys():
|
def mw_def(self) -> list[Line]:
|
||||||
|
lines: list[Word.Line] = []
|
||||||
|
for entry in self._current['definition']:
|
||||||
|
line = Word.Line()
|
||||||
|
meta = json.dumps(entry['meta'])
|
||||||
|
line.addFragment(
|
||||||
|
Word.Fragment(
|
||||||
|
meta,
|
||||||
|
self._resources['fonts']['text'],asis=True
|
||||||
|
)
|
||||||
|
)
|
||||||
|
lines.append(line)
|
||||||
|
lines += self.mw_def_entry(entry)
|
||||||
|
self._lines = lines
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def mw_seq(self, seq: list[Any]) -> list[Line]:
|
||||||
|
lines: list[Word.Line] = []
|
||||||
|
outer = ' '
|
||||||
|
inner = ' '
|
||||||
|
for value in seq:
|
||||||
|
sense = value[1]
|
||||||
|
#
|
||||||
|
# The optional 'sn' field tells us what sort of labeling to do
|
||||||
|
#
|
||||||
|
sn = sense.get('sn', '')
|
||||||
|
sns = sn.split(' ')
|
||||||
|
if len(sns) == 2:
|
||||||
|
outer = sns[0]
|
||||||
|
inner = sns[1]
|
||||||
|
elif len(sns) == 1:
|
||||||
|
if inner == ' ':
|
||||||
|
outer = sns[0]
|
||||||
|
else:
|
||||||
|
inner = sns[0]
|
||||||
|
|
||||||
|
for dt in sense['dt']:
|
||||||
|
if dt[0] == 'text':
|
||||||
|
line = Word.Line()
|
||||||
|
frag = Word.Fragment(
|
||||||
|
f"{outer} {inner} ",
|
||||||
|
self._resources['fonts']['bold'],
|
||||||
|
color = self._resources['colors']['base']
|
||||||
|
)
|
||||||
|
outer = ' '
|
||||||
|
frag.setLeft(10)
|
||||||
|
line.addFragment(frag)
|
||||||
|
frag = Word.Fragment(
|
||||||
|
dt[1],
|
||||||
|
self._resources['fonts']['text'],
|
||||||
|
color = self._resources['colors']['base']
|
||||||
|
)
|
||||||
|
frag.setLeft(30)
|
||||||
|
line.addFragment(frag)
|
||||||
|
lines.append(line)
|
||||||
|
elif dt[0] == 'vis':
|
||||||
|
for vis in dt[1]:
|
||||||
|
line = Word.Line()
|
||||||
|
frag =Word.Fragment(f" ",
|
||||||
|
self._resources['fonts']['bold'],
|
||||||
|
)
|
||||||
|
frag.setLeft(45)
|
||||||
|
line.addFragment(frag)
|
||||||
|
line.addFragment(
|
||||||
|
Word.Fragment(vis['t'],
|
||||||
|
self._resources['fonts']['text'],
|
||||||
|
color = QColor('#aaa')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
lines.append(line)
|
||||||
|
return lines
|
||||||
|
def mw_def_entry(self, entry) -> list[Line]:
|
||||||
|
#
|
||||||
|
# Easy reference to colors
|
||||||
|
#
|
||||||
|
base = self._resources['colors']['base']
|
||||||
|
blue = self._resources['colors']['blue']
|
||||||
|
|
||||||
|
lines: list[Word.Line] = []
|
||||||
|
line = Word.Line()
|
||||||
|
hw = re.sub(r'\*', '', entry['hwi']['hw'])
|
||||||
|
frag = Word.Fragment(hw, self._resources['fonts']['header'], color=base)
|
||||||
|
line.addFragment(frag)
|
||||||
|
frag = Word.Fragment(' '+entry["fl"], self._resources['fonts']['label'], color=blue)
|
||||||
|
line.addFragment(frag)
|
||||||
|
lines.append(line)
|
||||||
|
|
||||||
|
if "vrs" in entry.keys():
|
||||||
line = self.Line()
|
line = self.Line()
|
||||||
space = ''
|
space = ''
|
||||||
for vrs in self._current["vrs"]:
|
for vrs in entry["vrs"]:
|
||||||
frag = Word.Fragment(space + vrs["va"], labelFont, color=base)
|
frag = Word.Fragment(space + vrs["va"], self._resources['fonts']['label'], color=base)
|
||||||
space = ' '
|
space = ' '
|
||||||
line.addFragment(frag)
|
line.addFragment(frag)
|
||||||
self._lines.append(line)
|
lines.append(line)
|
||||||
if "prs" in self._current["hwi"].keys():
|
if "prs" in entry["hwi"].keys():
|
||||||
line = self.Line()
|
line = self.Line()
|
||||||
frag = Word.Fragment(self._current['hwi']['hw'] + ' ', phonicFont, color=base)
|
frag = Word.Fragment(entry['hwi']['hw'] + ' ', self._resources['fonts']['phonic'], color=base)
|
||||||
line.addFragment(frag)
|
line.addFragment(frag)
|
||||||
for prs in self._current["hwi"]["prs"]:
|
for prs in entry["hwi"]["prs"]:
|
||||||
audio = self.sound_url(prs)
|
audio = self.sound_url(prs)
|
||||||
if audio is None:
|
if audio is None:
|
||||||
audio = ""
|
audio = ""
|
||||||
frag = Word.Fragment(prs['mw'], phonicFont, color=blue)
|
frag = Word.Fragment(prs['mw'], self._resources['fonts']['phonic'], color=blue)
|
||||||
frag.setAudio(audio)
|
frag.setAudio(audio)
|
||||||
frag.setPadding(0,10,3,12)
|
frag.setPadding(0,10,3,12)
|
||||||
frag.setBorder(1)
|
frag.setBorder(1)
|
||||||
frag.setMargin(0,3,0,3)
|
frag.setMargin(0,3,0,3)
|
||||||
line.addFragment(frag)
|
line.addFragment(frag)
|
||||||
self._lines.append(line)
|
lines.append(line)
|
||||||
if "ins" in self._current.keys():
|
if "ins" in entry.keys():
|
||||||
line = self.Line()
|
line = self.Line()
|
||||||
space = ''
|
space = ''
|
||||||
for ins in self._current['ins']:
|
for ins in entry['ins']:
|
||||||
try:
|
try:
|
||||||
frag = Word.Fragment(ins['il'], textFont, color=base)
|
frag = Word.Fragment(ins['il'], self._resources['fonts']['text'], color=base)
|
||||||
line.addFragment(frag)
|
line.addFragment(frag)
|
||||||
space = ' '
|
space = ' '
|
||||||
except KeyError:
|
except KeyError:
|
||||||
space = ''
|
pass
|
||||||
frag = Word.Fragment(space + ins['if'], boldFont, color=base)
|
frag = Word.Fragment(space + ins['if'], self._resources['fonts']['bold'], color=base)
|
||||||
line.addFragment(frag)
|
line.addFragment(frag)
|
||||||
space = '; '
|
space = '; '
|
||||||
self._lines.append(line)
|
lines.append(line)
|
||||||
if 'lbs' in self._current.keys():
|
if 'lbs' in entry.keys():
|
||||||
print('lbs')
|
|
||||||
line = self.Line()
|
line = self.Line()
|
||||||
frag = Word.Fragment('; '.join(self._current['lbs']), boldFont, color=base)
|
frag = Word.Fragment('; '.join(entry['lbs']), self._resources['fonts']['bold'], color=base)
|
||||||
line.addFragment(frag)
|
line.addFragment(frag)
|
||||||
self._lines.append(line)
|
lines.append(line)
|
||||||
|
for value in entry['def']: # has multiple 'sseg' or 'vd' init
|
||||||
return self._lines
|
for k,v in value.items():
|
||||||
|
if k == 'sseq': # has multiple 'senses'
|
||||||
|
for seq in v:
|
||||||
|
r = self.mw_seq(seq)
|
||||||
|
lines += r
|
||||||
|
elif k == 'vd':
|
||||||
|
line = self.Line()
|
||||||
|
line.addFragment(Word.Fragment(
|
||||||
|
v,
|
||||||
|
self._resources['fonts']['italic'],
|
||||||
|
color=blue
|
||||||
|
))
|
||||||
|
lines.append(line)
|
||||||
|
return 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:
|
||||||
"""Create a URL from a PRS structure."""
|
"""Create a URL from a PRS structure."""
|
||||||
base = f"https://media.merriam-webster.com/audio/prons/en/us/{fmt}"
|
base = f"https://media.merriam-webster.com/audio/prons/en/us/{fmt}"
|
||||||
if "sound" not in prs.keys():
|
if "sound" not in prs.keys():
|
||||||
@@ -609,9 +746,6 @@ class Word:
|
|||||||
def mw_html(self) -> str:
|
def mw_html(self) -> str:
|
||||||
def parse_sn(sn: str, old: str) -> str:
|
def parse_sn(sn: str, old: str) -> str:
|
||||||
return sn
|
return sn
|
||||||
|
|
||||||
assert self._current is not None
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Create the header, base word and its label
|
# Create the header, base word and its label
|
||||||
#
|
#
|
||||||
@@ -703,12 +837,23 @@ class Definition(QWidget):
|
|||||||
self._lines = lines
|
self._lines = lines
|
||||||
self._buttons = []
|
self._buttons = []
|
||||||
assert self._lines is not None
|
assert self._lines is not None
|
||||||
|
#self.setFixedWidth(600)
|
||||||
base = 0
|
base = 0
|
||||||
for line in self._lines:
|
for line in self._lines:
|
||||||
line.finalizeLine(80)
|
line.finalizeLine(self.width())
|
||||||
base += line.getLeading()
|
base += line.getLeading()
|
||||||
|
self.setFixedHeight(base)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def resizeEvent(self, event: QResizeEvent) -> None:
|
||||||
|
base = 0
|
||||||
|
for line in self._lines:
|
||||||
|
line.finalizeLine(event.size().width())
|
||||||
|
base += line.getLeading()
|
||||||
|
self.setFixedHeight(base)
|
||||||
|
super(Definition,self).resizeEvent(event)
|
||||||
|
return
|
||||||
|
|
||||||
_downRect: QRect | None = None
|
_downRect: QRect | None = None
|
||||||
|
|
||||||
def mousePressEvent(self, event: Optional[QMouseEvent]) -> None:
|
def mousePressEvent(self, event: Optional[QMouseEvent]) -> None:
|
||||||
@@ -768,10 +913,20 @@ class Definition(QWidget):
|
|||||||
#
|
#
|
||||||
elif frag.wRef():
|
elif frag.wRef():
|
||||||
painter.drawLine(frag.borderRect().bottomLeft(), frag.borderRect().bottomRight())
|
painter.drawLine(frag.borderRect().bottomLeft(), frag.borderRect().bottomRight())
|
||||||
print(base, painter.pen().color().name(), frag.position(), frag.text())
|
|
||||||
painter.drawText(frag.position(), frag.text())
|
painter.drawText(frag.position(), frag.text())
|
||||||
painter.restore()
|
painter.restore()
|
||||||
painter.resetTransform()
|
painter.resetTransform()
|
||||||
base += line.getLeading()
|
base += line.getLeading()
|
||||||
painter.restore()
|
painter.restore()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
class DefinitionArea(QScrollArea):
|
||||||
|
def __init__(self, w: Word, *args: Any, **kwargs: Any) -> None:
|
||||||
|
super(DefinitionArea,self).__init__(*args,*kwargs)
|
||||||
|
d = Definition(w)
|
||||||
|
self.setWidget(d)
|
||||||
|
self.setWidgetResizable(True)
|
||||||
|
self.setVerticalScrollBarPolicy(
|
||||||
|
Qt.ScrollBarPolicy.ScrollBarAlwaysOn
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user