File: options_dialog.py

package info (click to toggle)
raysession 0.17.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 19,168 kB
  • sloc: python: 44,371; sh: 1,538; makefile: 208; xml: 86
file content (355 lines) | stat: -rw-r--r-- 13,554 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355

from pathlib import Path
from typing import TYPE_CHECKING, Optional

from qtpy.QtCore import Qt, QProcess, QSettings, Slot # type:ignore
from qtpy.QtGui import QIcon, QPixmap
from qtpy.QtWidgets import (QDialog, QApplication, QInputDialog,
                             QMessageBox, QWidget, QFileDialog)


from patshared import Naming, PrettyDiff
from ..patchcanvas import patchcanvas, xdg
from ..patchcanvas.theme_manager import ThemeData
from ..patchcanvas.init_values import GridStyle
from ..tools_widgets import is_dark_theme
from ..ui.canvas_options import Ui_CanvasOptions

if TYPE_CHECKING:
    from ..patchbay_manager import PatchbayManager


_translate = QApplication.translate


class CanvasOptionsDialog(QDialog):    
    def __init__(self, parent: QWidget, manager: 'PatchbayManager',
                 settings: Optional[QSettings] = None):
        QDialog.__init__(self, parent)
        self.ui = Ui_CanvasOptions()
        self.ui.setupUi(self)
        
        self.mng = manager
        
        box_layout_dict = {
            1.0: _translate('box_layout', 'Choose the smallest area'),
            1.1: _translate('box_layout', 'Prefer large boxes'),
            1.4: _translate('box_layout', 'Almost only large boxes'),
            2.0: _translate('box_layout', 'Force large boxes')
        }
        
        grid_style_dict = {
            GridStyle.NONE: _translate('grid_style', 'None'),
            GridStyle.TECHNICAL_GRID: _translate('grid_style', 'Technical Grid'),
            GridStyle.GRID: _translate('grid_style', 'Grid'),
            GridStyle.CHESSBOARD: _translate('grid_style', 'Chessboard')
        }
        
        for ratio, text in box_layout_dict.items():
            self.ui.comboBoxBoxesAutoLayout.addItem(text, ratio)

        for grid_style in GridStyle:
            self.ui.comboBoxGridStyle.addItem(
                grid_style_dict[grid_style], grid_style)

        self.set_values()

        self.ui.comboBoxTheme.activated.connect(self._theme_box_activated)
        self.ui.pushButtonEditTheme.clicked.connect(self._edit_theme)
        self.ui.pushButtonDuplicateTheme.clicked.connect(self._duplicate_theme)
        self.ui.pushButtonPatchichiExport.clicked.connect(self._export_to_patchichi)
        
        self._current_theme_ref = ''
        self._theme_list = list[ThemeData]()
        
        # connect checkboxs and spinbox signals to patchbays signals
        self.ui.checkBoxA2J.stateChanged.connect(
            manager.sg.a2j_grouped_changed) # type:ignore
        self.ui.checkBoxAlsa.stateChanged.connect(
            manager.sg.alsa_midi_enabled_changed) # type:ignore
        
        self.ui.checkBoxJackPrettyNames.stateChanged.connect(
            self._naming_changed)
        self.ui.checkBoxCustomNames.stateChanged.connect(
            self._naming_changed)
        self.ui.checkBoxGracefulNames.stateChanged.connect(
            self._naming_changed)
        self.ui.checkBoxExportCustomNames.clicked.connect(
            self._jack_export_naming_changed)
        self.ui.pushButtonExportCustomJack.clicked.connect(
            self._export_custom_names_to_jack)
        self.ui.pushButtonImportPrettyJack.clicked.connect(
            self._import_pretty_names_from_jack)
        
        self.ui.checkBoxShadows.stateChanged.connect(
            manager.sg.group_shadows_changed) # type:ignore
        self.ui.comboBoxGridStyle.currentIndexChanged.connect(
            self._grid_style_changed)
        self.ui.checkBoxAutoSelectItems.stateChanged.connect(
            manager.sg.auto_select_items_changed) # type:ignore
        self.ui.checkBoxElastic.stateChanged.connect(
            manager.sg.elastic_changed) # type:ignore
        self.ui.checkBoxBordersNavigation.stateChanged.connect(
            manager.sg.borders_nav_changed) # type:ignore
        self.ui.checkBoxPreventOverlap.stateChanged.connect(
            manager.sg.prevent_overlap_changed) # type:ignore
        self.ui.spinBoxMaxPortWidth.valueChanged.connect(
            manager.sg.max_port_width_changed) # type:ignore
        self.ui.spinBoxDefaultZoom.valueChanged.connect(
            self._change_default_zoom)
        self.ui.comboBoxBoxesAutoLayout.currentIndexChanged.connect(
            self._grouped_box_auto_layout_changed)
        self.ui.spinBoxGridWidth.valueChanged.connect(
            self._grid_width_changed)
        self.ui.spinBoxGridHeight.valueChanged.connect(
            self._grid_height_changed)

    def set_values(self):
        self.ui.checkBoxA2J.setChecked(
            self.mng.group_a2j_hw)
        self.ui.checkBoxAlsa.setChecked(
            self.mng.alsa_midi_enabled)
        
        self.ui.checkBoxJackPrettyNames.setChecked(
            Naming.METADATA_PRETTY in self.mng.naming)
        self.ui.checkBoxCustomNames.setChecked(
            Naming.CUSTOM in self.mng.naming)
        self.ui.checkBoxGracefulNames.setChecked(
            Naming.GRACEFUL in self.mng.naming)
        
        b = self.ui.checkBoxExportCustomNames
        if b.isEnabled():
            b.setChecked(
                Naming.CUSTOM in self.mng.jack_export_naming)
        
        options = patchcanvas.options
        
        self.ui.checkBoxShadows.setChecked(
            options.show_shadows)
        self.ui.comboBoxGridStyle.setCurrentIndex(
            options.grid_style.value)
        self.ui.checkBoxAutoSelectItems.setChecked(
            options.auto_select_items)
        self.ui.checkBoxElastic.setChecked(
            options.elastic)
        self.ui.checkBoxBordersNavigation.setChecked(
            options.borders_navigation)
        self.ui.checkBoxPreventOverlap.setChecked(
            options.prevent_overlap)
        self.ui.spinBoxMaxPortWidth.setValue(
            options.max_port_width)
        self.ui.spinBoxDefaultZoom.setValue(
            options.default_zoom)
        self.ui.spinBoxGridWidth.setValue(
            options.cell_width)
        self.ui.spinBoxGridHeight.setValue(
            options.cell_height)
        
        layout_ratio = options.box_grouped_auto_layout_ratio
        
        if layout_ratio <= 1.0:
            box_index = 0
        elif layout_ratio <= 1.3:
            box_index = 1
        elif layout_ratio < 2.0:
            box_index = 2
        else:
            box_index = 3
            
        self.ui.comboBoxBoxesAutoLayout.setCurrentIndex(box_index)

    @Slot(int)
    def _naming_changed(self, state: int):
        naming = Naming.TRUE_NAME
        if self.ui.checkBoxJackPrettyNames.isChecked():
            naming |= Naming.METADATA_PRETTY
        if self.ui.checkBoxCustomNames.isChecked():
            naming |= Naming.CUSTOM
        if self.ui.checkBoxGracefulNames.isChecked():
            naming |= Naming.GRACEFUL
        
        self.mng.change_naming(naming)

    @Slot(bool)
    def _jack_export_naming_changed(self, checked: bool):
        jack_exp_naming = Naming.TRUE_NAME
        if self.ui.checkBoxExportCustomNames.isChecked():
            jack_exp_naming |= Naming.CUSTOM 
        
        self.mng.change_jack_export_naming(jack_exp_naming)

    @Slot()
    def _export_custom_names_to_jack(self):
        self.mng.export_custom_names_to_jack()
        
    @Slot()
    def _import_pretty_names_from_jack(self):
        self.mng.import_pretty_names_from_jack()

    def auto_export_pretty_names_changed(self, state: bool):
        # option has been changed from the daemon itself 
        # (probably with ray_control)
        b = self.ui.checkBoxExportCustomNames
        if b.isEnabled():
            b.setChecked(state)
        else:
            b.setChecked(False)

    def change_pretty_diff(self, pretty_diff: PrettyDiff):
        self.ui.pushButtonExportCustomJack.setEnabled(
            PrettyDiff.NON_EXPORTED in pretty_diff)
        self.ui.pushButtonImportPrettyJack.setEnabled(
            PrettyDiff.NON_IMPORTED in pretty_diff)

    def set_pretty_names_locked(self, locked: bool):
        b = self.ui.checkBoxExportCustomNames
        if locked:
            b.setChecked(False)
        b.setEnabled(not locked)

    def _change_default_zoom(self, value: int):
        patchcanvas.set_default_zoom(value)
        patchcanvas.zoom_reset()

    def _theme_box_activated(self):
        current_theme_ref_id: str = self.ui.comboBoxTheme.currentData(
            Qt.ItemDataRole.UserRole)
        if current_theme_ref_id == self._current_theme_ref:
            return
        
        for theme_data in self._theme_list:
            if theme_data.ref_id == current_theme_ref_id:
                self.ui.pushButtonEditTheme.setEnabled(theme_data.editable)
                break

        self.mng.sg.theme_changed.emit(current_theme_ref_id)
        
    def _duplicate_theme(self):        
        new_theme_name, ok = QInputDialog.getText(
            self, _translate('patchbay_theme', 'New Theme Name'),
            _translate('patchbay_theme', 'Choose a name for the new theme :'))
        
        if not new_theme_name or not ok:
            return
        
        new_theme_name = new_theme_name.replace('/', '⁄')

        err = patchcanvas.copy_and_load_current_theme(new_theme_name)
        
        if err:
            message = _translate(
                'patchbay_theme', 'The copy of the theme directory failed')
            
            QMessageBox.warning(
                self, _translate('patchbay_theme', 'Copy failed !'), message)

    def _edit_theme(self):
        current_theme_ref_id = self.ui.comboBoxTheme.currentData(
            Qt.ItemDataRole.UserRole)
        
        for theme_data in self._theme_list:
            if (theme_data.ref_id == current_theme_ref_id
                    and theme_data.editable):
                # start the text editor process
                QProcess.startDetached('xdg-open', [theme_data.file_path])
                break

    def _export_to_patchichi(self):
        scenes_dir = xdg.xdg_data_home() / 'Patchichi' / 'scenes'

        if not scenes_dir.exists():
            try:
                scenes_dir.mkdir()
            except:
                pass
        
        if not scenes_dir.is_dir():
            scenes_dir = Path.home()
        
        ret, ok = QFileDialog.getSaveFileName(
            self,
            _translate(
                'file_dialog',
                'Where do you want to save this patchbay scene ?'),
            str(scenes_dir),
            _translate('file_dialog', 'Patchichi files (*.patchichi.json)'))

        if not ok:
            return
        
        self.mng.export_to_patchichi_json(Path(ret))

    def set_theme_list(self, theme_list: list[ThemeData]):
        self.ui.comboBoxTheme.clear()
        del self._theme_list
        self._theme_list = theme_list

        dark = '-dark' if is_dark_theme(self) else ''
        user_icon = QIcon(QPixmap(f':scalable/breeze{dark}/im-user'))

        for theme_data in theme_list:
            if theme_data.editable:
                self.ui.comboBoxTheme.addItem(
                    user_icon, theme_data.name, theme_data.ref_id) # type:ignore
            else:
                self.ui.comboBoxTheme.addItem(
                    theme_data.name, theme_data.ref_id)

    def set_theme(self, theme_ref: str):
        for i in range(self.ui.comboBoxTheme.count()):
            ref_id = self.ui.comboBoxTheme.itemData(
                i, Qt.ItemDataRole.UserRole)
            if ref_id == theme_ref:
                self.ui.comboBoxTheme.setCurrentIndex(i)
                break
        else:
            # the new theme has not been found
            # update the list and select it if it exists
            self.set_theme_list(patchcanvas.list_themes())
            for i in range(self.ui.comboBoxTheme.count()):
                ref_id = self.ui.comboBoxTheme.itemData(
                    i, Qt.ItemDataRole.UserRole)
                if ref_id == theme_ref:
                    self.ui.comboBoxTheme.setCurrentIndex(i)
                    
                    # update the edit button enable state
                    for theme_data in self._theme_list:
                        if theme_data.ref_id == ref_id:
                            self.ui.pushButtonEditTheme.setEnabled(
                                theme_data.editable)
                            break
                    break

    def enable_alsa_midi(self, yesno: bool):
        self.ui.checkBoxAlsa.setEnabled(yesno)
        if yesno:
            self.ui.checkBoxAlsa.setToolTip('')
        else:
            self.ui.checkBoxAlsa.setToolTip(
                _translate(
                    'alsa_midi', 
                    "ALSA python lib version is not present or too old.\n"
                    "Ensure to have python3-pyalsa >= 1.2.4"))

    def _grouped_box_auto_layout_changed(self, index: int):
        patchcanvas.set_grouped_box_layout_ratio(
            self.ui.comboBoxBoxesAutoLayout.currentData())

    def _grid_width_changed(self, value: int):
        patchcanvas.change_grid_width(value)
        
    def _grid_height_changed(self, value: int):
        patchcanvas.change_grid_height(value)

    def _grid_style_changed(self, value: int):
        grid_style: GridStyle = self.ui.comboBoxGridStyle.currentData()
        patchcanvas.change_grid_widget_style(grid_style)

    def showEvent(self, event):
        self.set_theme_list(patchcanvas.list_themes())
        self.set_theme(patchcanvas.get_theme())
        self.set_values()
        QDialog.showEvent(self, event)

    def closeEvent(self, event):
        QDialog.closeEvent(self, event)