plover 5.1.0__py3-none-any.whl → 5.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- plover/__init__.py +5 -3
- plover/config.py +58 -14
- plover/dictionary/loading_manager.py +1 -1
- plover/engine.py +205 -37
- plover/formatting.py +5 -2
- plover/gui_qt/about_dialog_ui.py +1 -1
- plover/gui_qt/add_translation_dialog_ui.py +1 -1
- plover/gui_qt/add_translation_widget_ui.py +1 -1
- plover/gui_qt/appearance.py +49 -0
- plover/gui_qt/config_file_widget_ui.py +1 -1
- plover/gui_qt/config_keyboard_widget_ui.py +1 -1
- plover/gui_qt/config_plover_hid_widget_ui.py +1 -1
- plover/gui_qt/config_serial_widget_ui.py +2 -11
- plover/gui_qt/config_window.py +139 -33
- plover/gui_qt/config_window_ui.py +2 -2
- plover/gui_qt/console_widget.py +1 -1
- plover/gui_qt/console_widget_ui.py +1 -1
- plover/gui_qt/dictionaries_widget_ui.py +1 -1
- plover/gui_qt/dictionary_editor_ui.py +1 -1
- plover/gui_qt/lookup_dialog_ui.py +1 -1
- plover/gui_qt/machine_options.py +1 -19
- plover/gui_qt/main_window.py +13 -1
- plover/gui_qt/main_window_ui.py +15 -8
- plover/gui_qt/paper_tape_ui.py +1 -1
- plover/gui_qt/plugins_manager.py +9 -4
- plover/gui_qt/plugins_manager_ui.py +2 -2
- plover/gui_qt/resources_rc.py +29 -29
- plover/gui_qt/run_dialog_ui.py +1 -1
- plover/gui_qt/suggestions_dialog_ui.py +1 -1
- plover/gui_qt/trayicon.py +0 -2
- plover/gui_qt/utils.py +0 -1
- plover/i18n.py +1 -1
- plover/key_combo.py +3 -1
- plover/log.py +2 -2
- plover/machine/base.py +12 -2
- plover/machine/keyboard_capture/__init__.py +33 -10
- plover/machine/keymap.py +86 -10
- plover/machine/plover_hid.py +46 -25
- plover/machine/procat.py +0 -3
- plover/machine/stentura.py +5 -5
- plover/messages/es/LC_MESSAGES/plover.mo +0 -0
- plover/messages/es/LC_MESSAGES/plover.po +2 -2
- plover/messages/fr/LC_MESSAGES/plover.mo +0 -0
- plover/messages/fr/LC_MESSAGES/plover.po +2 -2
- plover/messages/it/LC_MESSAGES/plover.mo +0 -0
- plover/messages/it/LC_MESSAGES/plover.po +2 -2
- plover/messages/nl/LC_MESSAGES/plover.mo +0 -0
- plover/messages/nl/LC_MESSAGES/plover.po +2 -2
- plover/messages/plover.pot +1 -1
- plover/messages/zh_tw/LC_MESSAGES/plover.mo +0 -0
- plover/messages/zh_tw/LC_MESSAGES/plover.po +2 -2
- plover/orthography.py +2 -1
- plover/oslayer/controller.py +1 -1
- plover/oslayer/linux/keyboardcontrol.py +4 -2
- plover/oslayer/linux/keyboardcontrol_uinput.py +107 -343
- plover/oslayer/linux/keyboardcontrol_x11.py +22 -13
- plover/oslayer/linux/keyboardlayout_wayland.py +403 -0
- plover/oslayer/linux/log.py +3 -1
- plover/oslayer/linux/wayland_connection.py +293 -0
- plover/oslayer/osx/keyboardlayout.py +1 -1
- plover/plugins_manager/registry.py +4 -3
- plover/registry.py +1 -1
- plover/scripts/main.py +6 -3
- plover/system/__init__.py +7 -7
- {plover-5.1.0.dist-info → plover-5.2.0.dist-info}/METADATA +5 -4
- {plover-5.1.0.dist-info → plover-5.2.0.dist-info}/RECORD +76 -74
- {plover-5.1.0.dist-info → plover-5.2.0.dist-info}/WHEEL +1 -1
- plover_build_utils/check_requirements.py +0 -3
- plover_build_utils/functions.sh +0 -11
- plover_build_utils/testing/__init__.py +9 -0
- plover_build_utils/testing/blackbox.py +3 -1
- plover_build_utils/testing/steno_dictionary.py +2 -2
- plover_build_utils/deps.sh +0 -2
- {plover-5.1.0.dist-info → plover-5.2.0.dist-info}/entry_points.txt +0 -0
- {plover-5.1.0.dist-info → plover-5.2.0.dist-info}/licenses/LICENSE.txt +0 -0
- {plover-5.1.0.dist-info → plover-5.2.0.dist-info}/top_level.txt +0 -0
- {plover-5.1.0.dist-info → plover-5.2.0.dist-info}/zip-safe +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
from plover import log
|
|
3
|
+
|
|
4
|
+
from PySide6.QtCore import Qt
|
|
5
|
+
from PySide6.QtGui import QGuiApplication
|
|
6
|
+
|
|
7
|
+
MODE_SYSTEM = "system"
|
|
8
|
+
MODE_LIGHT = "light"
|
|
9
|
+
MODE_DARK = "dark"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _set_mode(mode: Optional[str]) -> None:
|
|
13
|
+
"""Apply the requested mode to the current Qt application.
|
|
14
|
+
|
|
15
|
+
This function tweaks Qt's idea of the platform color scheme via
|
|
16
|
+
QStyleHints.setColorScheme / unsetColorScheme so that other code can
|
|
17
|
+
query styleHints().colorScheme() and get the effective setting.
|
|
18
|
+
|
|
19
|
+
- "system": follow the operating system setting again
|
|
20
|
+
- "light": force a light color scheme
|
|
21
|
+
- "dark": force a dark color scheme
|
|
22
|
+
- None: no-op
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
if mode is None:
|
|
26
|
+
# Explicitly do nothing when no mode was provided.
|
|
27
|
+
return
|
|
28
|
+
|
|
29
|
+
app = QGuiApplication.instance()
|
|
30
|
+
if not isinstance(app, QGuiApplication):
|
|
31
|
+
# No GUI application instance (or unexpected type); nothing to do.
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
# Ensure the style is initialized.
|
|
35
|
+
hints = app.styleHints()
|
|
36
|
+
|
|
37
|
+
if mode == MODE_SYSTEM:
|
|
38
|
+
# Remove any explicit override so Qt follows the OS again.
|
|
39
|
+
hints.unsetColorScheme()
|
|
40
|
+
elif mode == MODE_LIGHT:
|
|
41
|
+
hints.setColorScheme(Qt.ColorScheme.Light)
|
|
42
|
+
elif mode == MODE_DARK:
|
|
43
|
+
hints.setColorScheme(Qt.ColorScheme.Dark)
|
|
44
|
+
else:
|
|
45
|
+
log.warning(f"invalid mode config value: {mode}")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def update(config):
|
|
49
|
+
_set_mode(config.get("appearance_mode"))
|
|
@@ -4,7 +4,7 @@ _ = __import__(__package__.split(".", 1)[0])._
|
|
|
4
4
|
################################################################################
|
|
5
5
|
## Form generated from reading UI file 'config_file_widget.ui'
|
|
6
6
|
##
|
|
7
|
-
## Created by: Qt User Interface Compiler version 6.10.
|
|
7
|
+
## Created by: Qt User Interface Compiler version 6.10.1
|
|
8
8
|
##
|
|
9
9
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
|
10
10
|
################################################################################
|
|
@@ -4,7 +4,7 @@ _ = __import__(__package__.split(".", 1)[0])._
|
|
|
4
4
|
################################################################################
|
|
5
5
|
## Form generated from reading UI file 'config_keyboard_widget.ui'
|
|
6
6
|
##
|
|
7
|
-
## Created by: Qt User Interface Compiler version 6.10.
|
|
7
|
+
## Created by: Qt User Interface Compiler version 6.10.1
|
|
8
8
|
##
|
|
9
9
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
|
10
10
|
################################################################################
|
|
@@ -4,7 +4,7 @@ _ = __import__(__package__.split(".", 1)[0])._
|
|
|
4
4
|
################################################################################
|
|
5
5
|
## Form generated from reading UI file 'config_plover_hid_widget.ui'
|
|
6
6
|
##
|
|
7
|
-
## Created by: Qt User Interface Compiler version 6.10.
|
|
7
|
+
## Created by: Qt User Interface Compiler version 6.10.1
|
|
8
8
|
##
|
|
9
9
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
|
10
10
|
################################################################################
|
|
@@ -4,7 +4,7 @@ _ = __import__(__package__.split(".", 1)[0])._
|
|
|
4
4
|
################################################################################
|
|
5
5
|
## Form generated from reading UI file 'config_serial_widget.ui'
|
|
6
6
|
##
|
|
7
|
-
## Created by: Qt User Interface Compiler version 6.10.
|
|
7
|
+
## Created by: Qt User Interface Compiler version 6.10.1
|
|
8
8
|
##
|
|
9
9
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
|
10
10
|
################################################################################
|
|
@@ -159,13 +159,6 @@ class Ui_SerialWidget(object):
|
|
|
159
159
|
|
|
160
160
|
self.gridLayout.addWidget(self.timeout, 0, 1, 1, 1)
|
|
161
161
|
|
|
162
|
-
self.use_timeout = QCheckBox(self.groupBox_3)
|
|
163
|
-
self.use_timeout.setObjectName(u"use_timeout")
|
|
164
|
-
sizePolicy3.setHeightForWidth(self.use_timeout.sizePolicy().hasHeightForWidth())
|
|
165
|
-
self.use_timeout.setSizePolicy(sizePolicy3)
|
|
166
|
-
|
|
167
|
-
self.gridLayout.addWidget(self.use_timeout, 1, 0, 1, 2)
|
|
168
|
-
|
|
169
162
|
|
|
170
163
|
self.horizontalLayout_2.addWidget(self.groupBox_3)
|
|
171
164
|
|
|
@@ -209,7 +202,6 @@ class Ui_SerialWidget(object):
|
|
|
209
202
|
self.parity.textActivated.connect(SerialWidget.update_parity)
|
|
210
203
|
self.port.editTextChanged.connect(SerialWidget.update_port)
|
|
211
204
|
self.stopbits.textActivated.connect(SerialWidget.update_stopbits)
|
|
212
|
-
self.use_timeout.clicked["bool"].connect(SerialWidget.update_use_timeout)
|
|
213
205
|
self.xonxoff.clicked["bool"].connect(SerialWidget.update_xonxoff)
|
|
214
206
|
self.rtscts.clicked["bool"].connect(SerialWidget.update_rtscts)
|
|
215
207
|
self.timeout.valueChanged.connect(SerialWidget.update_timeout)
|
|
@@ -254,14 +246,13 @@ class Ui_SerialWidget(object):
|
|
|
254
246
|
self.groupBox_3.setAccessibleName("")
|
|
255
247
|
#endif // QT_CONFIG(accessibility)
|
|
256
248
|
self.groupBox_3.setTitle(QCoreApplication.translate("SerialWidget", u"Timeout", None))
|
|
257
|
-
self.label_6.setText(QCoreApplication.translate("SerialWidget", u"Duration", None))
|
|
249
|
+
self.label_6.setText(QCoreApplication.translate("SerialWidget", u"Duration (s)", None))
|
|
258
250
|
#if QT_CONFIG(accessibility)
|
|
259
251
|
self.timeout.setAccessibleName(QCoreApplication.translate("SerialWidget", u"Duration", None))
|
|
260
252
|
#endif // QT_CONFIG(accessibility)
|
|
261
253
|
#if QT_CONFIG(accessibility)
|
|
262
254
|
self.timeout.setAccessibleDescription(QCoreApplication.translate("SerialWidget", u"Timeout duration in seconds.", None))
|
|
263
255
|
#endif // QT_CONFIG(accessibility)
|
|
264
|
-
self.use_timeout.setText(QCoreApplication.translate("SerialWidget", u"Use timeout", None))
|
|
265
256
|
self.groupBox_4.setTitle(QCoreApplication.translate("SerialWidget", u"Flow control", None))
|
|
266
257
|
self.xonxoff.setText(QCoreApplication.translate("SerialWidget", u"Xon/Xoff", None))
|
|
267
258
|
self.rtscts.setText(QCoreApplication.translate("SerialWidget", u"RTS/CTS", None))
|
plover/gui_qt/config_window.py
CHANGED
|
@@ -7,7 +7,10 @@ from PySide6.QtCore import (
|
|
|
7
7
|
Signal,
|
|
8
8
|
Slot,
|
|
9
9
|
)
|
|
10
|
+
from typing import Set
|
|
11
|
+
|
|
10
12
|
from PySide6.QtWidgets import (
|
|
13
|
+
QAbstractScrollArea,
|
|
11
14
|
QCheckBox,
|
|
12
15
|
QComboBox,
|
|
13
16
|
QDialog,
|
|
@@ -15,9 +18,11 @@ from PySide6.QtWidgets import (
|
|
|
15
18
|
QFileDialog,
|
|
16
19
|
QFormLayout,
|
|
17
20
|
QFrame,
|
|
21
|
+
QHeaderView,
|
|
18
22
|
QGroupBox,
|
|
19
23
|
QLabel,
|
|
20
24
|
QScrollArea,
|
|
25
|
+
QSizePolicy,
|
|
21
26
|
QSpinBox,
|
|
22
27
|
QStyledItemDelegate,
|
|
23
28
|
QTableWidget,
|
|
@@ -26,8 +31,10 @@ from PySide6.QtWidgets import (
|
|
|
26
31
|
|
|
27
32
|
from plover import _
|
|
28
33
|
from plover.config import MINIMUM_UNDO_LEVELS, MINIMUM_TIME_BETWEEN_KEY_PRESSES
|
|
34
|
+
from plover.gui_qt import appearance
|
|
29
35
|
from plover.misc import expand_path, shorten_path
|
|
30
36
|
from plover.registry import registry
|
|
37
|
+
from plover.oslayer.config import PLATFORM
|
|
31
38
|
|
|
32
39
|
from plover.gui_qt.config_window_ui import Ui_ConfigWindow
|
|
33
40
|
from plover.gui_qt.config_file_widget_ui import Ui_FileWidget
|
|
@@ -118,7 +125,7 @@ class FileOption(QGroupBox, Ui_FileWidget):
|
|
|
118
125
|
class TableOption(QTableWidget):
|
|
119
126
|
def __init__(self):
|
|
120
127
|
super().__init__()
|
|
121
|
-
self.horizontalHeader().setStretchLastSection(
|
|
128
|
+
self.horizontalHeader().setStretchLastSection(False)
|
|
122
129
|
self.setSelectionMode(self.SelectionMode.SingleSelection)
|
|
123
130
|
self.setTabKeyNavigation(False)
|
|
124
131
|
self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
|
@@ -210,10 +217,10 @@ class MultipleChoicesOption(TableOption):
|
|
|
210
217
|
valueChanged = Signal(object)
|
|
211
218
|
|
|
212
219
|
LABELS = (
|
|
213
|
-
# i18n: Widget: “MultipleChoicesOption”.
|
|
214
|
-
_("Choice"),
|
|
215
220
|
# i18n: Widget: “MultipleChoicesOption”.
|
|
216
221
|
_("Selected"),
|
|
222
|
+
# i18n: Widget: “MultipleChoicesOption”.
|
|
223
|
+
_("Choice"),
|
|
217
224
|
)
|
|
218
225
|
|
|
219
226
|
# i18n: Widget: “MultipleChoicesOption”.
|
|
@@ -221,20 +228,29 @@ class MultipleChoicesOption(TableOption):
|
|
|
221
228
|
super().__init__()
|
|
222
229
|
if labels is None:
|
|
223
230
|
labels = self.LABELS
|
|
224
|
-
self._value =
|
|
231
|
+
self._value: Set[str] = set()
|
|
225
232
|
self._updating = False
|
|
226
233
|
self._choices = {} if choices is None else choices
|
|
227
234
|
self._reversed_choices = {
|
|
228
235
|
translation: choice for choice, translation in choices.items()
|
|
229
236
|
}
|
|
237
|
+
self.setSizeAdjustPolicy(
|
|
238
|
+
QAbstractScrollArea.SizeAdjustPolicy.AdjustToContentsOnFirstShow
|
|
239
|
+
)
|
|
240
|
+
self.setSizePolicy(
|
|
241
|
+
QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
|
242
|
+
)
|
|
230
243
|
self.setColumnCount(2)
|
|
231
244
|
self.setHorizontalHeaderLabels(labels)
|
|
245
|
+
header = self.horizontalHeader()
|
|
246
|
+
header.setSectionResizeMode(0, QHeaderView.ResizeMode.ResizeToContents)
|
|
247
|
+
header.setSectionResizeMode(1, QHeaderView.ResizeMode.ResizeToContents)
|
|
248
|
+
header.setStretchLastSection(True)
|
|
249
|
+
header.setStretchLastSection(True)
|
|
232
250
|
self.cellChanged.connect(self._on_cell_changed)
|
|
233
251
|
|
|
234
252
|
def setValue(self, value):
|
|
235
253
|
self._updating = True
|
|
236
|
-
self.resizeColumnsToContents()
|
|
237
|
-
self.setMinimumSize(self.viewportSizeHint())
|
|
238
254
|
self.setRowCount(0)
|
|
239
255
|
if value is None:
|
|
240
256
|
value = set()
|
|
@@ -246,9 +262,6 @@ class MultipleChoicesOption(TableOption):
|
|
|
246
262
|
for choice in sorted(self._reversed_choices):
|
|
247
263
|
row += 1
|
|
248
264
|
self.insertRow(row)
|
|
249
|
-
item = QTableWidgetItem(self._choices[choice])
|
|
250
|
-
item.setFlags(item.flags() & ~Qt.ItemFlag.ItemIsEditable)
|
|
251
|
-
self.setItem(row, 0, item)
|
|
252
265
|
item = QTableWidgetItem()
|
|
253
266
|
item.setFlags(
|
|
254
267
|
(item.flags() & ~Qt.ItemFlag.ItemIsEditable)
|
|
@@ -257,19 +270,28 @@ class MultipleChoicesOption(TableOption):
|
|
|
257
270
|
item.setCheckState(
|
|
258
271
|
Qt.CheckState.Checked if choice in value else Qt.CheckState.Unchecked
|
|
259
272
|
)
|
|
273
|
+
self.setItem(row, 0, item)
|
|
274
|
+
item = QTableWidgetItem(self._choices[choice])
|
|
275
|
+
item.setFlags(item.flags() & ~Qt.ItemFlag.ItemIsEditable)
|
|
260
276
|
self.setItem(row, 1, item)
|
|
261
277
|
self.resizeColumnsToContents()
|
|
262
|
-
self.setMinimumSize(self.viewportSizeHint())
|
|
263
278
|
self._updating = False
|
|
264
279
|
|
|
265
280
|
def _on_cell_changed(self, row, column):
|
|
266
281
|
if self._updating:
|
|
267
282
|
return
|
|
268
|
-
assert column ==
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
283
|
+
assert column == 0
|
|
284
|
+
name_item = self.item(row, 1)
|
|
285
|
+
state_item = self.item(row, 0)
|
|
286
|
+
if name_item is None or state_item is None:
|
|
287
|
+
return
|
|
288
|
+
name = name_item.data(Qt.ItemDataRole.DisplayRole)
|
|
289
|
+
if name is None:
|
|
290
|
+
return
|
|
291
|
+
choice = self._reversed_choices.get(name)
|
|
292
|
+
if choice is None:
|
|
293
|
+
return
|
|
294
|
+
if state_item.checkState() == Qt.CheckState.Checked:
|
|
273
295
|
self._value.add(choice)
|
|
274
296
|
else:
|
|
275
297
|
self._value.discard(choice)
|
|
@@ -284,9 +306,23 @@ class BooleanAsDualChoiceOption(ChoiceOption):
|
|
|
284
306
|
super().__init__(choices)
|
|
285
307
|
|
|
286
308
|
|
|
309
|
+
class TextWrapQLabel(QLabel):
|
|
310
|
+
"""Simple QLabel wrapper that enables wordWrap"""
|
|
311
|
+
|
|
312
|
+
def __init__(self, *args):
|
|
313
|
+
super().__init__(*args)
|
|
314
|
+
self.setWordWrap(True)
|
|
315
|
+
|
|
316
|
+
|
|
287
317
|
class ConfigOption:
|
|
288
318
|
def __init__(
|
|
289
|
-
self,
|
|
319
|
+
self,
|
|
320
|
+
display_name,
|
|
321
|
+
option_name,
|
|
322
|
+
widget_class,
|
|
323
|
+
help_text="",
|
|
324
|
+
dependents=(),
|
|
325
|
+
additional_widget_classes=[],
|
|
290
326
|
):
|
|
291
327
|
self.display_name = display_name
|
|
292
328
|
self.option_name = option_name
|
|
@@ -296,6 +332,9 @@ class ConfigOption:
|
|
|
296
332
|
self.layout = None
|
|
297
333
|
self.widget = None
|
|
298
334
|
self.label = None
|
|
335
|
+
# Other widgets to be added immediately after the main widget_class
|
|
336
|
+
# Does not work in dependents
|
|
337
|
+
self.additional_widget_classes = additional_widget_classes
|
|
299
338
|
|
|
300
339
|
|
|
301
340
|
class ConfigWindow(QDialog, Ui_ConfigWindow, WindowStateMixin):
|
|
@@ -313,6 +352,24 @@ class ConfigWindow(QDialog, Ui_ConfigWindow, WindowStateMixin):
|
|
|
313
352
|
(
|
|
314
353
|
_("Interface"),
|
|
315
354
|
(
|
|
355
|
+
ConfigOption(
|
|
356
|
+
_("Appearance:"),
|
|
357
|
+
"appearance_mode",
|
|
358
|
+
partial(
|
|
359
|
+
ChoiceOption,
|
|
360
|
+
choices={
|
|
361
|
+
"system": _("System"),
|
|
362
|
+
"light": _("Light"),
|
|
363
|
+
"dark": _("Dark"),
|
|
364
|
+
},
|
|
365
|
+
),
|
|
366
|
+
_(
|
|
367
|
+
"Set the application appearance:\n"
|
|
368
|
+
"- System: follow the operating system mode\n"
|
|
369
|
+
"- Light: force light mode\n"
|
|
370
|
+
"- Dark: force dark mode"
|
|
371
|
+
),
|
|
372
|
+
),
|
|
316
373
|
ConfigOption(
|
|
317
374
|
_("Start minimized:"),
|
|
318
375
|
"start_minimized",
|
|
@@ -481,12 +538,26 @@ class ConfigWindow(QDialog, Ui_ConfigWindow, WindowStateMixin):
|
|
|
481
538
|
"colemak": "colemak",
|
|
482
539
|
"colemak-dh": "colemak-dh",
|
|
483
540
|
"dvorak": "dvorak",
|
|
541
|
+
"wayland-auto": "wayland-auto",
|
|
484
542
|
},
|
|
485
543
|
),
|
|
486
544
|
_(
|
|
487
|
-
"Set the keyboard layout
|
|
488
|
-
"This only applies when using Linux/BSD and not using X11
|
|
545
|
+
"Set the keyboard layout configured in your system.\n"
|
|
546
|
+
"This only applies when using Linux/BSD and not using X11.\n\n"
|
|
547
|
+
"When wayland-auto is selected,"
|
|
548
|
+
"Plover is only able detect the first keyboard layout\n"
|
|
549
|
+
"and can not detect to layout switches."
|
|
489
550
|
),
|
|
551
|
+
additional_widget_classes=[
|
|
552
|
+
partial(
|
|
553
|
+
TextWrapQLabel,
|
|
554
|
+
_(
|
|
555
|
+
"When wayland-auto is selected, "
|
|
556
|
+
"Plover is only able detect the first keyboard layout "
|
|
557
|
+
"and can not detect to layout switches."
|
|
558
|
+
),
|
|
559
|
+
)
|
|
560
|
+
],
|
|
490
561
|
),
|
|
491
562
|
),
|
|
492
563
|
),
|
|
@@ -495,7 +566,7 @@ class ConfigWindow(QDialog, Ui_ConfigWindow, WindowStateMixin):
|
|
|
495
566
|
_("Plugins"),
|
|
496
567
|
(
|
|
497
568
|
ConfigOption(
|
|
498
|
-
_("
|
|
569
|
+
_("Extensions:"),
|
|
499
570
|
"enabled_extensions",
|
|
500
571
|
partial(
|
|
501
572
|
MultipleChoicesOption,
|
|
@@ -503,7 +574,7 @@ class ConfigWindow(QDialog, Ui_ConfigWindow, WindowStateMixin):
|
|
|
503
574
|
plugin.name: plugin.name
|
|
504
575
|
for plugin in registry.list_plugins("extension")
|
|
505
576
|
},
|
|
506
|
-
labels=(_("
|
|
577
|
+
labels=(_("Enabled"), _("Name")),
|
|
507
578
|
),
|
|
508
579
|
_("Configure enabled plugin extensions."),
|
|
509
580
|
),
|
|
@@ -539,7 +610,7 @@ class ConfigWindow(QDialog, Ui_ConfigWindow, WindowStateMixin):
|
|
|
539
610
|
self._supported_options = set()
|
|
540
611
|
for section, option_list in mappings:
|
|
541
612
|
self._supported_options.update(option.option_name for option in option_list)
|
|
542
|
-
self.
|
|
613
|
+
self._load_config()
|
|
543
614
|
# Create and fill tabs.
|
|
544
615
|
option_by_name = {}
|
|
545
616
|
for section, option_list in mappings:
|
|
@@ -552,6 +623,8 @@ class ConfigWindow(QDialog, Ui_ConfigWindow, WindowStateMixin):
|
|
|
552
623
|
option.label.setToolTip(option.help_text)
|
|
553
624
|
option.label.setBuddy(option.widget)
|
|
554
625
|
layout.addRow(option.label, option.widget)
|
|
626
|
+
for additional_widget_class in option.additional_widget_classes:
|
|
627
|
+
layout.addRow(None, additional_widget_class())
|
|
555
628
|
frame = QFrame()
|
|
556
629
|
frame.setLayout(layout)
|
|
557
630
|
frame.setAccessibleName(section)
|
|
@@ -561,6 +634,29 @@ class ConfigWindow(QDialog, Ui_ConfigWindow, WindowStateMixin):
|
|
|
561
634
|
scroll_area.setWidget(frame)
|
|
562
635
|
scroll_area.setFocusProxy(frame)
|
|
563
636
|
self.tabs.addTab(scroll_area, section)
|
|
637
|
+
|
|
638
|
+
# platform specific overwrites
|
|
639
|
+
if PLATFORM == "linux":
|
|
640
|
+
# Appearance overwrite doesn't work on Linux so we're not showing the option
|
|
641
|
+
appearance_option = option_by_name.get("appearance_mode")
|
|
642
|
+
if appearance_option is not None:
|
|
643
|
+
appearance_option.label.hide()
|
|
644
|
+
appearance_option.widget.hide()
|
|
645
|
+
if PLATFORM != "linux":
|
|
646
|
+
# Keyboard layout is only relevant on Linux
|
|
647
|
+
keyboard_layout_option = option_by_name.get("keyboard_layout")
|
|
648
|
+
if keyboard_layout_option is not None:
|
|
649
|
+
keyboard_layout_option.label.hide()
|
|
650
|
+
keyboard_layout_option.widget.hide()
|
|
651
|
+
|
|
652
|
+
# temporary hiding start_minimized setting on macOS due to bug in
|
|
653
|
+
# macOS 26, see https://github.com/openstenoproject/plover/issues/1782
|
|
654
|
+
if PLATFORM == "mac":
|
|
655
|
+
start_minimized_option = option_by_name.get("start_minimized")
|
|
656
|
+
if start_minimized_option is not None:
|
|
657
|
+
start_minimized_option.label.hide()
|
|
658
|
+
start_minimized_option.widget.hide()
|
|
659
|
+
|
|
564
660
|
# Update dependents.
|
|
565
661
|
for option in option_by_name.values():
|
|
566
662
|
option.dependents = [
|
|
@@ -577,18 +673,27 @@ class ConfigWindow(QDialog, Ui_ConfigWindow, WindowStateMixin):
|
|
|
577
673
|
self.restore_state()
|
|
578
674
|
self.finished.connect(self.save_state)
|
|
579
675
|
|
|
580
|
-
def
|
|
676
|
+
def _update_appearance(self):
|
|
677
|
+
appearance.update(self._config.maps[0])
|
|
678
|
+
|
|
679
|
+
def _save_config(self):
|
|
680
|
+
"""Persist the overrides from this dialog back into the engine config.
|
|
681
|
+
|
|
682
|
+
This uses the engine's async config update mechanism; the engine thread
|
|
683
|
+
will apply the update after it processes the queued job.
|
|
684
|
+
"""
|
|
581
685
|
with self._engine:
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
686
|
+
self._engine.config = self._config.maps[0]
|
|
687
|
+
|
|
688
|
+
def _load_config(self):
|
|
689
|
+
"""Load the current config from the engine into this dialog."""
|
|
690
|
+
with self._engine:
|
|
691
|
+
base_config = {
|
|
692
|
+
name: value
|
|
693
|
+
for name, value in self._engine.config.items()
|
|
694
|
+
if name in self._supported_options
|
|
695
|
+
}
|
|
696
|
+
self._config = ChainMap({}, base_config)
|
|
592
697
|
|
|
593
698
|
def _machine_option(self, *args):
|
|
594
699
|
machine_options = {
|
|
@@ -651,4 +756,5 @@ class ConfigWindow(QDialog, Ui_ConfigWindow, WindowStateMixin):
|
|
|
651
756
|
dependent.widget = widget
|
|
652
757
|
|
|
653
758
|
def on_apply(self):
|
|
654
|
-
self.
|
|
759
|
+
self._update_appearance()
|
|
760
|
+
self._save_config()
|
|
@@ -4,7 +4,7 @@ _ = __import__(__package__.split(".", 1)[0])._
|
|
|
4
4
|
################################################################################
|
|
5
5
|
## Form generated from reading UI file 'config_window.ui'
|
|
6
6
|
##
|
|
7
|
-
## Created by: Qt User Interface Compiler version 6.10.
|
|
7
|
+
## Created by: Qt User Interface Compiler version 6.10.1
|
|
8
8
|
##
|
|
9
9
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
|
10
10
|
################################################################################
|
|
@@ -24,7 +24,7 @@ class Ui_ConfigWindow(object):
|
|
|
24
24
|
def setupUi(self, ConfigWindow):
|
|
25
25
|
if not ConfigWindow.objectName():
|
|
26
26
|
ConfigWindow.setObjectName(u"ConfigWindow")
|
|
27
|
-
ConfigWindow.resize(
|
|
27
|
+
ConfigWindow.resize(500, 500)
|
|
28
28
|
icon = QIcon()
|
|
29
29
|
icon.addFile(u":/resources/plover.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
|
30
30
|
ConfigWindow.setWindowIcon(icon)
|
plover/gui_qt/console_widget.py
CHANGED
|
@@ -4,7 +4,7 @@ _ = __import__(__package__.split(".", 1)[0])._
|
|
|
4
4
|
################################################################################
|
|
5
5
|
## Form generated from reading UI file 'console_widget.ui'
|
|
6
6
|
##
|
|
7
|
-
## Created by: Qt User Interface Compiler version 6.10.
|
|
7
|
+
## Created by: Qt User Interface Compiler version 6.10.1
|
|
8
8
|
##
|
|
9
9
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
|
10
10
|
################################################################################
|
|
@@ -4,7 +4,7 @@ _ = __import__(__package__.split(".", 1)[0])._
|
|
|
4
4
|
################################################################################
|
|
5
5
|
## Form generated from reading UI file 'dictionaries_widget.ui'
|
|
6
6
|
##
|
|
7
|
-
## Created by: Qt User Interface Compiler version 6.10.
|
|
7
|
+
## Created by: Qt User Interface Compiler version 6.10.1
|
|
8
8
|
##
|
|
9
9
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
|
10
10
|
################################################################################
|
|
@@ -4,7 +4,7 @@ _ = __import__(__package__.split(".", 1)[0])._
|
|
|
4
4
|
################################################################################
|
|
5
5
|
## Form generated from reading UI file 'dictionary_editor.ui'
|
|
6
6
|
##
|
|
7
|
-
## Created by: Qt User Interface Compiler version 6.10.
|
|
7
|
+
## Created by: Qt User Interface Compiler version 6.10.1
|
|
8
8
|
##
|
|
9
9
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
|
10
10
|
################################################################################
|
|
@@ -4,7 +4,7 @@ _ = __import__(__package__.split(".", 1)[0])._
|
|
|
4
4
|
################################################################################
|
|
5
5
|
## Form generated from reading UI file 'lookup_dialog.ui'
|
|
6
6
|
##
|
|
7
|
-
## Created by: Qt User Interface Compiler version 6.10.
|
|
7
|
+
## Created by: Qt User Interface Compiler version 6.10.1
|
|
8
8
|
##
|
|
9
9
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
|
10
10
|
################################################################################
|
plover/gui_qt/machine_options.py
CHANGED
|
@@ -89,7 +89,6 @@ class SerialOption(QGroupBox, Ui_SerialWidget):
|
|
|
89
89
|
if not details:
|
|
90
90
|
return
|
|
91
91
|
cursor.insertFrame(self._details_frame_format)
|
|
92
|
-
details_list = cursor.createList(self._details_list_format)
|
|
93
92
|
for n, part in enumerate(details):
|
|
94
93
|
if n:
|
|
95
94
|
cursor.insertBlock()
|
|
@@ -140,15 +139,7 @@ class SerialOption(QGroupBox, Ui_SerialWidget):
|
|
|
140
139
|
self.parity.setCurrentText(value["parity"])
|
|
141
140
|
self.stopbits.addItems(map(str, Serial.STOPBITS))
|
|
142
141
|
self.stopbits.setCurrentText(str(value["stopbits"]))
|
|
143
|
-
timeout
|
|
144
|
-
if timeout is None:
|
|
145
|
-
self.use_timeout.setChecked(False)
|
|
146
|
-
self.timeout.setValue(0.0)
|
|
147
|
-
self.timeout.setEnabled(False)
|
|
148
|
-
else:
|
|
149
|
-
self.use_timeout.setChecked(True)
|
|
150
|
-
self.timeout.setValue(timeout)
|
|
151
|
-
self.timeout.setEnabled(True)
|
|
142
|
+
self.timeout.setValue(value["timeout"])
|
|
152
143
|
for setting in ("xonxoff", "rtscts"):
|
|
153
144
|
widget = getattr(self, setting)
|
|
154
145
|
if setting in value:
|
|
@@ -188,15 +179,6 @@ class SerialOption(QGroupBox, Ui_SerialWidget):
|
|
|
188
179
|
def update_timeout(self, value):
|
|
189
180
|
self._update("timeout", value)
|
|
190
181
|
|
|
191
|
-
@Slot(bool)
|
|
192
|
-
def update_use_timeout(self, value):
|
|
193
|
-
if value:
|
|
194
|
-
timeout = self.timeout.value()
|
|
195
|
-
else:
|
|
196
|
-
timeout = None
|
|
197
|
-
self.timeout.setEnabled(value)
|
|
198
|
-
self._update("timeout", timeout)
|
|
199
|
-
|
|
200
182
|
@Slot(bool)
|
|
201
183
|
def update_xonxoff(self, value):
|
|
202
184
|
self._update("xonxoff", value)
|
plover/gui_qt/main_window.py
CHANGED
|
@@ -22,6 +22,7 @@ from plover.gui_qt.config_window import ConfigWindow
|
|
|
22
22
|
from plover.gui_qt.about_dialog import AboutDialog
|
|
23
23
|
from plover.gui_qt.trayicon import TrayIcon
|
|
24
24
|
from plover.gui_qt.utils import WindowStateMixin
|
|
25
|
+
from plover.gui_qt import appearance
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
class MainWindow(QMainWindow, Ui_MainWindow, WindowStateMixin):
|
|
@@ -141,10 +142,21 @@ class MainWindow(QMainWindow, Ui_MainWindow, WindowStateMixin):
|
|
|
141
142
|
self.configure()
|
|
142
143
|
# Apply configuration settings.
|
|
143
144
|
config = self._engine.config
|
|
145
|
+
|
|
146
|
+
# Set the initial appearance based on the loaded configuration.
|
|
147
|
+
appearance.update(config)
|
|
148
|
+
|
|
144
149
|
self._warn_on_hide_to_tray = not config["start_minimized"]
|
|
145
150
|
self._update_machine(config["machine_type"])
|
|
146
151
|
self._configured = False
|
|
147
|
-
|
|
152
|
+
|
|
153
|
+
# temporary ignoring start_minimized setting on macOS due to bug in
|
|
154
|
+
# macOS 26, see https://github.com/openstenoproject/plover/issues/1782
|
|
155
|
+
if PLATFORM == "mac":
|
|
156
|
+
self.set_visible(True)
|
|
157
|
+
else:
|
|
158
|
+
self.set_visible(not config["start_minimized"])
|
|
159
|
+
|
|
148
160
|
# Process events before starting the engine
|
|
149
161
|
# (to avoid display lag at window creation).
|
|
150
162
|
QCoreApplication.processEvents()
|
plover/gui_qt/main_window_ui.py
CHANGED
|
@@ -4,7 +4,7 @@ _ = __import__(__package__.split(".", 1)[0])._
|
|
|
4
4
|
################################################################################
|
|
5
5
|
## Form generated from reading UI file 'main_window.ui'
|
|
6
6
|
##
|
|
7
|
-
## Created by: Qt User Interface Compiler version 6.10.
|
|
7
|
+
## Created by: Qt User Interface Compiler version 6.10.1
|
|
8
8
|
##
|
|
9
9
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
|
10
10
|
################################################################################
|
|
@@ -19,8 +19,8 @@ from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient,
|
|
|
19
19
|
QTransform)
|
|
20
20
|
from PySide6.QtWidgets import (QApplication, QComboBox, QGridLayout, QGroupBox,
|
|
21
21
|
QLabel, QMainWindow, QMenu, QMenuBar,
|
|
22
|
-
QPushButton, QRadioButton, QSizePolicy,
|
|
23
|
-
QWidget)
|
|
22
|
+
QPushButton, QRadioButton, QSizePolicy, QSpacerItem,
|
|
23
|
+
QToolBar, QWidget)
|
|
24
24
|
|
|
25
25
|
from plover.gui_qt.dictionaries_widget import DictionariesWidget
|
|
26
26
|
from . import resources_rc
|
|
@@ -30,7 +30,7 @@ class Ui_MainWindow(object):
|
|
|
30
30
|
if not MainWindow.objectName():
|
|
31
31
|
MainWindow.setObjectName(u"MainWindow")
|
|
32
32
|
MainWindow.setEnabled(True)
|
|
33
|
-
MainWindow.resize(
|
|
33
|
+
MainWindow.resize(700, 500)
|
|
34
34
|
MainWindow.setMinimumSize(QSize(250, 0))
|
|
35
35
|
MainWindow.setWindowTitle(u"Plover")
|
|
36
36
|
icon = QIcon()
|
|
@@ -70,6 +70,10 @@ class Ui_MainWindow(object):
|
|
|
70
70
|
self.centralwidget.setMinimumSize(QSize(0, 0))
|
|
71
71
|
self.gridLayout = QGridLayout(self.centralwidget)
|
|
72
72
|
self.gridLayout.setObjectName(u"gridLayout")
|
|
73
|
+
self.topSpacer = QSpacerItem(0, 4, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)
|
|
74
|
+
|
|
75
|
+
self.gridLayout.addItem(self.topSpacer, 0, 0, 1, 3)
|
|
76
|
+
|
|
73
77
|
self.groupBox = QGroupBox(self.centralwidget)
|
|
74
78
|
self.groupBox.setObjectName(u"groupBox")
|
|
75
79
|
sizePolicy1 = QSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Preferred)
|
|
@@ -106,12 +110,16 @@ class Ui_MainWindow(object):
|
|
|
106
110
|
self.gridLayout_2.addWidget(self.machine_type, 0, 0, 1, 2)
|
|
107
111
|
|
|
108
112
|
|
|
109
|
-
self.gridLayout.addWidget(self.groupBox,
|
|
113
|
+
self.gridLayout.addWidget(self.groupBox, 1, 0, 1, 1)
|
|
114
|
+
|
|
115
|
+
self.verticalSpacer = QSpacerItem(0, 10, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)
|
|
116
|
+
|
|
117
|
+
self.gridLayout.addItem(self.verticalSpacer, 2, 0, 1, 3)
|
|
110
118
|
|
|
111
119
|
self.dictionaries = DictionariesWidget(self.centralwidget)
|
|
112
120
|
self.dictionaries.setObjectName(u"dictionaries")
|
|
113
121
|
|
|
114
|
-
self.gridLayout.addWidget(self.dictionaries,
|
|
122
|
+
self.gridLayout.addWidget(self.dictionaries, 3, 0, 1, 3)
|
|
115
123
|
|
|
116
124
|
self.groupBox1 = QGroupBox(self.centralwidget)
|
|
117
125
|
self.groupBox1.setObjectName(u"groupBox1")
|
|
@@ -134,12 +142,11 @@ class Ui_MainWindow(object):
|
|
|
134
142
|
self.gridLayout_3.addWidget(self.output_disable, 1, 0, 1, 1)
|
|
135
143
|
|
|
136
144
|
|
|
137
|
-
self.gridLayout.addWidget(self.groupBox1,
|
|
145
|
+
self.gridLayout.addWidget(self.groupBox1, 1, 1, 1, 1)
|
|
138
146
|
|
|
139
147
|
MainWindow.setCentralWidget(self.centralwidget)
|
|
140
148
|
self.menubar = QMenuBar(MainWindow)
|
|
141
149
|
self.menubar.setObjectName(u"menubar")
|
|
142
|
-
self.menubar.setGeometry(QRect(0, 0, 329, 25))
|
|
143
150
|
self.menu_File = QMenu(self.menubar)
|
|
144
151
|
self.menu_File.setObjectName(u"menu_File")
|
|
145
152
|
self.menu_Tools = QMenu(self.menubar)
|