More styling shenanigans, fix an export typo bug
This commit is contained in:
parent
03b10ab692
commit
f8e0a7f179
4 changed files with 213 additions and 50 deletions
|
|
@ -1,3 +1,9 @@
|
||||||
|
# 0.1.9
|
||||||
|
|
||||||
|
* More styling/toolbar fixes to support toggled-on styles, exclusive styles (e.g it should not be
|
||||||
|
possible to set both H1 and H2 at once)
|
||||||
|
* Fix small bug in export of HTML or arbitrary extension
|
||||||
|
|
||||||
# 0.1.8
|
# 0.1.8
|
||||||
|
|
||||||
* Fix saving the new key to the settings if the 'remember key' option was set and the DB was rekeyed
|
* Fix saving the new key to the settings if the 'remember key' option was set and the DB was rekeyed
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ class Editor(QTextEdit):
|
||||||
_URL_RX = QRegularExpression(r'((?:https?://|www\.)[^\s<>"\'<>]+)')
|
_URL_RX = QRegularExpression(r'((?:https?://|www\.)[^\s<>"\'<>]+)')
|
||||||
_CODE_BG = QColor(245, 245, 245)
|
_CODE_BG = QColor(245, 245, 245)
|
||||||
_CODE_FRAME_PROP = int(QTextFrameFormat.UserProperty) + 100 # marker for our frames
|
_CODE_FRAME_PROP = int(QTextFrameFormat.UserProperty) + 100 # marker for our frames
|
||||||
|
_HEADING_SIZES = (24.0, 18.0, 14.0)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
@ -40,6 +41,21 @@ class Editor(QTextEdit):
|
||||||
self.textChanged.connect(self._linkify_document)
|
self.textChanged.connect(self._linkify_document)
|
||||||
self.viewport().setMouseTracking(True)
|
self.viewport().setMouseTracking(True)
|
||||||
|
|
||||||
|
def _approx(self, a: float, b: float, eps: float = 0.5) -> bool:
|
||||||
|
return abs(float(a) - float(b)) <= eps
|
||||||
|
|
||||||
|
def _is_heading_typing(self) -> bool:
|
||||||
|
"""Is the current *insertion* format using a heading size?"""
|
||||||
|
s = self.currentCharFormat().fontPointSize() or self.font().pointSizeF()
|
||||||
|
return any(self._approx(s, h) for h in self._HEADING_SIZES)
|
||||||
|
|
||||||
|
def _apply_normal_typing(self):
|
||||||
|
"""Switch the *insertion* format to Normal (default size, normal weight)."""
|
||||||
|
nf = QTextCharFormat()
|
||||||
|
nf.setFontPointSize(self.font().pointSizeF())
|
||||||
|
nf.setFontWeight(QFont.Weight.Normal)
|
||||||
|
self.mergeCurrentCharFormat(nf)
|
||||||
|
|
||||||
def _find_code_frame(self, cursor=None):
|
def _find_code_frame(self, cursor=None):
|
||||||
"""Return the nearest ancestor frame that's one of our code frames, else None."""
|
"""Return the nearest ancestor frame that's one of our code frames, else None."""
|
||||||
if cursor is None:
|
if cursor is None:
|
||||||
|
|
@ -139,6 +155,7 @@ class Editor(QTextEdit):
|
||||||
|
|
||||||
if key in (Qt.Key_Return, Qt.Key_Enter):
|
if key in (Qt.Key_Return, Qt.Key_Enter):
|
||||||
c = self.textCursor()
|
c = self.textCursor()
|
||||||
|
|
||||||
# If we're on an empty line inside a code frame, consume Enter and jump out
|
# If we're on an empty line inside a code frame, consume Enter and jump out
|
||||||
if c.block().length() == 1:
|
if c.block().length() == 1:
|
||||||
frame = self._find_code_frame(c)
|
frame = self._find_code_frame(c)
|
||||||
|
|
@ -149,6 +166,13 @@ class Editor(QTextEdit):
|
||||||
super().insertPlainText("\n") # start a normal paragraph
|
super().insertPlainText("\n") # start a normal paragraph
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Follow-on style: if we typed a heading and press Enter at end of block,
|
||||||
|
# new paragraph should revert to Normal.
|
||||||
|
if not c.hasSelection() and c.atBlockEnd() and self._is_heading_typing():
|
||||||
|
super().keyPressEvent(e) # insert the new paragraph
|
||||||
|
self._apply_normal_typing() # make the *new* paragraph Normal for typing
|
||||||
|
return
|
||||||
|
|
||||||
# otherwise default handling
|
# otherwise default handling
|
||||||
return super().keyPressEvent(e)
|
return super().keyPressEvent(e)
|
||||||
|
|
||||||
|
|
@ -158,27 +182,31 @@ class Editor(QTextEdit):
|
||||||
self.setCurrentCharFormat(nf)
|
self.setCurrentCharFormat(nf)
|
||||||
|
|
||||||
def _break_anchor_for_next_char(self):
|
def _break_anchor_for_next_char(self):
|
||||||
c = self.textCursor()
|
"""
|
||||||
fmt = c.charFormat()
|
Ensure the *next* typed character is not part of a hyperlink.
|
||||||
if fmt.isAnchor() or fmt.fontUnderline() or fmt.foreground().style() != 0:
|
Only strips link-specific attributes; leaves bold/italic/underline etc intact.
|
||||||
# clone, then strip just the link-specific bits so the next char is plain text
|
"""
|
||||||
nf = QTextCharFormat(fmt)
|
# What we're about to type with
|
||||||
|
ins_fmt = self.currentCharFormat()
|
||||||
|
# What the cursor is sitting on
|
||||||
|
cur_fmt = self.textCursor().charFormat()
|
||||||
|
|
||||||
|
# Do nothing unless either side indicates we're in/propagating an anchor
|
||||||
|
if not (ins_fmt.isAnchor() or cur_fmt.isAnchor()):
|
||||||
|
return
|
||||||
|
|
||||||
|
nf = QTextCharFormat(ins_fmt)
|
||||||
nf.setAnchor(False)
|
nf.setAnchor(False)
|
||||||
nf.setFontUnderline(False)
|
|
||||||
nf.clearForeground()
|
|
||||||
try:
|
|
||||||
nf.setAnchorHref("")
|
nf.setAnchorHref("")
|
||||||
except AttributeError:
|
|
||||||
nf.setAnchorNames([])
|
|
||||||
self.setCurrentCharFormat(nf)
|
self.setCurrentCharFormat(nf)
|
||||||
|
|
||||||
def merge_on_sel(self, fmt):
|
def merge_on_sel(self, fmt):
|
||||||
"""
|
"""
|
||||||
Sets the styling on the selected characters.
|
Sets the styling on the selected characters or the insertion position.
|
||||||
"""
|
"""
|
||||||
cursor = self.textCursor()
|
cursor = self.textCursor()
|
||||||
if not cursor.hasSelection():
|
if cursor.hasSelection():
|
||||||
cursor.select(cursor.SelectionType.WordUnderCursor)
|
|
||||||
cursor.mergeCharFormat(fmt)
|
cursor.mergeCharFormat(fmt)
|
||||||
self.mergeCurrentCharFormat(fmt)
|
self.mergeCurrentCharFormat(fmt)
|
||||||
|
|
||||||
|
|
@ -265,15 +293,25 @@ class Editor(QTextEdit):
|
||||||
c.endEditBlock()
|
c.endEditBlock()
|
||||||
|
|
||||||
@Slot(int)
|
@Slot(int)
|
||||||
def apply_heading(self, size):
|
def apply_heading(self, size: int):
|
||||||
fmt = QTextCharFormat()
|
"""
|
||||||
if size:
|
Set heading point size for typing. If there's a selection, also apply bold
|
||||||
fmt.setFontWeight(QFont.Weight.Bold)
|
to that selection (for H1..H3). "Normal" clears bold on the selection.
|
||||||
fmt.setFontPointSize(size)
|
"""
|
||||||
else:
|
base_size = size if size else self.font().pointSizeF()
|
||||||
fmt.setFontWeight(QFont.Weight.Normal)
|
c = self.textCursor()
|
||||||
fmt.setFontPointSize(self.font().pointSizeF())
|
|
||||||
self.merge_on_sel(fmt)
|
# Update the typing (insertion) format to be size only, but don't represent
|
||||||
|
# it as if the Bold style has been toggled on
|
||||||
|
ins = QTextCharFormat()
|
||||||
|
ins.setFontPointSize(base_size)
|
||||||
|
self.mergeCurrentCharFormat(ins)
|
||||||
|
|
||||||
|
# If user selected text, style that text visually as a heading
|
||||||
|
if c.hasSelection():
|
||||||
|
sel = QTextCharFormat(ins)
|
||||||
|
sel.setFontWeight(QFont.Weight.Bold if size else QFont.Weight.Normal)
|
||||||
|
c.mergeCharFormat(sel)
|
||||||
|
|
||||||
def toggle_bullets(self):
|
def toggle_bullets(self):
|
||||||
c = self.textCursor()
|
c = self.textCursor()
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,16 @@ import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from PySide6.QtCore import QDate, QTimer, Qt, QSettings, Slot, QUrl, QEvent
|
from PySide6.QtCore import (
|
||||||
|
QDate,
|
||||||
|
QTimer,
|
||||||
|
Qt,
|
||||||
|
QSettings,
|
||||||
|
Slot,
|
||||||
|
QUrl,
|
||||||
|
QEvent,
|
||||||
|
QSignalBlocker,
|
||||||
|
)
|
||||||
from PySide6.QtGui import (
|
from PySide6.QtGui import (
|
||||||
QAction,
|
QAction,
|
||||||
QCursor,
|
QCursor,
|
||||||
|
|
@ -12,6 +21,7 @@ from PySide6.QtGui import (
|
||||||
QFont,
|
QFont,
|
||||||
QGuiApplication,
|
QGuiApplication,
|
||||||
QTextCharFormat,
|
QTextCharFormat,
|
||||||
|
QTextListFormat,
|
||||||
)
|
)
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import (
|
||||||
QCalendarWidget,
|
QCalendarWidget,
|
||||||
|
|
@ -150,6 +160,9 @@ class MainWindow(QMainWindow):
|
||||||
self.toolBar.alignRequested.connect(self.editor.setAlignment)
|
self.toolBar.alignRequested.connect(self.editor.setAlignment)
|
||||||
self.toolBar.historyRequested.connect(self._open_history)
|
self.toolBar.historyRequested.connect(self._open_history)
|
||||||
|
|
||||||
|
self.editor.currentCharFormatChanged.connect(lambda _f: self._sync_toolbar())
|
||||||
|
self.editor.cursorPositionChanged.connect(self._sync_toolbar)
|
||||||
|
|
||||||
split = QSplitter()
|
split = QSplitter()
|
||||||
split.addWidget(left_panel)
|
split.addWidget(left_panel)
|
||||||
split.addWidget(self.editor)
|
split.addWidget(self.editor)
|
||||||
|
|
@ -315,6 +328,61 @@ class MainWindow(QMainWindow):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# --- UI handlers ---------------------------------------------------------
|
# --- UI handlers ---------------------------------------------------------
|
||||||
|
|
||||||
|
def _sync_toolbar(self):
|
||||||
|
fmt = self.editor.currentCharFormat()
|
||||||
|
c = self.editor.textCursor()
|
||||||
|
bf = c.blockFormat()
|
||||||
|
|
||||||
|
# Block signals so setChecked() doesn't re-trigger actions
|
||||||
|
blocker1 = QSignalBlocker(self.toolBar.actBold)
|
||||||
|
blocker2 = QSignalBlocker(self.toolBar.actItalic)
|
||||||
|
blocker3 = QSignalBlocker(self.toolBar.actUnderline)
|
||||||
|
blocker4 = QSignalBlocker(self.toolBar.actStrike)
|
||||||
|
|
||||||
|
self.toolBar.actBold.setChecked(fmt.fontWeight() == QFont.Weight.Bold)
|
||||||
|
self.toolBar.actItalic.setChecked(fmt.fontItalic())
|
||||||
|
self.toolBar.actUnderline.setChecked(fmt.fontUnderline())
|
||||||
|
self.toolBar.actStrike.setChecked(fmt.fontStrikeOut())
|
||||||
|
|
||||||
|
# Headings: decide which to check by current point size
|
||||||
|
def _approx(a, b, eps=0.5): # small float tolerance
|
||||||
|
return abs(float(a) - float(b)) <= eps
|
||||||
|
|
||||||
|
cur_size = fmt.fontPointSize() or self.editor.font().pointSizeF()
|
||||||
|
|
||||||
|
bH1 = _approx(cur_size, 24)
|
||||||
|
bH2 = _approx(cur_size, 18)
|
||||||
|
bH3 = _approx(cur_size, 14)
|
||||||
|
|
||||||
|
b1 = QSignalBlocker(self.toolBar.actH1)
|
||||||
|
b2 = QSignalBlocker(self.toolBar.actH2)
|
||||||
|
b3 = QSignalBlocker(self.toolBar.actH3)
|
||||||
|
bN = QSignalBlocker(self.toolBar.actNormal)
|
||||||
|
|
||||||
|
self.toolBar.actH1.setChecked(bH1)
|
||||||
|
self.toolBar.actH2.setChecked(bH2)
|
||||||
|
self.toolBar.actH3.setChecked(bH3)
|
||||||
|
self.toolBar.actNormal.setChecked(not (bH1 or bH2 or bH3))
|
||||||
|
|
||||||
|
# Lists
|
||||||
|
lst = c.currentList()
|
||||||
|
bullets_on = lst and lst.format().style() == QTextListFormat.Style.ListDisc
|
||||||
|
numbers_on = lst and lst.format().style() == QTextListFormat.Style.ListDecimal
|
||||||
|
QSignalBlocker(self.toolBar.actBullets)
|
||||||
|
QSignalBlocker(self.toolBar.actNumbers)
|
||||||
|
self.toolBar.actBullets.setChecked(bool(bullets_on))
|
||||||
|
self.toolBar.actNumbers.setChecked(bool(numbers_on))
|
||||||
|
|
||||||
|
# Alignment
|
||||||
|
align = bf.alignment() & Qt.AlignHorizontal_Mask
|
||||||
|
QSignalBlocker(self.toolBar.actAlignL)
|
||||||
|
self.toolBar.actAlignL.setChecked(align == Qt.AlignLeft)
|
||||||
|
QSignalBlocker(self.toolBar.actAlignC)
|
||||||
|
self.toolBar.actAlignC.setChecked(align == Qt.AlignHCenter)
|
||||||
|
QSignalBlocker(self.toolBar.actAlignR)
|
||||||
|
self.toolBar.actAlignR.setChecked(align == Qt.AlignRight)
|
||||||
|
|
||||||
def _current_date_iso(self) -> str:
|
def _current_date_iso(self) -> str:
|
||||||
d = self.calendar.selectedDate()
|
d = self.calendar.selectedDate()
|
||||||
return f"{d.year():04d}-{d.month():02d}-{d.day():02d}"
|
return f"{d.year():04d}-{d.month():02d}-{d.day():02d}"
|
||||||
|
|
@ -518,9 +586,9 @@ class MainWindow(QMainWindow):
|
||||||
elif selected_filter.startswith("CSV"):
|
elif selected_filter.startswith("CSV"):
|
||||||
self.db.export_csv(entries, filename)
|
self.db.export_csv(entries, filename)
|
||||||
elif selected_filter.startswith("HTML"):
|
elif selected_filter.startswith("HTML"):
|
||||||
self.bd.export_html(entries, filename)
|
self.db.export_html(entries, filename)
|
||||||
else:
|
else:
|
||||||
self.bd.export_by_extension(entries, filename)
|
self.db.export_by_extension(entries, filename)
|
||||||
|
|
||||||
QMessageBox.information(self, "Export complete", f"Saved to:\n{filename}")
|
QMessageBox.information(self, "Export complete", f"Saved to:\n{filename}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from PySide6.QtCore import Signal, Qt
|
from PySide6.QtCore import Signal, Qt
|
||||||
from PySide6.QtGui import QAction, QKeySequence, QFont, QFontDatabase
|
from PySide6.QtGui import QAction, QKeySequence, QFont, QFontDatabase, QActionGroup
|
||||||
from PySide6.QtWidgets import QToolBar
|
from PySide6.QtWidgets import QToolBar
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -25,54 +25,81 @@ class ToolBar(QToolBar):
|
||||||
self._apply_toolbar_styles()
|
self._apply_toolbar_styles()
|
||||||
|
|
||||||
def _build_actions(self):
|
def _build_actions(self):
|
||||||
self.actBold = QAction("Bold", self)
|
self.actBold = QAction("B", self)
|
||||||
|
self.actBold.setToolTip("Bold")
|
||||||
|
self.actBold.setCheckable(True)
|
||||||
self.actBold.setShortcut(QKeySequence.Bold)
|
self.actBold.setShortcut(QKeySequence.Bold)
|
||||||
self.actBold.triggered.connect(self.boldRequested)
|
self.actBold.triggered.connect(self.boldRequested)
|
||||||
|
|
||||||
self.actItalic = QAction("Italic", self)
|
self.actItalic = QAction("I", self)
|
||||||
|
self.actItalic.setToolTip("Italic")
|
||||||
|
self.actItalic.setCheckable(True)
|
||||||
self.actItalic.setShortcut(QKeySequence.Italic)
|
self.actItalic.setShortcut(QKeySequence.Italic)
|
||||||
self.actItalic.triggered.connect(self.italicRequested)
|
self.actItalic.triggered.connect(self.italicRequested)
|
||||||
|
|
||||||
self.actUnderline = QAction("Underline", self)
|
self.actUnderline = QAction("U", self)
|
||||||
|
self.actUnderline.setToolTip("Underline")
|
||||||
|
self.actUnderline.setCheckable(True)
|
||||||
self.actUnderline.setShortcut(QKeySequence.Underline)
|
self.actUnderline.setShortcut(QKeySequence.Underline)
|
||||||
self.actUnderline.triggered.connect(self.underlineRequested)
|
self.actUnderline.triggered.connect(self.underlineRequested)
|
||||||
|
|
||||||
self.actStrike = QAction("Strikethrough", self)
|
self.actStrike = QAction("S", self)
|
||||||
|
self.actStrike.setToolTip("Strikethrough")
|
||||||
|
self.actStrike.setCheckable(True)
|
||||||
self.actStrike.setShortcut("Ctrl+-")
|
self.actStrike.setShortcut("Ctrl+-")
|
||||||
self.actStrike.triggered.connect(self.strikeRequested)
|
self.actStrike.triggered.connect(self.strikeRequested)
|
||||||
|
|
||||||
self.actCode = QAction("Inline code", self)
|
self.actCode = QAction("</>", self)
|
||||||
|
self.actCode.setToolTip("Code block")
|
||||||
self.actCode.setShortcut("Ctrl+`")
|
self.actCode.setShortcut("Ctrl+`")
|
||||||
self.actCode.triggered.connect(self.codeRequested)
|
self.actCode.triggered.connect(self.codeRequested)
|
||||||
|
|
||||||
# Headings
|
# Headings
|
||||||
self.actH1 = QAction("Heading 1", self)
|
self.actH1 = QAction("H1", self)
|
||||||
self.actH2 = QAction("Heading 2", self)
|
self.actH1.setToolTip("Heading 1")
|
||||||
self.actH3 = QAction("Heading 3", self)
|
self.actH1.setCheckable(True)
|
||||||
self.actNormal = QAction("Normal text", self)
|
|
||||||
self.actH1.setShortcut("Ctrl+1")
|
self.actH1.setShortcut("Ctrl+1")
|
||||||
self.actH2.setShortcut("Ctrl+2")
|
|
||||||
self.actH3.setShortcut("Ctrl+3")
|
|
||||||
self.actNormal.setShortcut("Ctrl+O")
|
|
||||||
self.actH1.triggered.connect(lambda: self.headingRequested.emit(24))
|
self.actH1.triggered.connect(lambda: self.headingRequested.emit(24))
|
||||||
|
self.actH2 = QAction("H2", self)
|
||||||
|
self.actH2.setToolTip("Heading 2")
|
||||||
|
self.actH2.setCheckable(True)
|
||||||
|
self.actH2.setShortcut("Ctrl+2")
|
||||||
self.actH2.triggered.connect(lambda: self.headingRequested.emit(18))
|
self.actH2.triggered.connect(lambda: self.headingRequested.emit(18))
|
||||||
|
self.actH3 = QAction("H3", self)
|
||||||
|
self.actH3.setToolTip("Heading 3")
|
||||||
|
self.actH3.setCheckable(True)
|
||||||
|
self.actH3.setShortcut("Ctrl+3")
|
||||||
self.actH3.triggered.connect(lambda: self.headingRequested.emit(14))
|
self.actH3.triggered.connect(lambda: self.headingRequested.emit(14))
|
||||||
|
self.actNormal = QAction("N", self)
|
||||||
|
self.actNormal.setToolTip("Normal paragraph text")
|
||||||
|
self.actNormal.setCheckable(True)
|
||||||
|
self.actNormal.setShortcut("Ctrl+O")
|
||||||
self.actNormal.triggered.connect(lambda: self.headingRequested.emit(0))
|
self.actNormal.triggered.connect(lambda: self.headingRequested.emit(0))
|
||||||
|
|
||||||
# Lists
|
# Lists
|
||||||
self.actBullets = QAction("Bulleted list", self)
|
self.actBullets = QAction("•", self)
|
||||||
|
self.actBullets.setToolTip("Bulleted list")
|
||||||
|
self.actBullets.setCheckable(True)
|
||||||
self.actBullets.triggered.connect(self.bulletsRequested)
|
self.actBullets.triggered.connect(self.bulletsRequested)
|
||||||
self.actNumbers = QAction("Numbered list", self)
|
self.actNumbers = QAction("1.", self)
|
||||||
|
self.actNumbers.setToolTip("Numbered list")
|
||||||
|
self.actNumbers.setCheckable(True)
|
||||||
self.actNumbers.triggered.connect(self.numbersRequested)
|
self.actNumbers.triggered.connect(self.numbersRequested)
|
||||||
|
|
||||||
# Alignment
|
# Alignment
|
||||||
self.actAlignL = QAction("Align left", self)
|
self.actAlignL = QAction("L", self)
|
||||||
self.actAlignC = QAction("Align center", self)
|
self.actAlignL.setToolTip("Align Left")
|
||||||
self.actAlignR = QAction("Align right", self)
|
self.actAlignL.setCheckable(True)
|
||||||
self.actAlignL.triggered.connect(lambda: self.alignRequested.emit(Qt.AlignLeft))
|
self.actAlignL.triggered.connect(lambda: self.alignRequested.emit(Qt.AlignLeft))
|
||||||
|
self.actAlignC = QAction("C", self)
|
||||||
|
self.actAlignC.setToolTip("Align Center")
|
||||||
|
self.actAlignC.setCheckable(True)
|
||||||
self.actAlignC.triggered.connect(
|
self.actAlignC.triggered.connect(
|
||||||
lambda: self.alignRequested.emit(Qt.AlignHCenter)
|
lambda: self.alignRequested.emit(Qt.AlignHCenter)
|
||||||
)
|
)
|
||||||
|
self.actAlignR = QAction("R", self)
|
||||||
|
self.actAlignR.setToolTip("Align Right")
|
||||||
|
self.actAlignR.setCheckable(True)
|
||||||
self.actAlignR.triggered.connect(
|
self.actAlignR.triggered.connect(
|
||||||
lambda: self.alignRequested.emit(Qt.AlignRight)
|
lambda: self.alignRequested.emit(Qt.AlignRight)
|
||||||
)
|
)
|
||||||
|
|
@ -81,6 +108,28 @@ class ToolBar(QToolBar):
|
||||||
self.actHistory = QAction("History", self)
|
self.actHistory = QAction("History", self)
|
||||||
self.actHistory.triggered.connect(self.historyRequested)
|
self.actHistory.triggered.connect(self.historyRequested)
|
||||||
|
|
||||||
|
# Set exclusive buttons in QActionGroups
|
||||||
|
self.grpHeadings = QActionGroup(self)
|
||||||
|
self.grpHeadings.setExclusive(True)
|
||||||
|
for a in (
|
||||||
|
self.actBold,
|
||||||
|
self.actItalic,
|
||||||
|
self.actUnderline,
|
||||||
|
self.actStrike,
|
||||||
|
self.actH1,
|
||||||
|
self.actH2,
|
||||||
|
self.actH3,
|
||||||
|
self.actNormal,
|
||||||
|
):
|
||||||
|
a.setCheckable(True)
|
||||||
|
a.setActionGroup(self.grpHeadings)
|
||||||
|
|
||||||
|
self.grpAlign = QActionGroup(self)
|
||||||
|
self.grpAlign.setExclusive(True)
|
||||||
|
for a in (self.actAlignL, self.actAlignC, self.actAlignR):
|
||||||
|
a.setActionGroup(self.grpAlign)
|
||||||
|
|
||||||
|
# Add actions
|
||||||
self.addActions(
|
self.addActions(
|
||||||
[
|
[
|
||||||
self.actBold,
|
self.actBold,
|
||||||
|
|
@ -106,7 +155,6 @@ class ToolBar(QToolBar):
|
||||||
self._style_letter_button(self.actItalic, "I", italic=True)
|
self._style_letter_button(self.actItalic, "I", italic=True)
|
||||||
self._style_letter_button(self.actUnderline, "U", underline=True)
|
self._style_letter_button(self.actUnderline, "U", underline=True)
|
||||||
self._style_letter_button(self.actStrike, "S", strike=True)
|
self._style_letter_button(self.actStrike, "S", strike=True)
|
||||||
|
|
||||||
# Monospace look for code; use a fixed font
|
# Monospace look for code; use a fixed font
|
||||||
code_font = QFontDatabase.systemFont(QFontDatabase.FixedFont)
|
code_font = QFontDatabase.systemFont(QFontDatabase.FixedFont)
|
||||||
self._style_letter_button(self.actCode, "</>", custom_font=code_font)
|
self._style_letter_button(self.actCode, "</>", custom_font=code_font)
|
||||||
|
|
@ -139,11 +187,13 @@ class ToolBar(QToolBar):
|
||||||
underline: bool = False,
|
underline: bool = False,
|
||||||
strike: bool = False,
|
strike: bool = False,
|
||||||
custom_font: QFont | None = None,
|
custom_font: QFont | None = None,
|
||||||
|
tooltip: str | None = None,
|
||||||
):
|
):
|
||||||
btn = self.widgetForAction(action)
|
btn = self.widgetForAction(action)
|
||||||
if not btn:
|
if not btn:
|
||||||
return
|
return
|
||||||
btn.setText(text)
|
btn.setText(text)
|
||||||
|
|
||||||
f = custom_font if custom_font is not None else QFont(btn.font())
|
f = custom_font if custom_font is not None else QFont(btn.font())
|
||||||
if custom_font is None:
|
if custom_font is None:
|
||||||
f.setBold(bold)
|
f.setBold(bold)
|
||||||
|
|
@ -153,5 +203,6 @@ class ToolBar(QToolBar):
|
||||||
btn.setFont(f)
|
btn.setFont(f)
|
||||||
|
|
||||||
# Keep accessibility/tooltip readable
|
# Keep accessibility/tooltip readable
|
||||||
btn.setToolTip(action.text())
|
if tooltip:
|
||||||
btn.setAccessibleName(action.text())
|
btn.setToolTip(tooltip)
|
||||||
|
btn.setAccessibleName(tooltip)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue