diff --git a/CHANGELOG.md b/CHANGELOG.md index ee5b362..268726b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,6 @@ * Improve SaveDialog widget width * Make Tags and TimeLog optional features that can be switched on/off in Settings (enabled by default) * Make it possible to change regular text size - * Refactored Settings dialog to use tabs to reduce its size # 0.4.1 diff --git a/bouquin/locales/en.json b/bouquin/locales/en.json index 7ed1dea..9ec462c 100644 --- a/bouquin/locales/en.json +++ b/bouquin/locales/en.json @@ -26,7 +26,7 @@ "close": "Close", "find": "Find", "file": "File", - "locale": "Language", + "locale": "Locale", "locale_restart": "Please restart the application to load the new language.", "settings": "Settings", "theme": "Theme", @@ -98,15 +98,9 @@ "backup_encrypted_notebook": "Backup encrypted notebook", "enter_a_name_for_this_version": "Enter a name for this version", "new_version_i_saved_at": "New version I saved at", - "appearance": "Appearance", - "security": "Security", - "features": "Features", - "database": "Database", "save_key_warning": "If you don't want to be prompted for your encryption key, check this to remember it.\nWARNING: the key is saved to disk and could be recoverable if your disk is compromised.", "lock_screen_when_idle": "Lock screen when idle", "autolock_explanation": "Bouquin will automatically lock the notepad after this length of time, after which you'll need to re-enter the key to unlock it.'nSet to 0 (never) to never lock.", - "font_size": "Font size", - "font_size_explanation": "Changing this value will change the size of all paragraph text in all tabs. It does not affect heading or code block size", "search_for_notes_here": "Search for notes here", "toolbar_format": "Format", "toolbar_bold": "Bold", diff --git a/bouquin/main_window.py b/bouquin/main_window.py index 2065417..019a68d 100644 --- a/bouquin/main_window.py +++ b/bouquin/main_window.py @@ -1078,14 +1078,11 @@ class MainWindow(QMainWindow): save_db_config(self.cfg) # Apply font size change to all open editors - self._apply_font_size_to_all_tabs(new_size) - - def _apply_font_size_to_all_tabs(self, size: int) -> None: for i in range(self.tab_widget.count()): ed = self.tab_widget.widget(i) if not isinstance(ed, MarkdownEditor): continue - ed.qfont.setPointSize(size) + ed.qfont.setPointSize(new_size) ed.setFont(ed.qfont) def _on_font_larger_requested(self) -> None: @@ -1363,14 +1360,11 @@ class MainWindow(QMainWindow): self.cfg.tags = getattr(new_cfg, "tags", self.cfg.tags) self.cfg.time_log = getattr(new_cfg, "time_log", self.cfg.time_log) self.cfg.locale = getattr(new_cfg, "locale", self.cfg.locale) - self.cfg.font_size = getattr(new_cfg, "font_size", self.cfg.font_size) # Persist once save_db_config(self.cfg) # Apply idle setting immediately (restart the timer with new interval if it changed) self._apply_idle_minutes(self.cfg.idle_minutes) - # Apply font size to all tabs - self._apply_font_size_to_all_tabs(self.cfg.font_size) # If the DB path changed, reconnect if self.cfg.path != old_path: diff --git a/bouquin/settings_dialog.py b/bouquin/settings_dialog.py index 226db08..47209ba 100644 --- a/bouquin/settings_dialog.py +++ b/bouquin/settings_dialog.py @@ -6,6 +6,7 @@ from PySide6.QtWidgets import ( QCheckBox, QComboBox, QDialog, + QFormLayout, QFrame, QGroupBox, QLabel, @@ -17,8 +18,6 @@ from PySide6.QtWidgets import ( QSizePolicy, QSpinBox, QMessageBox, - QWidget, - QTabWidget, ) from PySide6.QtCore import Qt, Slot from PySide6.QtGui import QPalette @@ -40,45 +39,14 @@ class SettingsDialog(QDialog): self._db = db self.key = "" - self.current_settings = load_db_config() - - self.setMinimumWidth(480) + form = QFormLayout() + form.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow) + self.setMinimumWidth(560) self.setSizeGripEnabled(True) - # --- Tabs ---------------------------------------------------------- - tabs = QTabWidget() - tabs.setTabPosition(QTabWidget.North) - tabs.setDocumentMode(True) - tabs.setMovable(False) + self.current_settings = load_db_config() - tabs.addTab(self._create_appearance_page(cfg), strings._("appearance")) - tabs.addTab(self._create_features_page(), strings._("features")) - tabs.addTab(self._create_security_page(cfg), strings._("security")) - tabs.addTab(self._create_database_page(), strings._("database")) - - # --- Buttons ------------------------------------------------------- - bb = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Cancel) - bb.accepted.connect(self._save) - bb.rejected.connect(self.reject) - - # Root layout - root = QVBoxLayout(self) - root.setContentsMargins(12, 12, 12, 12) - root.setSpacing(8) - root.addWidget(tabs) - root.addWidget(bb, 0, Qt.AlignRight) - - # ------------------------------------------------------------------ # - # Pages - # ------------------------------------------------------------------ # - - def _create_appearance_page(self, cfg: DBConfig) -> QWidget: - page = QWidget() - layout = QVBoxLayout(page) - layout.setContentsMargins(12, 12, 12, 12) - layout.setSpacing(12) - - # --- Theme group -------------------------------------------------- + # Add theme selection theme_group = QGroupBox(strings._("theme")) theme_layout = QVBoxLayout(theme_group) @@ -86,6 +54,7 @@ class SettingsDialog(QDialog): self.theme_light = QRadioButton(strings._("light")) self.theme_dark = QRadioButton(strings._("dark")) + # Load current theme from settings current_theme = self.current_settings.theme if current_theme == Theme.DARK.value: self.theme_dark.setChecked(True) @@ -98,98 +67,66 @@ class SettingsDialog(QDialog): theme_layout.addWidget(self.theme_light) theme_layout.addWidget(self.theme_dark) - # font size row - font_row = QHBoxLayout() - self.font_heading = QLabel(strings._("font_size")) - self.font_size = QSpinBox() - self.font_size.setRange(1, 24) - self.font_size.setSingleStep(1) - self.font_size.setAccelerated(True) - self.font_size.setValue(getattr(cfg, "font_size", 11)) - font_row.addWidget(self.font_heading) - font_row.addWidget(self.font_size) - font_row.addStretch() - theme_layout.addLayout(font_row) + form.addRow(theme_group) - # explanation - self.font_size_label = QLabel(strings._("font_size_explanation")) - self.font_size_label.setWordWrap(True) - self.font_size_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) - pal = self.font_size_label.palette() - self.font_size_label.setForegroundRole(QPalette.PlaceholderText) - self.font_size_label.setPalette(pal) - - font_exp_row = QHBoxLayout() - font_exp_row.setContentsMargins(24, 0, 0, 0) - font_exp_row.addWidget(self.font_size_label) - theme_layout.addLayout(font_exp_row) - - layout.addWidget(theme_group) - - # --- Locale group ------------------------------------------------- + # Locale settings locale_group = QGroupBox(strings._("locale")) locale_layout = QVBoxLayout(locale_group) + locale_layout.setContentsMargins(12, 8, 12, 12) + locale_layout.setSpacing(6) self.locale_combobox = QComboBox() self.locale_combobox.addItems(strings._AVAILABLE) self.locale_combobox.setCurrentText(self.current_settings.locale) locale_layout.addWidget(self.locale_combobox, 0, Qt.AlignLeft) + # Explanation for locale self.locale_label = QLabel(strings._("locale_restart")) self.locale_label.setWordWrap(True) self.locale_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) + # make it look secondary lpal = self.locale_label.palette() self.locale_label.setForegroundRole(QPalette.PlaceholderText) self.locale_label.setPalette(lpal) - loc_row = QHBoxLayout() - loc_row.setContentsMargins(24, 0, 0, 0) - loc_row.addWidget(self.locale_label) - locale_layout.addLayout(loc_row) + locale_row = QHBoxLayout() + locale_row.setContentsMargins(24, 0, 0, 0) + locale_row.addWidget(self.locale_label) + locale_layout.addLayout(locale_row) + form.addRow(locale_group) - layout.addWidget(locale_group) - layout.addStretch() - return page - - def _create_features_page(self) -> QWidget: - page = QWidget() - layout = QVBoxLayout(page) - layout.setContentsMargins(12, 12, 12, 12) - layout.setSpacing(12) - - features_group = QGroupBox(strings._("features")) - features_layout = QVBoxLayout(features_group) + # Add Behaviour + behaviour_group = QGroupBox(strings._("behaviour")) + behaviour_layout = QVBoxLayout(behaviour_group) + # Checkbox moving self.move_todos = QCheckBox( strings._("move_yesterdays_unchecked_todos_to_today_on_startup") ) self.move_todos.setChecked(self.current_settings.move_todos) self.move_todos.setCursor(Qt.PointingHandCursor) - features_layout.addWidget(self.move_todos) + behaviour_layout.addWidget(self.move_todos) + # Tags self.tags = QCheckBox(strings._("enable_tags_feature")) self.tags.setChecked(self.current_settings.tags) self.tags.setCursor(Qt.PointingHandCursor) - features_layout.addWidget(self.tags) + behaviour_layout.addWidget(self.tags) + # Time logging self.time_log = QCheckBox(strings._("enable_time_log_feature")) self.time_log.setChecked(self.current_settings.time_log) self.time_log.setCursor(Qt.PointingHandCursor) - features_layout.addWidget(self.time_log) + behaviour_layout.addWidget(self.time_log) - layout.addWidget(features_group) - layout.addStretch() - return page + form.addRow(behaviour_group) - def _create_security_page(self, cfg: DBConfig) -> QWidget: - page = QWidget() - layout = QVBoxLayout(page) - layout.setContentsMargins(12, 12, 12, 12) - layout.setSpacing(12) - - # --- Encryption group --------------------------------------------- + # Encryption settings enc_group = QGroupBox(strings._("encryption")) enc = QVBoxLayout(enc_group) + enc.setContentsMargins(12, 8, 12, 12) + enc.setSpacing(6) + # Checkbox to remember key self.save_key_btn = QCheckBox(strings._("remember_key")) self.key = self.current_settings.key or "" self.save_key_btn.setChecked(bool(self.key)) @@ -197,15 +134,17 @@ class SettingsDialog(QDialog): self.save_key_btn.toggled.connect(self._save_key_btn_clicked) enc.addWidget(self.save_key_btn, 0, Qt.AlignLeft) + # Explanation for remembering key self.save_key_label = QLabel(strings._("save_key_warning")) self.save_key_label.setWordWrap(True) self.save_key_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) + # make it look secondary pal = self.save_key_label.palette() self.save_key_label.setForegroundRole(QPalette.PlaceholderText) self.save_key_label.setPalette(pal) exp_row = QHBoxLayout() - exp_row.setContentsMargins(24, 0, 0, 0) + exp_row.setContentsMargins(24, 0, 0, 0) # indent to line up under the checkbox exp_row.addWidget(self.save_key_label) enc.addLayout(exp_row) @@ -214,16 +153,20 @@ class SettingsDialog(QDialog): line.setFrameShadow(QFrame.Sunken) enc.addWidget(line) + # Change key button self.rekey_btn = QPushButton(strings._("change_encryption_key")) self.rekey_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.rekey_btn.clicked.connect(self._change_key) + enc.addWidget(self.rekey_btn, 0, Qt.AlignLeft) - layout.addWidget(enc_group) + form.addRow(enc_group) - # --- Idle lock group ---------------------------------------------- + # Privacy settings priv_group = QGroupBox(strings._("lock_screen_when_idle")) priv = QVBoxLayout(priv_group) + priv.setContentsMargins(12, 8, 12, 12) + priv.setSpacing(6) self.idle_spin = QSpinBox() self.idle_spin.setRange(0, 240) @@ -233,40 +176,39 @@ class SettingsDialog(QDialog): self.idle_spin.setSpecialValueText(strings._("Never")) self.idle_spin.setValue(getattr(cfg, "idle_minutes", 15)) priv.addWidget(self.idle_spin, 0, Qt.AlignLeft) - + # Explanation for idle option (autolock) self.idle_spin_label = QLabel(strings._("autolock_explanation")) self.idle_spin_label.setWordWrap(True) self.idle_spin_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) + # make it look secondary spal = self.idle_spin_label.palette() self.idle_spin_label.setForegroundRole(QPalette.PlaceholderText) self.idle_spin_label.setPalette(spal) spin_row = QHBoxLayout() - spin_row.setContentsMargins(24, 0, 0, 0) + spin_row.setContentsMargins(24, 0, 0, 0) # indent to line up under the spinbox spin_row.addWidget(self.idle_spin_label) priv.addLayout(spin_row) - layout.addWidget(priv_group) - layout.addStretch() - return page - - def _create_database_page(self) -> QWidget: - page = QWidget() - layout = QVBoxLayout(page) - layout.setContentsMargins(12, 12, 12, 12) - layout.setSpacing(12) + form.addRow(priv_group) + # Maintenance settings maint_group = QGroupBox(strings._("database_maintenance")) maint = QVBoxLayout(maint_group) + maint.setContentsMargins(12, 8, 12, 12) + maint.setSpacing(6) self.compact_btn = QPushButton(strings._("database_compact")) self.compact_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.compact_btn.clicked.connect(self._compact_btn_clicked) + maint.addWidget(self.compact_btn, 0, Qt.AlignLeft) + # Explanation for compacting button self.compact_label = QLabel(strings._("database_compact_explanation")) self.compact_label.setWordWrap(True) self.compact_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) + # make it look secondary cpal = self.compact_label.palette() self.compact_label.setForegroundRole(QPalette.PlaceholderText) self.compact_label.setPalette(cpal) @@ -276,15 +218,22 @@ class SettingsDialog(QDialog): maint_row.addWidget(self.compact_label) maint.addLayout(maint_row) - layout.addWidget(maint_group) - layout.addStretch() - return page + form.addRow(maint_group) - # ------------------------------------------------------------------ # - # Save settings - # ------------------------------------------------------------------ # + # Buttons + bb = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Cancel) + bb.accepted.connect(self._save) + bb.rejected.connect(self.reject) + + # Root layout (adjust margins/spacing a bit) + v = QVBoxLayout(self) + v.setContentsMargins(12, 12, 12, 12) + v.setSpacing(10) + v.addLayout(form) + v.addWidget(bb, 0, Qt.AlignRight) def _save(self): + # Save the selected theme into QSettings if self.theme_dark.isChecked(): selected_theme = Theme.DARK elif self.theme_light.isChecked(): @@ -303,7 +252,6 @@ class SettingsDialog(QDialog): tags=self.tags.isChecked(), time_log=self.time_log.isChecked(), locale=self.locale_combobox.currentText(), - font_size=self.font_size.value(), ) save_db_config(self._cfg) diff --git a/bouquin/toolbar.py b/bouquin/toolbar.py index d6c52be..afff8f6 100644 --- a/bouquin/toolbar.py +++ b/bouquin/toolbar.py @@ -77,12 +77,10 @@ class ToolBar(QToolBar): self.actFontSmaller = QAction("N-", self) self.actFontSmaller.setToolTip(strings._("toolbar_font_smaller")) - self.actFontSmaller.setShortcut("Ctrl+Shift+-") self.actFontSmaller.triggered.connect(self.fontSizeSmallerRequested) self.actFontLarger = QAction("N+", self) self.actFontLarger.setToolTip(strings._("toolbar_font_larger")) - self.actFontLarger.setShortcut("Ctrl+Shift+=") self.actFontLarger.triggered.connect(self.fontSizeLargerRequested) # Lists diff --git a/pyproject.toml b/pyproject.toml index 336a163..3e0bbff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "bouquin" -version = "0.4.2" +version = "0.4.1" description = "Bouquin is a simple, opinionated notebook application written in Python, PyQt and SQLCipher." authors = ["Miguel Jacq "] readme = "README.md" diff --git a/tests/test_main_window.py b/tests/test_main_window.py index 4cdc298..e7eaed3 100644 --- a/tests/test_main_window.py +++ b/tests/test_main_window.py @@ -1643,7 +1643,6 @@ def test_main_window_settings_path_change_success( new_cfg.theme = "light" new_cfg.move_todos = True new_cfg.locale = "en" - new_cfg.font_size = 11 mock_instance.config = new_cfg mock_dialog.return_value = mock_instance @@ -1687,7 +1686,6 @@ def test_main_window_settings_path_change_failure( new_cfg.theme = "light" new_cfg.move_todos = True new_cfg.locale = "en" - new_cfg.font_size = 11 mock_instance.config = new_cfg mock_dialog.return_value = mock_instance @@ -1729,7 +1727,6 @@ def test_main_window_settings_no_path_change(app, fresh_db, tmp_db_cfg, monkeypa new_cfg.theme = "dark" # Changed new_cfg.move_todos = False # Changed new_cfg.locale = "fr" # Changed - new_cfg.font_size = 12 # Changed mock_instance.config = new_cfg mock_dialog.return_value = mock_instance @@ -1741,7 +1738,6 @@ def test_main_window_settings_no_path_change(app, fresh_db, tmp_db_cfg, monkeypa assert window.cfg.idle_minutes == 20 assert window.cfg.theme == "dark" assert window.cfg.path == old_path - assert window.cfg.font_size == 12 def test_main_window_settings_cancelled(app, fresh_db, tmp_db_cfg, monkeypatch):