Move Fragment out of Word
This commit is contained in:
548
lib/words.py
548
lib/words.py
@@ -1,10 +1,10 @@
|
|||||||
import copy
|
import copy
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
from typing import Any, Optional, Self
|
from typing import Any, Optional
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from PyQt6.QtCore import QPoint, QRect, QSize, QUrl, Qt, pyqtSignal
|
from PyQt6.QtCore import QPoint, QRect, QUrl, Qt, pyqtSignal
|
||||||
from PyQt6.QtGui import (
|
from PyQt6.QtGui import (
|
||||||
QBrush,
|
QBrush,
|
||||||
QColor,
|
QColor,
|
||||||
@@ -19,231 +19,227 @@ from PyQt6.QtGui import (
|
|||||||
QTransform,
|
QTransform,
|
||||||
)
|
)
|
||||||
from PyQt6.QtSql import QSqlQuery
|
from PyQt6.QtSql import QSqlQuery
|
||||||
from PyQt6.QtWidgets import QScrollArea, QScrollBar, QSizePolicy, QWidget
|
from PyQt6.QtWidgets import QScrollArea, QWidget
|
||||||
|
|
||||||
from lib import query_error
|
from lib import query_error
|
||||||
|
|
||||||
|
class Fragment:
|
||||||
|
"""A structure to hold typed values of a fragment."""
|
||||||
|
|
||||||
|
_type: str # Function of this fragment. Think text, span, button
|
||||||
|
_text: str # The simple utf-8 text
|
||||||
|
_content: list['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
|
||||||
|
_asis: bool = False
|
||||||
|
_left: int = 0
|
||||||
|
|
||||||
|
|
||||||
|
TYPES = [ 'text', 'span', 'button' ]
|
||||||
|
def __init__(self,
|
||||||
|
text:str,
|
||||||
|
font:QFont,
|
||||||
|
t:str = 'text',
|
||||||
|
audio:str = '',
|
||||||
|
color: Optional[QColor] = None,
|
||||||
|
asis: bool = False,
|
||||||
|
) -> None:
|
||||||
|
if t not in self.TYPES:
|
||||||
|
raise Exception(f"Unknown fragment type{t}")
|
||||||
|
self._type = t
|
||||||
|
self._text = text
|
||||||
|
self._font = font
|
||||||
|
self._audio = QUrl(audio)
|
||||||
|
self._align = QTextOption(
|
||||||
|
Qt.AlignmentFlag.AlignLeft
|
||||||
|
| Qt.AlignmentFlag.AlignBaseline
|
||||||
|
)
|
||||||
|
self._padding = [0, 0, 0, 0]
|
||||||
|
self._border = [0, 0, 0, 0]
|
||||||
|
self._margin = [0, 0, 0, 0]
|
||||||
|
self._wref = ''
|
||||||
|
self._position = QPoint()
|
||||||
|
self._borderRect = QRect()
|
||||||
|
if color:
|
||||||
|
self._color = color
|
||||||
|
else:
|
||||||
|
self._color = QColor()
|
||||||
|
self._asis = asis
|
||||||
|
return
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self._text
|
||||||
|
#
|
||||||
|
# Setters
|
||||||
|
#
|
||||||
|
def setType(self, t:str) -> None:
|
||||||
|
if t not in self.TYPES:
|
||||||
|
raise Exception(f"Unknown fragment type{t}")
|
||||||
|
self._type = t
|
||||||
|
return
|
||||||
|
def setText(self, text:str) -> None:
|
||||||
|
self._text = text
|
||||||
|
return
|
||||||
|
def setFont(self, font:QFont) -> None:
|
||||||
|
self._font = font
|
||||||
|
return
|
||||||
|
def setAudio(self, audio:str) -> None:
|
||||||
|
self._audio = QUrl(audio)
|
||||||
|
return
|
||||||
|
def setAlign(self, align:QTextOption) -> None:
|
||||||
|
self._align = align
|
||||||
|
return
|
||||||
|
def setRect(self,rect:QRect) -> None:
|
||||||
|
self._rect = rect
|
||||||
|
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
|
||||||
|
def setLeft(self, left:int) -> None:
|
||||||
|
self._left = left
|
||||||
|
return
|
||||||
|
#
|
||||||
|
# Getters
|
||||||
|
#
|
||||||
|
def wRef(self) -> str:
|
||||||
|
return self._wref
|
||||||
|
def type(self) -> str:
|
||||||
|
return self._type
|
||||||
|
def text(self) -> str:
|
||||||
|
return self._text
|
||||||
|
def font(self) -> QFont:
|
||||||
|
return self._font
|
||||||
|
def audio(self) -> str:
|
||||||
|
return self._audio.url()
|
||||||
|
def align(self) -> QTextOption:
|
||||||
|
return self._align
|
||||||
|
def rect(self) -> QRect:
|
||||||
|
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
|
||||||
|
def asis(self) -> bool:
|
||||||
|
return self._asis
|
||||||
|
def left(self) -> int:
|
||||||
|
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"
|
||||||
|
|
||||||
|
|
||||||
class Word:
|
class Word:
|
||||||
_instance = None
|
"""All processing of a dictionary word."""
|
||||||
|
|
||||||
|
|
||||||
_words: dict[str, Any] = {}
|
_words: dict[str, Any] = {}
|
||||||
_current: dict[str, Any] = {}
|
|
||||||
_currentWord: str
|
|
||||||
|
|
||||||
class Fragment:
|
|
||||||
"""A structure to hold typed values of a fragment."""
|
|
||||||
|
|
||||||
_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
|
|
||||||
_asis: bool = False
|
|
||||||
_left: int = 0
|
|
||||||
|
|
||||||
|
|
||||||
TYPES = [ 'text', 'span', 'button' ]
|
|
||||||
def __init__(self,
|
|
||||||
text:str,
|
|
||||||
font:QFont,
|
|
||||||
t:str = 'text',
|
|
||||||
audio:str = '',
|
|
||||||
color: Optional[QColor] = None,
|
|
||||||
asis: bool = False,
|
|
||||||
) -> None:
|
|
||||||
if t not in self.TYPES:
|
|
||||||
raise Exception(f"Unknown fragment type{t}")
|
|
||||||
self._type = t
|
|
||||||
self._text = text
|
|
||||||
self._font = font
|
|
||||||
self._audio = QUrl(audio)
|
|
||||||
self._align = QTextOption(
|
|
||||||
Qt.AlignmentFlag.AlignLeft
|
|
||||||
| Qt.AlignmentFlag.AlignBaseline
|
|
||||||
)
|
|
||||||
self._padding = [0, 0, 0, 0]
|
|
||||||
self._border = [0, 0, 0, 0]
|
|
||||||
self._margin = [0, 0, 0, 0]
|
|
||||||
self._wref = ''
|
|
||||||
self._position = QPoint()
|
|
||||||
self._borderRect = QRect()
|
|
||||||
if color:
|
|
||||||
self._color = color
|
|
||||||
else:
|
|
||||||
self._color = QColor()
|
|
||||||
self._asis = asis
|
|
||||||
return
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return self._text
|
|
||||||
#
|
|
||||||
# Setters
|
|
||||||
#
|
|
||||||
def setType(self, t:str) -> None:
|
|
||||||
if t not in self.TYPES:
|
|
||||||
raise Exception(f"Unknown fragment type{t}")
|
|
||||||
self._type = t
|
|
||||||
return
|
|
||||||
def setText(self, text:str) -> None:
|
|
||||||
self._text = text
|
|
||||||
return
|
|
||||||
def setFont(self, font:QFont) -> None:
|
|
||||||
self._font = font
|
|
||||||
return
|
|
||||||
def setAudio(self, audio:str) -> None:
|
|
||||||
self._audio = QUrl(audio)
|
|
||||||
return
|
|
||||||
def setAlign(self, align:QTextOption) -> None:
|
|
||||||
self._align = align
|
|
||||||
return
|
|
||||||
def setRect(self,rect:QRect) -> None:
|
|
||||||
self._rect = rect
|
|
||||||
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
|
|
||||||
def setLeft(self, left:int) -> None:
|
|
||||||
self._left = left
|
|
||||||
return
|
|
||||||
#
|
|
||||||
# Getters
|
|
||||||
#
|
|
||||||
def wRef(self) -> str:
|
|
||||||
return self._wref
|
|
||||||
def type(self) -> str:
|
|
||||||
return self._type
|
|
||||||
def text(self) -> str:
|
|
||||||
return self._text
|
|
||||||
def font(self) -> QFont:
|
|
||||||
return self._font
|
|
||||||
def audio(self) -> str:
|
|
||||||
return self._audio.url()
|
|
||||||
def align(self) -> QTextOption:
|
|
||||||
return self._align
|
|
||||||
def rect(self) -> QRect:
|
|
||||||
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
|
|
||||||
def asis(self) -> bool:
|
|
||||||
return self._asis
|
|
||||||
def left(self) -> int:
|
|
||||||
return self._left
|
|
||||||
|
|
||||||
class Line:
|
class Line:
|
||||||
|
|
||||||
_maxHeight: int
|
|
||||||
_leading: int
|
|
||||||
_baseLine: int
|
|
||||||
_fragments: list['Word.Fragment']
|
|
||||||
|
|
||||||
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 = []
|
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 parseText(self, frag: 'Word.Fragment') -> list['Word.Fragment']:
|
def parseText(self, frag: Fragment) -> list[Fragment]:
|
||||||
org = frag.text()
|
org = frag.text()
|
||||||
if frag.asis():
|
if frag.asis():
|
||||||
return [frag]
|
return [frag]
|
||||||
@@ -259,7 +255,7 @@ class Word:
|
|||||||
script = QFont(frag.font())
|
script = QFont(frag.font())
|
||||||
script.setPixelSize(int(script.pixelSize()/4))
|
script.setPixelSize(int(script.pixelSize()/4))
|
||||||
|
|
||||||
results: list['Word.Fragment'] = []
|
results: list[Fragment] = []
|
||||||
while True:
|
while True:
|
||||||
text = frag.text()
|
text = frag.text()
|
||||||
start = text.find('{')
|
start = text.find('{')
|
||||||
@@ -292,7 +288,7 @@ class Word:
|
|||||||
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, 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 ['b', 'inf', 'it', 'sc', 'sup', 'phrase', 'parahw', 'gloss',
|
||||||
'qword', 'wi', 'dx', 'dx_def', 'dx_ety', 'ma']:
|
'qword', 'wi', 'dx', 'dx_def', 'dx_ety', 'ma']:
|
||||||
@@ -372,7 +368,7 @@ class Word:
|
|||||||
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(self, frag: 'Word.Fragment',) -> None:
|
def addFragment(self, frag: Fragment,) -> None:
|
||||||
SPEAKER = "\U0001F508"
|
SPEAKER = "\U0001F508"
|
||||||
|
|
||||||
if frag.audio():
|
if frag.audio():
|
||||||
@@ -459,7 +455,7 @@ class Word:
|
|||||||
x += width
|
x += width
|
||||||
return
|
return
|
||||||
|
|
||||||
def getLine(self) -> list['Word.Fragment']:
|
def getLine(self) -> list[Fragment]:
|
||||||
return self._fragments
|
return self._fragments
|
||||||
|
|
||||||
def getLeading(self) -> int:
|
def getLeading(self) -> int:
|
||||||
@@ -467,26 +463,13 @@ class Word:
|
|||||||
|
|
||||||
_lines: list[Line] = []
|
_lines: list[Line] = []
|
||||||
|
|
||||||
def __new__(cls: type[Self], _: str) -> Self: # flycheck: ignore
|
|
||||||
if cls._instance:
|
|
||||||
return cls._instance
|
|
||||||
cls._instance = super(Word, cls).__new__(cls)
|
|
||||||
return cls._instance
|
|
||||||
|
|
||||||
def __init__(self, word: str) -> None:
|
def __init__(self, word: str) -> None:
|
||||||
#
|
self.resources = {}
|
||||||
# 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?
|
||||||
#
|
#
|
||||||
try:
|
try:
|
||||||
self._current = json.loads(self._words[word])
|
self.current = json.loads(Word._words[word])
|
||||||
return
|
return
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
@@ -496,17 +479,17 @@ 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] = {
|
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 = self._words[word]
|
self.current = Word._words[word]
|
||||||
return
|
return
|
||||||
source = 'mw'
|
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 = {}
|
self.current = {}
|
||||||
return
|
return
|
||||||
data = json.loads(response.content.decode("utf-8"))
|
data = json.loads(response.content.decode("utf-8"))
|
||||||
print(data)
|
print(data)
|
||||||
@@ -515,35 +498,34 @@ class Word:
|
|||||||
'source': source,
|
'source': source,
|
||||||
'definition': data,
|
'definition': data,
|
||||||
}
|
}
|
||||||
self._current = self._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 getCurrent(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']}")
|
||||||
|
|
||||||
_resources:dict[str,Any] = {}
|
|
||||||
def get_def(self) -> list[Line] | None:
|
def get_def(self) -> list[Line] | None:
|
||||||
if len(self._lines) > 0:
|
if len(self._lines) > 0:
|
||||||
return self._lines
|
return self._lines
|
||||||
if len(self._resources.keys()) < 1:
|
if len(self.resources.keys()) < 1:
|
||||||
#
|
#
|
||||||
# Colors we used
|
# Colors we used
|
||||||
#
|
#
|
||||||
@@ -563,7 +545,7 @@ class Word:
|
|||||||
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"),
|
||||||
@@ -577,22 +559,22 @@ class Word:
|
|||||||
'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()
|
line = Word.Line()
|
||||||
meta = json.dumps(entry['meta'])
|
meta = json.dumps(entry['meta'])
|
||||||
line.addFragment(
|
line.addFragment(
|
||||||
Word.Fragment(
|
Fragment(
|
||||||
meta,
|
meta,
|
||||||
self._resources['fonts']['text'],asis=True
|
self.resources['fonts']['text'],asis=True
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
lines.append(line)
|
lines.append(line)
|
||||||
@@ -623,18 +605,18 @@ class Word:
|
|||||||
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 = Word.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 = Word.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)
|
||||||
@@ -642,14 +624,14 @@ class Word:
|
|||||||
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 =Word.Fragment(f" ",
|
frag =Fragment(f" ",
|
||||||
self._resources['fonts']['bold'],
|
self.resources['fonts']['bold'],
|
||||||
)
|
)
|
||||||
frag.setLeft(45)
|
frag.setLeft(45)
|
||||||
line.addFragment(frag)
|
line.addFragment(frag)
|
||||||
line.addFragment(
|
line.addFragment(
|
||||||
Word.Fragment(vis['t'],
|
Fragment(vis['t'],
|
||||||
self._resources['fonts']['text'],
|
self.resources['fonts']['text'],
|
||||||
color = QColor('#aaa')
|
color = QColor('#aaa')
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -659,15 +641,15 @@ class Word:
|
|||||||
#
|
#
|
||||||
# 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 = Word.Fragment(hw, self._resources['fonts']['header'], color=base)
|
frag = Fragment(hw, self.resources['fonts']['header'], color=base)
|
||||||
line.addFragment(frag)
|
line.addFragment(frag)
|
||||||
frag = Word.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)
|
||||||
|
|
||||||
@@ -675,19 +657,19 @@ class Word:
|
|||||||
line = self.Line()
|
line = self.Line()
|
||||||
space = ''
|
space = ''
|
||||||
for vrs in entry["vrs"]:
|
for vrs in entry["vrs"]:
|
||||||
frag = Word.Fragment(space + vrs["va"], self._resources['fonts']['label'], color=base)
|
frag = Fragment(space + vrs["va"], self.resources['fonts']['label'], color=base)
|
||||||
space = ' '
|
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 = Word.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.sound_url(prs)
|
audio = self.sound_url(prs)
|
||||||
if audio is None:
|
if audio is None:
|
||||||
audio = ""
|
audio = ""
|
||||||
frag = Word.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)
|
||||||
frag.setPadding(0,10,3,12)
|
frag.setPadding(0,10,3,12)
|
||||||
frag.setBorder(1)
|
frag.setBorder(1)
|
||||||
@@ -699,18 +681,18 @@ class Word:
|
|||||||
space = ''
|
space = ''
|
||||||
for ins in entry['ins']:
|
for ins in entry['ins']:
|
||||||
try:
|
try:
|
||||||
frag = Word.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 = Word.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 = Word.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
|
||||||
@@ -721,9 +703,9 @@ class Word:
|
|||||||
lines += r
|
lines += r
|
||||||
elif k == 'vd':
|
elif k == 'vd':
|
||||||
line = self.Line()
|
line = self.Line()
|
||||||
line.addFragment(Word.Fragment(
|
line.addFragment(Fragment(
|
||||||
v,
|
v,
|
||||||
self._resources['fonts']['italic'],
|
self.resources['fonts']['italic'],
|
||||||
color=blue
|
color=blue
|
||||||
))
|
))
|
||||||
lines.append(line)
|
lines.append(line)
|
||||||
@@ -749,28 +731,28 @@ class Word:
|
|||||||
#
|
#
|
||||||
# Create the header, base word and its label
|
# Create the header, base word and its label
|
||||||
#
|
#
|
||||||
word = self._current["hwi"]["hw"]
|
word = self.current["hwi"]["hw"]
|
||||||
label = self._current["fl"]
|
label = self.current["fl"]
|
||||||
html = f'<h1 class="def-word">{word} <span class="def-label">{label}</span></h1>\n'
|
html = f'<h1 class="def-word">{word} <span class="def-label">{label}</span></h1>\n'
|
||||||
|
|
||||||
#
|
#
|
||||||
# If there are variants, then add them in an unordered list.
|
# If there are variants, then add them in an unordered list.
|
||||||
# CSS will make it pretty
|
# CSS will make it pretty
|
||||||
#
|
#
|
||||||
if "vrs" in self._current.keys():
|
if "vrs" in self.current.keys():
|
||||||
html += "<ul class=\"def-vrs'>\n"
|
html += "<ul class=\"def-vrs'>\n"
|
||||||
html += "<li>"
|
html += "<li>"
|
||||||
html += "</li>\n<li>".join(
|
html += "</li>\n<li>".join(
|
||||||
[vrs["va"] for vrs in self._current["vrs"]]
|
[vrs["va"] for vrs in self.current["vrs"]]
|
||||||
)
|
)
|
||||||
html += "</li>\n</ul>\n"
|
html += "</li>\n</ul>\n"
|
||||||
|
|
||||||
#
|
#
|
||||||
# If there is a pronunciation section, create it
|
# If there is a pronunciation section, create it
|
||||||
#
|
#
|
||||||
if "prs" in self._current["hwi"].keys():
|
if "prs" in self.current["hwi"].keys():
|
||||||
tmp = []
|
tmp = []
|
||||||
for prs in self._current["hwi"]["prs"]:
|
for prs in self.current["hwi"]["prs"]:
|
||||||
url = self.sound_url(prs)
|
url = self.sound_url(prs)
|
||||||
how = prs["mw"]
|
how = prs["mw"]
|
||||||
if url:
|
if url:
|
||||||
@@ -784,16 +766,16 @@ class Word:
|
|||||||
#
|
#
|
||||||
# If there are inflections, create a header for that.
|
# If there are inflections, create a header for that.
|
||||||
#
|
#
|
||||||
if "ins" in self._current.keys():
|
if "ins" in self.current.keys():
|
||||||
html += '<h2 class="def-word">'
|
html += '<h2 class="def-word">'
|
||||||
html += ", ".join([ins["if"] for ins in self._current["ins"]])
|
html += ", ".join([ins["if"] for ins in self.current["ins"]])
|
||||||
html += "</h2>\n"
|
html += "</h2>\n"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Start creating the definition section
|
# Start creating the definition section
|
||||||
#
|
#
|
||||||
html += "<ul class='def-outer'>\n"
|
html += "<ul class='def-outer'>\n"
|
||||||
for meaning in self._current["def"]:
|
for meaning in self.current["def"]:
|
||||||
html += f"<li>{meaning['vd']}\n"
|
html += f"<li>{meaning['vd']}\n"
|
||||||
html += '<ul class="def-inner">\n'
|
html += '<ul class="def-inner">\n'
|
||||||
label = ""
|
label = ""
|
||||||
@@ -825,19 +807,14 @@ class Word:
|
|||||||
|
|
||||||
class Definition(QWidget):
|
class Definition(QWidget):
|
||||||
pronounce = pyqtSignal(str)
|
pronounce = pyqtSignal(str)
|
||||||
_word: str
|
|
||||||
_lines: list[Word.Line]
|
|
||||||
_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)
|
||||||
self._word = w.getCurrent()
|
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 = []
|
self._buttons:list[Fragment] = []
|
||||||
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(self.width())
|
line.finalizeLine(self.width())
|
||||||
@@ -859,7 +836,8 @@ class Definition(QWidget):
|
|||||||
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)
|
||||||
for rect in self._buttons:
|
for frag in self._buttons:
|
||||||
|
rect = frag.borderRect()
|
||||||
if rect.contains(event.pos()):
|
if rect.contains(event.pos()):
|
||||||
self._downRect = rect
|
self._downRect = rect
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user