From fdc72a1146aa4280e38451d9c73142d1dc824db9 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Thu, 27 Nov 2025 08:55:28 +1100 Subject: [PATCH 1/7] Update icon again to remove background --- CHANGELOG.md | 4 ++++ bouquin/icons/bouquin.svg | 19 ++++--------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 595c060..2a1f513 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.5.2 + + * Update icon again to remove background + # 0.5.1 * Try to address Noto Sans font issue that works for both numbers and checkbox/bullets. diff --git a/bouquin/icons/bouquin.svg b/bouquin/icons/bouquin.svg index e3d5e51..b282050 100644 --- a/bouquin/icons/bouquin.svg +++ b/bouquin/icons/bouquin.svg @@ -4,21 +4,10 @@ viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" > - - - From 576dc435ef140d034a1fd25122ff13228ff199f9 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Thu, 27 Nov 2025 09:45:15 +1100 Subject: [PATCH 2/7] Adjust History icon and reorder toolbar items. Try to address checkbox/bullet size issues (again) --- CHANGELOG.md | 2 ++ bouquin/markdown_editor.py | 16 ++++++++++++++++ bouquin/markdown_highlighter.py | 26 ++++++++++++++++++++++++-- bouquin/toolbar.py | 28 ++++++++++++++-------------- 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a1f513..3e2d232 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # 0.5.2 * Update icon again to remove background + * Adjust History icon and reorder toolbar items + * Try to address checkbox/bullet size issues (again) # 0.5.1 diff --git a/bouquin/markdown_editor.py b/bouquin/markdown_editor.py index 27850f6..ac8a849 100644 --- a/bouquin/markdown_editor.py +++ b/bouquin/markdown_editor.py @@ -119,6 +119,22 @@ class MarkdownEditor(QTextEdit): self._apply_code_block_spacing() QTimer.singleShot(0, self._update_code_block_row_backgrounds) + def setFont(self, font: QFont) -> None: # type: ignore[override] + """ + Ensure that whenever the base editor font changes, our highlighter + re-computes checkbox / bullet formats. + """ + # Keep qfont in sync + self.qfont = QFont(font) + super().setFont(self.qfont) + + # If the highlighter is already attached, let it rebuild its formats + highlighter = getattr(self, "highlighter", None) + if highlighter is not None: + refresh = getattr(highlighter, "refresh_for_font_change", None) + if callable(refresh): + refresh() + def showEvent(self, e): super().showEvent(e) # First time the widget is shown, Qt may rebuild layout once more. diff --git a/bouquin/markdown_highlighter.py b/bouquin/markdown_highlighter.py index 7674d1b..f9826ff 100644 --- a/bouquin/markdown_highlighter.py +++ b/bouquin/markdown_highlighter.py @@ -6,6 +6,7 @@ from PySide6.QtGui import ( QColor, QFont, QFontDatabase, + QFontMetrics, QGuiApplication, QPalette, QSyntaxHighlighter, @@ -33,6 +34,14 @@ class MarkdownHighlighter(QSyntaxHighlighter): self._setup_formats() self.rehighlight() + def refresh_for_font_change(self) -> None: + """ + Called when the editor's base font changes (zoom / settings). + It rebuilds any formats that depend on the editor font metrics. + """ + self._setup_formats() + self.rehighlight() + def _setup_formats(self): """Setup text formats for different markdown elements.""" @@ -110,8 +119,21 @@ class MarkdownHighlighter(QSyntaxHighlighter): # Use Symbols font for checkbox and bullet glyphs if present if self._editor is not None and hasattr(self._editor, "symbols_font_family"): - base_size = self._editor.qfont.pointSize() - symbols_font = QFont(self._editor.symbols_font_family, base_size) + base_font = QFont(self._editor.qfont) # copy of editor font + symbols_font = QFont(self._editor.symbols_font_family) + symbols_font.setPointSizeF(base_font.pointSizeF()) + + base_metrics = QFontMetrics(base_font) + sym_metrics = QFontMetrics(symbols_font) + + # If Symbols glyphs are noticeably shorter than the text, + # scale them up so the visual heights roughly match. + if sym_metrics.height() > 0: + ratio = base_metrics.height() / sym_metrics.height() + if ratio > 1.05: # more than ~5% smaller + ratio = min(ratio, 1.4) # Oh, Tod, Tod. Don't overdo it. + symbols_font.setPointSizeF(symbols_font.pointSizeF() * ratio) + self.checkbox_format.setFont(symbols_font) self.bullet_format.setFont(symbols_font) diff --git a/bouquin/toolbar.py b/bouquin/toolbar.py index cba1820..c4274a4 100644 --- a/bouquin/toolbar.py +++ b/bouquin/toolbar.py @@ -100,6 +100,17 @@ class ToolBar(QToolBar): self.actCheckboxes.setToolTip(strings._("toolbar_toggle_checkboxes")) self.actCheckboxes.triggered.connect(self.checkboxesRequested) + # Images + self.actInsertImg = QAction("📸", self) + self.actInsertImg.setToolTip(strings._("insert_images")) + self.actInsertImg.setShortcut("Ctrl+Shift+I") + self.actInsertImg.triggered.connect(self.insertImageRequested) + + # History button + self.actHistory = QAction("🔁", self) + self.actHistory.setToolTip(strings._("history")) + self.actHistory.triggered.connect(self.historyRequested) + # Alarm / reminder self.actAlarm = QAction("⏰", self) self.actAlarm.setToolTip(strings._("toolbar_alarm")) @@ -115,17 +126,6 @@ class ToolBar(QToolBar): self.actTable.setToolTip(strings._("toolbar_insert_table")) self.actTable.triggered.connect(self.tableRequested) - # Images - self.actInsertImg = QAction("📸", self) - self.actInsertImg.setToolTip(strings._("insert_images")) - self.actInsertImg.setShortcut("Ctrl+Shift+I") - self.actInsertImg.triggered.connect(self.insertImageRequested) - - # History button - self.actHistory = QAction("⎌", self) - self.actHistory.setToolTip(strings._("history")) - self.actHistory.triggered.connect(self.historyRequested) - # Set exclusive buttons in QActionGroups self.grpHeadings = QActionGroup(self) self.grpHeadings.setExclusive(True) @@ -162,10 +162,10 @@ class ToolBar(QToolBar): self.actBullets, self.actNumbers, self.actCheckboxes, - self.actAlarm, - self.actTimer, self.actTable, self.actInsertImg, + self.actAlarm, + self.actTimer, self.actHistory, ] ) @@ -195,7 +195,7 @@ class ToolBar(QToolBar): self._style_letter_button(self.actTable, "⊞") # History - self._style_letter_button(self.actHistory, "⎌") + self._style_letter_button(self.actHistory, "🔁") def _style_letter_button( self, From 917e51aa0b845b36f3da7e1250f14e30432c59a6 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Thu, 27 Nov 2025 09:56:29 +1100 Subject: [PATCH 3/7] Use same alarm icon for the Reminders sidebar widget --- bouquin/reminders.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bouquin/reminders.py b/bouquin/reminders.py index f99eef7..5306206 100644 --- a/bouquin/reminders.py +++ b/bouquin/reminders.py @@ -191,7 +191,7 @@ class UpcomingRemindersWidget(QFrame): self.toggle_btn.clicked.connect(self._on_toggle) self.add_btn = QToolButton() - self.add_btn.setIcon(self.style().standardIcon(QStyle.SP_FileDialogNewFolder)) + self.add_btn.setText("⏰") self.add_btn.setToolTip("Add Reminder") self.add_btn.setAutoRaise(True) self.add_btn.clicked.connect(self._add_reminder) From 5a54d809eda8de63429f281d7fa76473cc22ba54 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Thu, 27 Nov 2025 09:57:14 +1100 Subject: [PATCH 4/7] Fix HTML export of markdown (with newlines, tables and other styling preserved) --- CHANGELOG.md | 1 + bouquin/db.py | 26 +++++++++++++++++++++++--- poetry.lock | 17 ++++++++++++++++- pyproject.toml | 1 + 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e2d232..4b2e036 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ * Update icon again to remove background * Adjust History icon and reorder toolbar items * Try to address checkbox/bullet size issues (again) + * Fix HTML export of markdown (with newlines, tables and other styling preserved) # 0.5.1 diff --git a/bouquin/db.py b/bouquin/db.py index d6211f5..ba6b6ce 100644 --- a/bouquin/db.py +++ b/bouquin/db.py @@ -5,6 +5,7 @@ import datetime as _dt import hashlib import html import json +import markdown import re from dataclasses import dataclass @@ -440,14 +441,33 @@ class DBManager: '', '', f"{html.escape(title)}", - "", + "", "", f"

