Loading config/stylesheet.css +13 −1 Original line number Diff line number Diff line Loading @@ -937,7 +937,6 @@ TextAreaStyleButton { border-radius: 10px; padding: 5px; background-color: @widgetBackgroundColor; } TextAreaStyleButton#NewTextStyleButton { Loading @@ -956,6 +955,19 @@ TextAreaStyleButton::hover { background-color: #cad7ed; } HidePanelButton { width: 12px; height: 12px; padding: 3px; border: none; background-color: @widgetBackgroundColor; image: url(icons/titlebar_close.svg); } HidePanelButton::hover { background-color: #FF605C; } Widget#TextStyleAreaContent { background-color : @emptyContentBackgroundColor; border-radius: 7px; Loading ui/flow_layout.py 0 → 100644 +206 −0 Original line number Diff line number Diff line from qtpy.QtWidgets import QLayout, QWidgetItem, QLayoutItem, QWidgetItem, QWidget from qtpy.QtCore import QParallelAnimationGroup, Qt, QPropertyAnimation, QEasingCurve, QSize, QRect, QPoint from typing import List class WidgetItem(QWidgetItem): def sizeHint(self) -> QSize: return self.widget().sizeHint() class FlowLayout(QLayout): """ Flow layout """ def __init__(self, parent=None, needAni=False, isTight=False): """ Parameters ---------- parent: parent window or layout needAni: bool whether to add moving animation isTight: bool whether to use the tight layout when widgets are hidden """ super().__init__(parent) self._items = [] # type: List[QLayoutItem] self._anis = [] self._aniGroup = QParallelAnimationGroup(self) self._verticalSpacing = 10 self._horizontalSpacing = 10 self.duration = 300 self.ease = QEasingCurve.Linear self.needAni = needAni self.isTight = isTight self.height = 0 def insertWidget(self, idx: int, w: QWidget): self.addChildWidget(w) self.insertItem(idx, WidgetItem(w)) def insertItem(self, idx:int, item): self._items.insert(idx, item) def addItem(self, item): self._items.append(item) def addWidget(self, w): super().addWidget(w) if not self.needAni: return ani = QPropertyAnimation(w, b'geometry') ani.setEndValue(QRect(QPoint(0, 0), w.size())) ani.setDuration(self.duration) ani.setEasingCurve(self.ease) w.setProperty('flowAni', ani) self._anis.append(ani) self._aniGroup.addAnimation(ani) def setAnimation(self, duration, ease=QEasingCurve.Linear): """ set the moving animation Parameters ---------- duration: int the duration of animation in milliseconds ease: QEasingCurve the easing curve of animation """ if not self.needAni: return self.duration = duration self.ease = ease for ani in self._anis: ani.setDuration(duration) ani.setEasingCurve(ease) def count(self): return len(self._items) def itemAt(self, index: int): if 0 <= index < len(self._items): return self._items[index] return None def takeAt(self, index: int): if 0 <= index < len(self._items): item = self._items[index] # type: QWidgetItem ani = item.widget().property('flowAni') if ani: self._anis.remove(ani) self._aniGroup.removeAnimation(ani) ani.deleteLater() return self._items.pop(index).widget() return None def removeWidget(self, widget): for i, item in enumerate(self._items): if item.widget() is widget: return self.takeAt(i) def removeAllWidgets(self): """ remove all widgets from layout """ while self._items: self.takeAt(0) def takeAllWidgets(self): """ remove all widgets from layout and delete them """ while self._items: w = self.takeAt(0) if w: w.deleteLater() def expandingDirections(self): return Qt.Orientation(0) def hasHeightForWidth(self): return True def heightForWidth(self, width: int): """ get the minimal height according to width """ return self._doLayout(QRect(0, 0, width, 0), False) def setGeometry(self, rect: QRect): super().setGeometry(rect) self._doLayout(rect, True) def sizeHint(self): return self.minimumSize() def minimumSize(self): size = QSize() for item in self._items: size = size.expandedTo(item.minimumSize()) m = self.contentsMargins() size += QSize(m.left()+m.right(), m.top()+m.bottom()) return size def setVerticalSpacing(self, spacing: int): """ set vertical spacing between widgets """ self._verticalSpacing = spacing def verticalSpacing(self): """ get vertical spacing between widgets """ return self._verticalSpacing def setHorizontalSpacing(self, spacing: int): """ set horizontal spacing between widgets """ self._horizontalSpacing = spacing def horizontalSpacing(self): """ get horizontal spacing between widgets """ return self._horizontalSpacing def _doLayout(self, rect: QRect, move: bool): """ adjust widgets position according to the window size """ aniRestart = False margin = self.contentsMargins() x = rect.x() + margin.left() y = rect.y() + margin.top() rowHeight = 0 spaceX = self.horizontalSpacing() spaceY = self.verticalSpacing() for i, item in enumerate(self._items): if item.widget() and not item.widget().isVisible() and self.isTight: continue nextX = x + item.sizeHint().width() + spaceX if nextX - spaceX > rect.right() and rowHeight > 0: x = rect.x() + margin.left() y = y + rowHeight + spaceY nextX = x + item.sizeHint().width() + spaceX rowHeight = 0 if move: target = QRect(QPoint(x, y), item.sizeHint()) if not self.needAni: item.setGeometry(target) elif target != self._anis[i].endValue(): self._anis[i].stop() self._anis[i].setEndValue(target) aniRestart = True x = nextX rowHeight = max(rowHeight, item.sizeHint().height()) if self.needAni and aniRestart: self._aniGroup.stop() self._aniGroup.start() self.height = y + rowHeight + margin.bottom() - rect.y() return self.height No newline at end of file ui/fontformatpanel.py +14 −94 Original line number Diff line number Diff line Loading @@ -4,14 +4,15 @@ from typing import List from qtpy.QtWidgets import QComboBox, QMenu, QMessageBox, QStackedLayout, QGraphicsDropShadowEffect, QLineEdit, QScrollArea, QSizePolicy, QHBoxLayout, QVBoxLayout, QFrame, QFontComboBox, QApplication, QPushButton, QCheckBox, QLabel from qtpy.QtCore import Signal, Qt, QRectF from qtpy.QtGui import QDoubleValidator, QFocusEvent, QMouseEvent, QTextCursor, QFontMetrics, QIcon, QColor, QPixmap, QPainter, QContextMenuEvent, QKeyEvent from qtpy.QtGui import QDoubleValidator, QFocusEvent, QMouseEvent, QTextCursor, QFontMetrics, QColor, QPixmap, QPainter, QContextMenuEvent, QKeyEvent from utils.fontformat import FontFormat from utils import shared from utils.config import pcfg, save_text_styles, text_styles from utils import config as C from .stylewidgets import Widget, ColorPicker, ClickableLabel, CheckableLabel, TextChecker, FlowLayout, ScrollBar from .stylewidgets import Widget, ColorPicker, ClickableLabel, CheckableLabel, TextChecker, ScrollBar, ViewWidget from .flow_layout import FlowLayout from .textitem import TextBlkItem from .text_graphical_effect import TextEffectPanel from . import funcmaps as FM Loading Loading @@ -352,14 +353,6 @@ class FontFamilyComboBox(QFontComboBox): self.apply_fontfamily() CHEVRON_SIZE = 20 def chevron_down(): return QIcon(r'icons/chevron-down.svg').pixmap(CHEVRON_SIZE, CHEVRON_SIZE, mode=QIcon.Mode.Normal) def chevron_right(): return QIcon(r'icons/chevron-right.svg').pixmap(CHEVRON_SIZE, CHEVRON_SIZE, mode=QIcon.Mode.Normal) class StyleLabel(QLineEdit): edit_finished = Signal() Loading Loading @@ -820,92 +813,19 @@ class TextStyleArea(QScrollArea): return super().contextMenuEvent(e) class ExpandLabel(Widget): clicked = Signal() def __init__(self, text=None, parent=None, expanded=False, *args, **kwargs): super().__init__(parent=parent, *args, **kwargs) self.textlabel = QLabel(self) self.textlabel.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, True) font = self.textlabel.font() if shared.ON_MACOS: font.setPointSize(13) else: font.setPointSizeF(10) self.textlabel.setFont(font) self.arrowlabel = QLabel(self) self.arrowlabel.setFixedSize(CHEVRON_SIZE, CHEVRON_SIZE) self.arrowlabel.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, True) if text is not None: self.textlabel.setText(text) layout = QHBoxLayout(self) layout.addWidget(self.arrowlabel) layout.addWidget(self.textlabel) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(1) layout.addStretch(-1) self.expanded = False self.setExpand(expanded) self.setFixedHeight(26) def setExpand(self, expand: bool): self.expanded = expand if expand: self.arrowlabel.setPixmap(chevron_down()) else: self.arrowlabel.setPixmap(chevron_right()) def mousePressEvent(self, e: QMouseEvent) -> None: if e.button() == Qt.MouseButton.LeftButton: self.setExpand(not self.expanded) pcfg.expand_tstyle_panel = self.expanded self.clicked.emit() return super().mousePressEvent(e) class TextStylePanel(Widget): def __init__(self, text=None, parent=None, expanded=True, *args, **kwargs): super().__init__(parent=parent, *args, **kwargs) self.title_label = ExpandLabel(text, self, expanded=expanded) self.style_area = TextStyleArea(self) layout = QVBoxLayout(self) layout.addWidget(self.title_label) layout.addWidget(self.style_area) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) if not expanded: self.style_area.hide() self.title_label.clicked.connect(self.on_title_label_clicked) self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Maximum) def expand(self): if not self.title_label.expanded: self.title_label.setExpand(True) if self.style_area.isHidden(): self.style_area.show() def on_title_label_clicked(self): if self.title_label.expanded: self.style_area.show() else: self.style_area.hide() class TextStylePanel(ViewWidget): def setTitle(self, text: str): self.title_label.textlabel.setText(text) def __init__(self, text=None, parent=None, *args, **kwargs): def elidedText(self, text: str): fm = QFontMetrics(self.title_label.font()) return fm.elidedText(text, Qt.TextElideMode.ElideRight, self.style_area.width() - 40) style_area = TextStyleArea() super().__init__(style_area, text=text, parent=parent, *args, **kwargs) self.style_area = style_area def title(self) -> str: return self.title_label.textlabel.text() self.register_view_widget( 'show_text_style_preset', 'expand_tstyle_panel', self.tr('Show Text Style Panel') ) class FontFormatPanel(Widget): Loading Loading @@ -1003,7 +923,7 @@ class FontFormatPanel(Widget): lettersp_hlayout.setSpacing(shared.WIDGET_SPACING_CLOSE) self.global_fontfmt_str = self.tr("Global Font Format") self.textstyle_panel = TextStylePanel(self.global_fontfmt_str, parent=self, expanded=pcfg.expand_tstyle_panel) self.textstyle_panel = TextStylePanel(self.global_fontfmt_str, parent=self) self.textstyle_panel.style_area.active_text_style_label_changed.connect(self.on_active_textstyle_label_changed) self.textstyle_panel.style_area.active_stylename_edited.connect(self.on_active_stylename_edited) Loading ui/global_search_widget.py +2 −1 Original line number Diff line number Diff line Loading @@ -10,7 +10,8 @@ from utils.logger import logger as LOGGER from .page_search_widget import SearchEditor, HighlightMatched, SEARCHRST_HIGHLIGHT_COLOR from .misc import doc_replace from utils.config import pcfg from .stylewidgets import Widget, NoBorderPushBtn, ProgressMessageBox from .stylewidgets import Widget, NoBorderPushBtn from .message import ProgressMessageBox from .textitem import TextBlkItem, TextBlock from .textedit_area import TransPairWidget, SourceTextEdit, TransTextEdit from .config_proj import ProjImgTrans Loading ui/io_thread.py +1 −1 Original line number Diff line number Diff line Loading @@ -10,7 +10,7 @@ from utils.logger import logger as LOGGER from utils.io_utils import imread, imwrite from utils import create_error_dialog from .config_proj import ProjImgTrans from .stylewidgets import ProgressMessageBox from .message import ProgressMessageBox class ThreadBase(QThread): Loading Loading
config/stylesheet.css +13 −1 Original line number Diff line number Diff line Loading @@ -937,7 +937,6 @@ TextAreaStyleButton { border-radius: 10px; padding: 5px; background-color: @widgetBackgroundColor; } TextAreaStyleButton#NewTextStyleButton { Loading @@ -956,6 +955,19 @@ TextAreaStyleButton::hover { background-color: #cad7ed; } HidePanelButton { width: 12px; height: 12px; padding: 3px; border: none; background-color: @widgetBackgroundColor; image: url(icons/titlebar_close.svg); } HidePanelButton::hover { background-color: #FF605C; } Widget#TextStyleAreaContent { background-color : @emptyContentBackgroundColor; border-radius: 7px; Loading
ui/flow_layout.py 0 → 100644 +206 −0 Original line number Diff line number Diff line from qtpy.QtWidgets import QLayout, QWidgetItem, QLayoutItem, QWidgetItem, QWidget from qtpy.QtCore import QParallelAnimationGroup, Qt, QPropertyAnimation, QEasingCurve, QSize, QRect, QPoint from typing import List class WidgetItem(QWidgetItem): def sizeHint(self) -> QSize: return self.widget().sizeHint() class FlowLayout(QLayout): """ Flow layout """ def __init__(self, parent=None, needAni=False, isTight=False): """ Parameters ---------- parent: parent window or layout needAni: bool whether to add moving animation isTight: bool whether to use the tight layout when widgets are hidden """ super().__init__(parent) self._items = [] # type: List[QLayoutItem] self._anis = [] self._aniGroup = QParallelAnimationGroup(self) self._verticalSpacing = 10 self._horizontalSpacing = 10 self.duration = 300 self.ease = QEasingCurve.Linear self.needAni = needAni self.isTight = isTight self.height = 0 def insertWidget(self, idx: int, w: QWidget): self.addChildWidget(w) self.insertItem(idx, WidgetItem(w)) def insertItem(self, idx:int, item): self._items.insert(idx, item) def addItem(self, item): self._items.append(item) def addWidget(self, w): super().addWidget(w) if not self.needAni: return ani = QPropertyAnimation(w, b'geometry') ani.setEndValue(QRect(QPoint(0, 0), w.size())) ani.setDuration(self.duration) ani.setEasingCurve(self.ease) w.setProperty('flowAni', ani) self._anis.append(ani) self._aniGroup.addAnimation(ani) def setAnimation(self, duration, ease=QEasingCurve.Linear): """ set the moving animation Parameters ---------- duration: int the duration of animation in milliseconds ease: QEasingCurve the easing curve of animation """ if not self.needAni: return self.duration = duration self.ease = ease for ani in self._anis: ani.setDuration(duration) ani.setEasingCurve(ease) def count(self): return len(self._items) def itemAt(self, index: int): if 0 <= index < len(self._items): return self._items[index] return None def takeAt(self, index: int): if 0 <= index < len(self._items): item = self._items[index] # type: QWidgetItem ani = item.widget().property('flowAni') if ani: self._anis.remove(ani) self._aniGroup.removeAnimation(ani) ani.deleteLater() return self._items.pop(index).widget() return None def removeWidget(self, widget): for i, item in enumerate(self._items): if item.widget() is widget: return self.takeAt(i) def removeAllWidgets(self): """ remove all widgets from layout """ while self._items: self.takeAt(0) def takeAllWidgets(self): """ remove all widgets from layout and delete them """ while self._items: w = self.takeAt(0) if w: w.deleteLater() def expandingDirections(self): return Qt.Orientation(0) def hasHeightForWidth(self): return True def heightForWidth(self, width: int): """ get the minimal height according to width """ return self._doLayout(QRect(0, 0, width, 0), False) def setGeometry(self, rect: QRect): super().setGeometry(rect) self._doLayout(rect, True) def sizeHint(self): return self.minimumSize() def minimumSize(self): size = QSize() for item in self._items: size = size.expandedTo(item.minimumSize()) m = self.contentsMargins() size += QSize(m.left()+m.right(), m.top()+m.bottom()) return size def setVerticalSpacing(self, spacing: int): """ set vertical spacing between widgets """ self._verticalSpacing = spacing def verticalSpacing(self): """ get vertical spacing between widgets """ return self._verticalSpacing def setHorizontalSpacing(self, spacing: int): """ set horizontal spacing between widgets """ self._horizontalSpacing = spacing def horizontalSpacing(self): """ get horizontal spacing between widgets """ return self._horizontalSpacing def _doLayout(self, rect: QRect, move: bool): """ adjust widgets position according to the window size """ aniRestart = False margin = self.contentsMargins() x = rect.x() + margin.left() y = rect.y() + margin.top() rowHeight = 0 spaceX = self.horizontalSpacing() spaceY = self.verticalSpacing() for i, item in enumerate(self._items): if item.widget() and not item.widget().isVisible() and self.isTight: continue nextX = x + item.sizeHint().width() + spaceX if nextX - spaceX > rect.right() and rowHeight > 0: x = rect.x() + margin.left() y = y + rowHeight + spaceY nextX = x + item.sizeHint().width() + spaceX rowHeight = 0 if move: target = QRect(QPoint(x, y), item.sizeHint()) if not self.needAni: item.setGeometry(target) elif target != self._anis[i].endValue(): self._anis[i].stop() self._anis[i].setEndValue(target) aniRestart = True x = nextX rowHeight = max(rowHeight, item.sizeHint().height()) if self.needAni and aniRestart: self._aniGroup.stop() self._aniGroup.start() self.height = y + rowHeight + margin.bottom() - rect.y() return self.height No newline at end of file
ui/fontformatpanel.py +14 −94 Original line number Diff line number Diff line Loading @@ -4,14 +4,15 @@ from typing import List from qtpy.QtWidgets import QComboBox, QMenu, QMessageBox, QStackedLayout, QGraphicsDropShadowEffect, QLineEdit, QScrollArea, QSizePolicy, QHBoxLayout, QVBoxLayout, QFrame, QFontComboBox, QApplication, QPushButton, QCheckBox, QLabel from qtpy.QtCore import Signal, Qt, QRectF from qtpy.QtGui import QDoubleValidator, QFocusEvent, QMouseEvent, QTextCursor, QFontMetrics, QIcon, QColor, QPixmap, QPainter, QContextMenuEvent, QKeyEvent from qtpy.QtGui import QDoubleValidator, QFocusEvent, QMouseEvent, QTextCursor, QFontMetrics, QColor, QPixmap, QPainter, QContextMenuEvent, QKeyEvent from utils.fontformat import FontFormat from utils import shared from utils.config import pcfg, save_text_styles, text_styles from utils import config as C from .stylewidgets import Widget, ColorPicker, ClickableLabel, CheckableLabel, TextChecker, FlowLayout, ScrollBar from .stylewidgets import Widget, ColorPicker, ClickableLabel, CheckableLabel, TextChecker, ScrollBar, ViewWidget from .flow_layout import FlowLayout from .textitem import TextBlkItem from .text_graphical_effect import TextEffectPanel from . import funcmaps as FM Loading Loading @@ -352,14 +353,6 @@ class FontFamilyComboBox(QFontComboBox): self.apply_fontfamily() CHEVRON_SIZE = 20 def chevron_down(): return QIcon(r'icons/chevron-down.svg').pixmap(CHEVRON_SIZE, CHEVRON_SIZE, mode=QIcon.Mode.Normal) def chevron_right(): return QIcon(r'icons/chevron-right.svg').pixmap(CHEVRON_SIZE, CHEVRON_SIZE, mode=QIcon.Mode.Normal) class StyleLabel(QLineEdit): edit_finished = Signal() Loading Loading @@ -820,92 +813,19 @@ class TextStyleArea(QScrollArea): return super().contextMenuEvent(e) class ExpandLabel(Widget): clicked = Signal() def __init__(self, text=None, parent=None, expanded=False, *args, **kwargs): super().__init__(parent=parent, *args, **kwargs) self.textlabel = QLabel(self) self.textlabel.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, True) font = self.textlabel.font() if shared.ON_MACOS: font.setPointSize(13) else: font.setPointSizeF(10) self.textlabel.setFont(font) self.arrowlabel = QLabel(self) self.arrowlabel.setFixedSize(CHEVRON_SIZE, CHEVRON_SIZE) self.arrowlabel.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, True) if text is not None: self.textlabel.setText(text) layout = QHBoxLayout(self) layout.addWidget(self.arrowlabel) layout.addWidget(self.textlabel) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(1) layout.addStretch(-1) self.expanded = False self.setExpand(expanded) self.setFixedHeight(26) def setExpand(self, expand: bool): self.expanded = expand if expand: self.arrowlabel.setPixmap(chevron_down()) else: self.arrowlabel.setPixmap(chevron_right()) def mousePressEvent(self, e: QMouseEvent) -> None: if e.button() == Qt.MouseButton.LeftButton: self.setExpand(not self.expanded) pcfg.expand_tstyle_panel = self.expanded self.clicked.emit() return super().mousePressEvent(e) class TextStylePanel(Widget): def __init__(self, text=None, parent=None, expanded=True, *args, **kwargs): super().__init__(parent=parent, *args, **kwargs) self.title_label = ExpandLabel(text, self, expanded=expanded) self.style_area = TextStyleArea(self) layout = QVBoxLayout(self) layout.addWidget(self.title_label) layout.addWidget(self.style_area) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) if not expanded: self.style_area.hide() self.title_label.clicked.connect(self.on_title_label_clicked) self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Maximum) def expand(self): if not self.title_label.expanded: self.title_label.setExpand(True) if self.style_area.isHidden(): self.style_area.show() def on_title_label_clicked(self): if self.title_label.expanded: self.style_area.show() else: self.style_area.hide() class TextStylePanel(ViewWidget): def setTitle(self, text: str): self.title_label.textlabel.setText(text) def __init__(self, text=None, parent=None, *args, **kwargs): def elidedText(self, text: str): fm = QFontMetrics(self.title_label.font()) return fm.elidedText(text, Qt.TextElideMode.ElideRight, self.style_area.width() - 40) style_area = TextStyleArea() super().__init__(style_area, text=text, parent=parent, *args, **kwargs) self.style_area = style_area def title(self) -> str: return self.title_label.textlabel.text() self.register_view_widget( 'show_text_style_preset', 'expand_tstyle_panel', self.tr('Show Text Style Panel') ) class FontFormatPanel(Widget): Loading Loading @@ -1003,7 +923,7 @@ class FontFormatPanel(Widget): lettersp_hlayout.setSpacing(shared.WIDGET_SPACING_CLOSE) self.global_fontfmt_str = self.tr("Global Font Format") self.textstyle_panel = TextStylePanel(self.global_fontfmt_str, parent=self, expanded=pcfg.expand_tstyle_panel) self.textstyle_panel = TextStylePanel(self.global_fontfmt_str, parent=self) self.textstyle_panel.style_area.active_text_style_label_changed.connect(self.on_active_textstyle_label_changed) self.textstyle_panel.style_area.active_stylename_edited.connect(self.on_active_stylename_edited) Loading
ui/global_search_widget.py +2 −1 Original line number Diff line number Diff line Loading @@ -10,7 +10,8 @@ from utils.logger import logger as LOGGER from .page_search_widget import SearchEditor, HighlightMatched, SEARCHRST_HIGHLIGHT_COLOR from .misc import doc_replace from utils.config import pcfg from .stylewidgets import Widget, NoBorderPushBtn, ProgressMessageBox from .stylewidgets import Widget, NoBorderPushBtn from .message import ProgressMessageBox from .textitem import TextBlkItem, TextBlock from .textedit_area import TransPairWidget, SourceTextEdit, TransTextEdit from .config_proj import ProjImgTrans Loading
ui/io_thread.py +1 −1 Original line number Diff line number Diff line Loading @@ -10,7 +10,7 @@ from utils.logger import logger as LOGGER from utils.io_utils import imread, imwrite from utils import create_error_dialog from .config_proj import ProjImgTrans from .stylewidgets import ProgressMessageBox from .message import ProgressMessageBox class ThreadBase(QThread): Loading