{html.escape(title)}

", ] for d, c in entries: + body_html = markdown.markdown( + c, + extensions=[ + "extra", + "nl2br", + ], + output_format="html5", + ) + parts.append( - f"
{c}
" + f"
" + f"
" + f"
{body_html}
" + f"
" ) parts.append("") diff --git a/poetry.lock b/poetry.lock index ac46700..b968699 100644 --- a/poetry.lock +++ b/poetry.lock @@ -307,6 +307,21 @@ files = [ {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, ] +[[package]] +name = "markdown" +version = "3.10" +description = "Python implementation of John Gruber's Markdown." +optional = false +python-versions = ">=3.10" +files = [ + {file = "markdown-3.10-py3-none-any.whl", hash = "sha256:b5b99d6951e2e4948d939255596523444c0e677c669700b1d17aa4a8a464cb7c"}, + {file = "markdown-3.10.tar.gz", hash = "sha256:37062d4f2aa4b2b6b32aefb80faa300f82cc790cb949a35b8caede34f2b68c0e"}, +] + +[package.extras] +docs = ["mdx_gh_links (>=0.2)", "mkdocs (>=1.6)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] +testing = ["coverage", "pyyaml"] + [[package]] name = "packaging" version = "25.0" @@ -744,4 +759,4 @@ zstd = ["zstandard (>=0.18.0)"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.14" -content-hash = "d5fd8ea759b6bd3f23336930bdce9241659256ed918ec31746787cc86e817235" +content-hash = "86db2b4d6498ce9eba7fa9aedf9ce58fec6a63542b5f3bdb3cf6c4067e5b87df" diff --git a/pyproject.toml b/pyproject.toml index 6f13468..3d46c7e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ python = ">=3.10,<3.14" pyside6 = ">=6.8.1,<7.0.0" sqlcipher3-wheels = "^0.5.5.post0" requests = "^2.32.5" +markdown = "^3.10" [tool.poetry.scripts] bouquin = "bouquin.__main__:main" From 219b35856976e4349ca264da043d9a34d67d6edf Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Thu, 27 Nov 2025 09:57:26 +1100 Subject: [PATCH 5/7] remove problematic interactive test --- tests/test_reminders.py | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/tests/test_reminders.py b/tests/test_reminders.py index 94be08c..c003d86 100644 --- a/tests/test_reminders.py +++ b/tests/test_reminders.py @@ -765,35 +765,6 @@ def test_reminder_not_today_skipped(qtbot, fresh_db): assert len(triggered_texts) == 0 -def test_reminder_context_menu_single_item(qtbot, fresh_db): - """Test context menu for a single reminder item.""" - reminder = Reminder( - id=None, - text="Test reminder", - reminder_type=ReminderType.ONCE, - time_str="14:30", - date_iso=date.today().isoformat(), - active=True, - ) - fresh_db.save_reminder(reminder) - - reminders_widget = UpcomingRemindersWidget(fresh_db) - qtbot.addWidget(reminders_widget) - reminders_widget.show() - - # Refresh to populate the list - reminders_widget.refresh() - - # Select the first item - if reminders_widget.reminder_list.count() > 0: - reminders_widget.reminder_list.setCurrentRow(0) - - # Show context menu (won't actually display in tests) - reminders_widget._show_reminder_context_menu( - reminders_widget.reminder_list.pos() - ) - - def test_reminder_context_menu_no_selection(qtbot, fresh_db): """Test context menu with no selection returns early.""" reminders_widget = UpcomingRemindersWidget(fresh_db) From 73aa536a3264095e4da6fbaab6dd55d50dde195c Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Thu, 27 Nov 2025 09:57:39 +1100 Subject: [PATCH 6/7] Small README tweak --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cdfdfc5..5cf77e5 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ ## Introduction -Bouquin ("Book-ahn") is a notebook and planner application written in Python, PyQt and SQLCipher. +Bouquin ("Book-ahn") is a notebook and planner application written in Python, Qt and SQLCipher. It is designed to treat each day as its own 'page', complete with Markdown rendering, tagging, search, reminders and time logging for those of us who need to keep track of not just TODOs, but From 81cf878ffdc9b5c38fb6d064bcdfb2f9b2121feb Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Thu, 27 Nov 2025 09:57:49 +1100 Subject: [PATCH 7/7] 0.5.2 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3d46c7e..ce8e44a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bouquin" -version = "0.5.1" +version = "0.5.2" description = "Bouquin is a simple, opinionated notebook application written in Python, PyQt and SQLCipher." authors = ["Miguel Jacq "] readme = "README.md"