├── Dockerfile
├── LICENSE
├── MANIFEST.in
├── SpinTool.sh
├── docker-compose.yml
├── docs
└── img
│ ├── ST_Carla_MIDI.png
│ ├── ST_Carla_Suite.png
│ ├── ST_Icons.png
│ ├── ST_Launcher_00.png
│ ├── ST_Launcher_01.png
│ ├── ST_Launcher_02.png
│ ├── ST_Logo_L.png
│ ├── ST_Logo_Transparent.png
│ ├── ST_beat_amount_detail.png
│ ├── ST_bpm_detail.png
│ ├── ST_connections_audio.png
│ ├── ST_connections_midi.png
│ ├── ST_overview.png
│ └── info
├── midi_controllers
├── AKAI_APC_Key25.sbm
├── AKAI_APC_Key25_KORG_nanoKONTROL2.sbm
└── info
├── readme.md
├── requirements.txt
└── superboucle
├── __init__.py
├── about.py
├── about_ui.py
├── about_ui.ui
├── add_clip.py
├── add_clip_ui.py
├── add_clip_ui.ui
├── add_port.py
├── add_port_ui.py
├── add_port_ui.ui
├── add_scene.py
├── add_scene_ui.py
├── add_scene_ui.ui
├── assistant.py
├── assistant_ui.py
├── assistant_ui.ui
├── cell.py
├── cell_ui.py
├── cell_ui.ui
├── clip.py
├── common.py
├── device.py
├── device_manager.py
├── device_manager_ui.py
├── device_manager_ui.ui
├── edit_clips.py
├── edit_clips_ui.py
├── edit_clips_ui.ui
├── export_samples.py
├── export_samples_ui.py
├── export_samples_ui.ui
├── gui.py
├── gui.qrc
├── gui_rc.py
├── gui_ui.py
├── gui_ui.ui
├── help.py
├── help_ui.py
├── icons
├── MeltinPop_Logo_100.png
├── ST_Logo_Small_Transparent.png
├── ST_Logo_XSmall_Transparent.png
├── Superdirt_Logo_80.png
├── black_goto_24.png
├── black_pause_24.png
├── black_play_24.png
├── black_rewind_24.png
├── clip-add.png
├── clip-behaviour.png
├── clip-edit.png
├── clip-functions.png
├── clip-groups.png
├── clip-measures.png
├── clip-start-stop.png
├── copy.png
├── edit-delete.png
├── fader.png
├── file.png
├── folder.png
├── icon.png
├── icon_dev.png
├── info
├── logo_sb.png
├── record_24.png
├── shift.png
├── sliders.png
├── stop.png
├── warning.png
├── white_goto_24.png
├── white_pause_24.png
├── white_play_24.png
└── white_rewind_24.png
├── jack.py
├── learn.py
├── learn_cell_ui.py
├── learn_cell_ui.ui
├── learn_ui.py
├── learn_ui.ui
├── mixer.py
├── mixer_ui.py
├── mixer_ui.ui
├── mixerstrip.py
├── mixerstrip_ui.py
├── mixerstrip_ui.ui
├── new_song.py
├── new_song_ui.py
├── new_song_ui.ui
├── playlist.py
├── playlist_ui.py
├── playlist_ui.ui
├── port_manager.py
├── port_manager_ui.py
├── port_manager_ui.ui
├── preferences.py
├── preferences_ui.py
├── preferences_ui.ui
├── qsuperdial.py
├── qtmodern
├── __init__.py
├── _utils.py
├── info
├── resources
│ ├── frameless.qss
│ ├── info
│ ├── style (copy).qss
│ └── style.qss
├── styles (copy).py
├── styles.py
└── windows.py
├── scene_manager.py
├── scene_manager_ui.py
├── scene_manager_ui.ui
├── settings.py
├── settings.pyc
├── song_annotation.py
├── song_annotation_ui.py
├── song_annotation_ui.ui
└── spin.py
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.7-buster
2 |
3 | WORKDIR /usr/src
4 | RUN apt-get update && \
5 | apt-get install -y libsndfile1-dev libgl1 libjack-jackd2-dev && \
6 | apt-get clean
7 | COPY requirements.txt /usr/src
8 | RUN pip3 install -r requirements.txt
9 | COPY . /usr/src/
10 | RUN python3 setup.py install
11 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include *.md superboucle/gui.qrc superboucle/icons/icon.ico
2 | recursive-include superboucle *.png
3 |
--------------------------------------------------------------------------------
/SpinTool.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
3 | cd $SCRIPTPATH
4 | export PYTHONPATH=$(pwd):$PYTHONPATH
5 | python3 superboucle/spin.py
6 | read
7 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | builder:
4 | build: ./
5 | image: spintool-builder
6 | stdin_open: true
7 | tty: true
8 | environment:
9 | - DISPLAY=:0
10 | volumes:
11 | - /tmp/.X11-unix:/tmp/.X11-unix
12 | - /dev/shm:/dev/shm
13 |
--------------------------------------------------------------------------------
/docs/img/ST_Carla_MIDI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/docs/img/ST_Carla_MIDI.png
--------------------------------------------------------------------------------
/docs/img/ST_Carla_Suite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/docs/img/ST_Carla_Suite.png
--------------------------------------------------------------------------------
/docs/img/ST_Icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/docs/img/ST_Icons.png
--------------------------------------------------------------------------------
/docs/img/ST_Launcher_00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/docs/img/ST_Launcher_00.png
--------------------------------------------------------------------------------
/docs/img/ST_Launcher_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/docs/img/ST_Launcher_01.png
--------------------------------------------------------------------------------
/docs/img/ST_Launcher_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/docs/img/ST_Launcher_02.png
--------------------------------------------------------------------------------
/docs/img/ST_Logo_L.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/docs/img/ST_Logo_L.png
--------------------------------------------------------------------------------
/docs/img/ST_Logo_Transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/docs/img/ST_Logo_Transparent.png
--------------------------------------------------------------------------------
/docs/img/ST_beat_amount_detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/docs/img/ST_beat_amount_detail.png
--------------------------------------------------------------------------------
/docs/img/ST_bpm_detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/docs/img/ST_bpm_detail.png
--------------------------------------------------------------------------------
/docs/img/ST_connections_audio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/docs/img/ST_connections_audio.png
--------------------------------------------------------------------------------
/docs/img/ST_connections_midi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/docs/img/ST_connections_midi.png
--------------------------------------------------------------------------------
/docs/img/ST_overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/docs/img/ST_overview.png
--------------------------------------------------------------------------------
/docs/img/info:
--------------------------------------------------------------------------------
1 | IMGs for Wiki and other documentation
2 |
--------------------------------------------------------------------------------
/midi_controllers/AKAI_APC_Key25.sbm:
--------------------------------------------------------------------------------
1 | {"start_stop": [[[9, 0, 32, 127], [9, 0, 33, 127], [9, 0, 34, 127], [9, 0, 35, 127], [9, 0, 36, 127], [9, 0, 37, 127], [9, 0, 38, 127], [9, 0, 39, 127]], [[9, 0, 24, 127], [9, 0, 25, 127], [9, 0, 26, 127], [9, 0, 27, 127], [9, 0, 28, 127], [9, 0, 29, 127], [9, 0, 30, 127], [9, 0, 31, 127]], [[9, 0, 16, 127], [9, 0, 17, 127], [9, 0, 18, 127], [9, 0, 19, 127], [9, 0, 20, 127], [9, 0, 21, 127], [9, 0, 22, 127], [9, 0, 23, 127]], [[9, 0, 8, 127], [9, 0, 9, 127], [9, 0, 10, 127], [9, 0, 11, 127], [9, 0, 12, 127], [9, 0, 13, 127], [9, 0, 14, 127], [9, 0, 15, 127]], [[9, 0, 0, 127], [9, 0, 1, 127], [9, 0, 2, 127], [9, 0, 3, 127], [9, 0, 4, 127], [9, 0, 5, 127], [9, 0, 6, 127], [9, 0, 7, 127]]], "black_vel": 0, "green_vel": 1, "blink_green_vel": 2, "red_vel": 3, "blink_red_vel": 4, "amber_vel": 5, "blink_amber_vel": 6, "song_volume_ctrl": false, "play_btn": [9, 0, 91, 127], "pause_btn": false, "rewind_btn": false, "goto_btn": false, "record_btn": [9, 0, 93, 127], "stop_btn": [9, 0, 81, 127], "shift_btn": [9, 0, 98, 127], "unlink_stripes_btn": false, "custom_reset_btn": false, "init_command": [], "scene_buttons": [[9, 0, 82, 127], [9, 0, 83, 127], [9, 0, 84, 127], [9, 0, 85, 127], [9, 0, 86, 127]], "mute_buttons": [[9, 0, 64, 127], [9, 0, 65, 127], [9, 0, 66, 127], [9, 0, 67, 127], [9, 0, 68, 127], [9, 0, 69, 127], [9, 0, 70, 127], [9, 0, 71, 127]], "ctrls": [[11, 0, 48], [11, 0, 49], [11, 0, 50], [11, 0, 51], [11, 0, 52], [11, 0, 53], [11, 0, 54], [11, 0, 55]], "send1ctrls": [], "send2ctrls": [], "name": "AKAI APC key 25"}
--------------------------------------------------------------------------------
/midi_controllers/AKAI_APC_Key25_KORG_nanoKONTROL2.sbm:
--------------------------------------------------------------------------------
1 | {"start_stop": [[[9, 0, 32, 127], [9, 0, 33, 127], [9, 0, 34, 127], [9, 0, 35, 127], [9, 0, 36, 127], [9, 0, 37, 127], [9, 0, 38, 127], [9, 0, 39, 127]], [[9, 0, 24, 127], [9, 0, 25, 127], [9, 0, 26, 127], [9, 0, 27, 127], [9, 0, 28, 127], [9, 0, 29, 127], [9, 0, 30, 127], [9, 0, 31, 127]], [[9, 0, 16, 127], [9, 0, 17, 127], [9, 0, 18, 127], [9, 0, 19, 127], [9, 0, 20, 127], [9, 0, 21, 127], [9, 0, 22, 127], [9, 0, 23, 127]], [[9, 0, 8, 127], [9, 0, 9, 127], [9, 0, 10, 127], [9, 0, 11, 127], [9, 0, 12, 127], [9, 0, 13, 127], [9, 0, 14, 127], [9, 0, 15, 127]], [[9, 0, 0, 127], [9, 0, 1, 127], [9, 0, 2, 127], [9, 0, 3, 127], [9, 0, 4, 127], [9, 0, 5, 127], [9, 0, 6, 127], [9, 0, 7, 127]]], "black_vel": 0, "green_vel": 1, "blink_green_vel": 2, "red_vel": 3, "blink_red_vel": 4, "amber_vel": 5, "blink_amber_vel": 6, "song_volume_ctrl": false, "play_btn": [11, 2, 41, 127], "pause_btn": [9, 0, 91, 127], "rewind_btn": [11, 2, 43, 127], "goto_btn": [11, 2, 44, 127], "record_btn": [11, 2, 45, 127], "stop_btn": [11, 2, 42, 127], "shift_btn": [9, 0, 98, 127], "unlink_stripes_btn": [11, 2, 46, 127], "custom_reset_btn": [11, 2, 60, 127], "init_command": [], "scene_buttons": [[9, 0, 82, 127], [9, 0, 83, 127], [9, 0, 84, 127], [9, 0, 85, 127], [9, 0, 86, 127]], "mute_buttons": [[9, 0, 64, 127], [9, 0, 65, 127], [9, 0, 66, 127], [9, 0, 67, 127], [9, 0, 68, 127], [9, 0, 69, 127], [9, 0, 70, 127], [9, 0, 71, 127]], "ctrls": [[11, 2, 0], [11, 2, 1], [11, 2, 2], [11, 2, 3], [11, 2, 4], [11, 2, 5], [11, 2, 6], [11, 2, 7]], "send1ctrls": [[11, 2, 16], [11, 2, 17], [11, 2, 18], [11, 2, 19], [11, 2, 20], [11, 2, 21], [11, 2, 22], [11, 2, 23]], "send2ctrls": [[11, 0, 48], [11, 0, 49], [11, 0, 50], [11, 0, 51], [11, 0, 52], [11, 0, 53], [11, 0, 54], [11, 0, 55]], "name": "AKAI APC key 25 + KORG nanoKONTROL 2", "description": "Configuration\n\nAKAI APC key 25 (on midi channels 1+2) :\n\nCLIPS buttons, \nSCENES buttons (scene launch 1 to 5), \nMUTE BUTTONS ( buttons under clips) \nSHIFT (shift), \nPAUSE (play/pause), \nSENDS2 (knobs)\n\nKORG nanoKONTROL 2 (on midi channel 3):\n\nOUTPUT PORTS VOLUMES (sliders),\nTRANSPORT (REWIND, forward as GO..TO, STOP, PLAY, REC), \nUNLINK (cycle), \nCUSTOM RESET (Set), \nSENDS1 (knobs)\n\nMIDI setup by Manu Controvento (Meltin'Pop)", "send1_enabled_buttons": [[11, 2, 32, 127], [11, 2, 33, 127], [11, 2, 34, 127], [11, 2, 35, 127], [11, 2, 36, 127], [11, 2, 37, 127], [11, 2, 38, 127], [11, 2, 39, 127]], "send2_enabled_buttons": [[9, 0, 64, 127], [9, 0, 65, 127], [9, 0, 66, 127], [9, 0, 67, 127], [9, 0, 68, 127], [9, 0, 69, 127], [9, 0, 70, 127], [9, 0, 71, 127]]}
--------------------------------------------------------------------------------
/midi_controllers/info:
--------------------------------------------------------------------------------
1 | Midi controllers scripts for SpinTools/SuperBoucle
2 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # SpinTool
2 |
3 | SpinTool is a loop based software fully controllable with any midi device,
4 | synced with Jack transport. This version derives from original Vampouille's
5 | SuperBoucle, starting from a fork of the original repository.
6 |
7 | 
8 |
9 | Check user manual (from Info menu of application) for a description of
10 | usage and functions.
11 | Press the H key for integrated help to have a quick
12 | help on what the mouse cursor is pointing at.
13 |
14 | Usage Wiki for Starting:
15 | https://github.com/manucontrovento/SpinTool/wiki
16 |
17 |
18 | ## Features
19 |
20 | * Jack Transport
21 | * Record
22 | * Audio input / output
23 | * Midi input / output
24 | * Normalize and revert samples
25 | * Negative sample offset, sample offset in beats or frames
26 | * Load several formats: WAV, FLAC, AIFF, ... (no MP3 at the moment)
27 | * Playlist management
28 | * Scenes management
29 | * Full intuitive MIDI learn interface
30 | * Support any MIDI device: generic keyboard, pad, BCF, Akai APC, ...
31 | * Fully controllable by MIDI device or mouse/keyboard
32 | * One-shot clips
33 | * Light-on all midi device buttons (scenes and transport too)
34 | * Preferences Window
35 | * Start a clip just after recording it
36 | * Show clip details when triggered for start/stop
37 | * Show clip details when its volume is changed from controller
38 | * Preferred grid size, to match your controller's buttons grid
39 | * Choice of clip recording color (amber is default, red available)
40 | * Open scenes and playlist windows on start up
41 | * New grid cells style, showing clip volume
42 | * New massive clips edit functions to change clips parameters and column instrument-wise assignment
43 | * New Export-all samples function
44 | * Mixer for output ports with full MIDI support
45 | * Integrated Help/Manual
46 | * Force clips play/stop
47 |
48 | SpinTool releases start from version 20.04.07
49 |
50 | ## Requirements
51 |
52 | ### Linux
53 |
54 | * Python 3
55 | * Pip for python 3
56 | * Python modules : Cffi, PySoundFile, Numpy, PyQT 5
57 | * Running jack server
58 |
59 | Recommended:
60 | * a2jmidid to access midi controller
61 | * Carla to save connections
62 |
63 | ## Installation
64 |
65 | * Install Jack server :
66 |
67 | sudo aptitude install jackd2 qjackctl
68 |
69 | * Install midi bridge (optional) :
70 |
71 | sudo aptitude install a2jmidid
72 |
73 | * Install python modules :
74 |
75 | sudo aptitude install python3 python3-pip python3-cffi python3-numpy python3-pyqt5
76 | sudo pip3 install PySoundFile
77 |
78 | * Download and extract last version of SpinTool from https://github.com/manucontrovento/SpinTool/releases/
79 |
80 | ## Running
81 |
82 | Start Jack audio server and then run SpinTool.sh script from SpinTool directory :
83 |
84 | ./SpinTool.sh
85 |
86 | ## Credits and links
87 |
88 | I have to thank first of all Vampouille, who created SuperBoucle and fixed some
89 | issues I reported, and Vince who helped me understanding how to start and proceed
90 | in my development.
91 |
92 | Original SuperBoucle master repository is here:
93 | https://github.com/Vampouille/superboucle
94 |
95 | and Vince activities website:
96 | https://www.sonejo.net/
97 |
98 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | PyQt5>=5.11
2 | SoundFile>=0.8.0
3 | numpy>=1.16
4 | psutil>=5.7.2
--------------------------------------------------------------------------------
/superboucle/__init__.py:
--------------------------------------------------------------------------------
1 | from superboucle.clip import Clip, Song, load_song_from_file
2 | from superboucle.gui import Gui
3 | #from superboucle.cell import cell_ui
4 | #import jack
5 | import superboucle.cell_ui as cell_ui
6 | import superboucle.qsuperdial
7 |
--------------------------------------------------------------------------------
/superboucle/about.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtWidgets import QDialog
2 | from superboucle.about_ui import Ui_Dialog
3 | from PyQt5.QtGui import QDesktopServices
4 | from PyQt5.QtCore import QUrl
5 | import common
6 |
7 | class About(QDialog, Ui_Dialog):
8 |
9 | def __init__(self, parent):
10 | super(About, self).__init__(parent)
11 | self.gui = parent
12 | self.setupUi(self)
13 | self.webLink = "https://github.com/manucontrovento/SpinTool"
14 | self.btnWebLink.clicked.connect(self.onWebLinkDoubleClick)
15 |
16 | self.labelVersion.setText(common.APP_VERSION)
17 |
18 | self.btnWebLink.setText(self.webLink)
19 |
20 |
21 | self.description = '''Current development by
22 | Manu Controvento (Meltin'Pop) and Vincent Rateau (Superdirt³ / Sonejo.net).
23 | Many many thanks go to Vampouille (Julien Acroute) for developing SuperBoucle,
24 | which was the base of SpinTool, and to IARI (Julian Jarecki) for further development on SB.
25 | '''
26 |
27 |
28 | self.license = '''This is a free and open source application, you can re-distribute and/or change it according to
29 | GNU General Public License version 2 or later.
30 | '''
31 |
32 |
33 | self.labelText.setText(self.description)
34 | self.labelLicense.setText(self.license)
35 |
36 | self.setModal(True)
37 | self.show()
38 |
39 | def onWebLinkDoubleClick(self):
40 | QDesktopServices.openUrl(QUrl(self.webLink))
41 |
42 | def onFinished(self):
43 | pass
44 |
--------------------------------------------------------------------------------
/superboucle/add_clip.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import Qt
2 | from superboucle.assistant import Assistant
3 | from PyQt5.QtGui import QCursor
4 | import help
5 | from PyQt5.QtWidgets import QDialog, QApplication
6 | from superboucle.add_clip_ui import Ui_Dialog
7 | from superboucle.clip import Clip, basename
8 | import os
9 | import settings
10 | import common
11 |
12 |
13 | class AddClipDialog(QDialog, Ui_Dialog):
14 | def __init__(self, parent, cell):
15 | super(AddClipDialog, self).__init__(parent)
16 | self.gui = parent
17 | self.cell = cell
18 | self.type = None
19 | self.setupUi(self)
20 |
21 | # default choice
22 | self.newButton.setChecked(True)
23 | self.type = 'new'
24 | self.fileList.setEnabled(False)
25 |
26 | self.newButton.clicked.connect(self.onNew)
27 | self.useButton.clicked.connect(self.onUse)
28 | self.emptyButton.clicked.connect(self.onEmpty)
29 | self.accepted.connect(self.onOk)
30 | self.cBoxMetronomeClip.stateChanged.connect(self.onMetronomeClip)
31 |
32 | for wav_id in self.gui.song.data:
33 | self.fileList.addItem(wav_id)
34 |
35 | self.setModal(True)
36 | self.show()
37 |
38 | def onNew(self):
39 | self.type = 'new'
40 |
41 | def onUse(self):
42 | self.type = 'use'
43 |
44 |
45 | def onEmpty(self):
46 | self.type = 'empty'
47 |
48 |
49 | def onMetronomeClip(self):
50 | if self.cBoxMetronomeClip.isChecked():
51 |
52 | if self.emptyButton.isChecked():
53 | self.newButton.setChecked(True)
54 | self.emptyButton.setEnabled(False)
55 | self.cBoxLockRec.setChecked(False)
56 | self.cBoxOneShotClip.setChecked(False)
57 | self.cBoxLockRec.setEnabled(False)
58 | self.cBoxOneShotClip.setEnabled(False)
59 |
60 | else:
61 |
62 | self.emptyButton.setEnabled(True)
63 | self.cBoxLockRec.setEnabled(True)
64 | self.cBoxOneShotClip.setEnabled(True)
65 |
66 |
67 | def onOk(self):
68 |
69 | new_clip = None
70 |
71 | if self.type == 'new':
72 | new_clip = self.cell.openClip()
73 |
74 | elif self.type == 'use':
75 | wav_id = self.fileList.currentText()
76 | new_clip = Clip(audio_file=basename(wav_id), name=os.path.splitext(basename(wav_id))[0])
77 |
78 | elif self.type == 'empty':
79 | new_clip = Clip(audio_file=None,
80 | name='audio-%02d' % len(self.gui.song.clips))
81 |
82 | if new_clip:
83 | new_clip.one_shot = self.cBoxOneShotClip.isChecked()
84 | new_clip.lock_rec = self.cBoxLockRec.isChecked()
85 |
86 |
87 | if self.cBoxMetronomeClip.isChecked():
88 |
89 | new_clip.always_play = True
90 | new_clip.mute_group = 0
91 |
92 | # checking if CLICK output port exists; creating it otherwise
93 | click_st_port = common.checkClickPort(settings.output_ports)
94 |
95 | # adding it to jack, ST ports and GUI selection, un-route to master
96 | if click_st_port == False:
97 | self.gui.addPort(common.CLICK_PORT, False)
98 | #settings.output_ports[common.CLICK_PORT]["to_master"] = False # -> un-route port from master
99 | #self.gui.output_mixer.updateGui(settings.output_ports) # -> re-update mixer
100 | #print(settings.output_ports[common.CLICK_PORT])
101 |
102 |
103 | # Assigning CLICK port to clip
104 | new_clip.output = common.CLICK_PORT
105 |
106 |
107 | self.cell.setClip(new_clip)
108 |
109 | if settings.auto_assign_new_clip_column:
110 | self.gui.autoAssignClipColumn(new_clip)
111 |
112 |
113 | # HELP management ---------------------------------------------------------
114 |
115 | def keyPressEvent(self, event):
116 |
117 | if event.key() == Qt.Key_H: # if pressed key is H (help)
118 |
119 | pos = QCursor.pos()
120 | widget = QApplication.widgetAt(pos) # this is widget under cursor
121 |
122 | if widget is None: return
123 | accName = widget.accessibleName() # this is widget accessible name
124 |
125 | if accName != "":
126 | wantedHelp = help.Context(accName) # Conversion of string accessible name to Context enum
127 | self.showContextHelp(wantedHelp)
128 |
129 |
130 | def showContextHelp(self, wantedHelp):
131 | helpText = help.getContextHelp(wantedHelp)
132 | Assistant(self, helpText, Assistant.MODE_CONTEXT)
133 |
--------------------------------------------------------------------------------
/superboucle/add_clip_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file '/home/manu/Sviluppo/SpinTool/superboucle/add_clip_ui.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.14.1
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 |
10 | from PyQt5 import QtCore, QtGui, QtWidgets
11 |
12 |
13 | class Ui_Dialog(object):
14 | def setupUi(self, Dialog):
15 | Dialog.setObjectName("Dialog")
16 | Dialog.resize(350, 240)
17 | Dialog.setMinimumSize(QtCore.QSize(350, 240))
18 | Dialog.setMaximumSize(QtCore.QSize(350, 240))
19 | Dialog.setStyleSheet("/* background-color: rgb(242, 242, 242);")
20 | self.verticalLayout_2 = QtWidgets.QVBoxLayout(Dialog)
21 | self.verticalLayout_2.setObjectName("verticalLayout_2")
22 | self.newButton = QtWidgets.QRadioButton(Dialog)
23 | self.newButton.setStyleSheet("color: rgb(0, 0, 0);\n"
24 | "font: 10pt \"Noto Sans\";")
25 | self.newButton.setObjectName("newButton")
26 | self.verticalLayout_2.addWidget(self.newButton)
27 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
28 | self.horizontalLayout_2.setObjectName("horizontalLayout_2")
29 | self.useButton = QtWidgets.QRadioButton(Dialog)
30 | self.useButton.setStyleSheet("/*color: rgb(0, 0, 0);\n"
31 | "font: 10pt \"Noto Sans\";")
32 | self.useButton.setObjectName("useButton")
33 | self.horizontalLayout_2.addWidget(self.useButton)
34 | self.fileList = QtWidgets.QComboBox(Dialog)
35 | self.fileList.setMinimumSize(QtCore.QSize(250, 0))
36 | self.fileList.setStyleSheet("/*color: rgb(0, 0, 0);")
37 | self.fileList.setObjectName("fileList")
38 | self.horizontalLayout_2.addWidget(self.fileList)
39 | self.verticalLayout_2.addLayout(self.horizontalLayout_2)
40 | self.emptyButton = QtWidgets.QRadioButton(Dialog)
41 | self.emptyButton.setStyleSheet("/*color: rgb(0, 0, 0);\n"
42 | "font: 10pt \"Noto Sans\";")
43 | self.emptyButton.setObjectName("emptyButton")
44 | self.verticalLayout_2.addWidget(self.emptyButton)
45 | self.line = QtWidgets.QFrame(Dialog)
46 | self.line.setFrameShape(QtWidgets.QFrame.HLine)
47 | self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
48 | self.line.setObjectName("line")
49 | self.verticalLayout_2.addWidget(self.line)
50 | self.groupBoxClip = QtWidgets.QGroupBox(Dialog)
51 | self.groupBoxClip.setStyleSheet("/*font: italic 9pt \"Noto Sans\";\n"
52 | "color: rgb(0, 0, 0);\n"
53 | "border: 1;")
54 | self.groupBoxClip.setFlat(False)
55 | self.groupBoxClip.setObjectName("groupBoxClip")
56 | self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBoxClip)
57 | self.verticalLayout.setObjectName("verticalLayout")
58 | self.cBoxMetronomeClip = QtWidgets.QCheckBox(self.groupBoxClip)
59 | self.cBoxMetronomeClip.setStyleSheet("/*color: rgb(0, 0, 0);\n"
60 | "background-color: rgb(242, 242, 242);\n"
61 | "font: 10pt \"Noto Sans\";")
62 | self.cBoxMetronomeClip.setObjectName("cBoxMetronomeClip")
63 | self.verticalLayout.addWidget(self.cBoxMetronomeClip)
64 | self.horizontalLayout = QtWidgets.QHBoxLayout()
65 | self.horizontalLayout.setObjectName("horizontalLayout")
66 | self.cBoxOneShotClip = QtWidgets.QCheckBox(self.groupBoxClip)
67 | self.cBoxOneShotClip.setStyleSheet("/*color: rgb(0, 0, 0);\n"
68 | "background-color: rgb(242, 242, 242);\n"
69 | "font: 10pt \"Noto Sans\";")
70 | self.cBoxOneShotClip.setObjectName("cBoxOneShotClip")
71 | self.horizontalLayout.addWidget(self.cBoxOneShotClip)
72 | self.cBoxLockRec = QtWidgets.QCheckBox(self.groupBoxClip)
73 | font = QtGui.QFont()
74 | font.setFamily("Noto Sans")
75 | font.setPointSize(10)
76 | font.setBold(False)
77 | font.setItalic(False)
78 | font.setWeight(50)
79 | self.cBoxLockRec.setFont(font)
80 | self.cBoxLockRec.setStyleSheet("/*color: rgb(0, 0, 0);\n"
81 | "background-color: rgb(242, 242, 242);\n"
82 | "font: 10pt \"Noto Sans\";")
83 | self.cBoxLockRec.setObjectName("cBoxLockRec")
84 | self.horizontalLayout.addWidget(self.cBoxLockRec)
85 | self.verticalLayout.addLayout(self.horizontalLayout)
86 | self.verticalLayout_2.addWidget(self.groupBoxClip)
87 | spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
88 | self.verticalLayout_2.addItem(spacerItem)
89 | self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
90 | self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
91 | self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
92 | self.buttonBox.setObjectName("buttonBox")
93 | self.verticalLayout_2.addWidget(self.buttonBox)
94 |
95 | self.retranslateUi(Dialog)
96 | self.buttonBox.accepted.connect(Dialog.accept)
97 | self.buttonBox.rejected.connect(Dialog.reject)
98 | self.useButton.toggled['bool'].connect(self.fileList.setEnabled)
99 | QtCore.QMetaObject.connectSlotsByName(Dialog)
100 |
101 | def retranslateUi(self, Dialog):
102 | _translate = QtCore.QCoreApplication.translate
103 | Dialog.setWindowTitle(_translate("Dialog", "Create new clip"))
104 | self.newButton.setText(_translate("Dialog", "Load new file..."))
105 | self.useButton.setText(_translate("Dialog", "Use file:"))
106 | self.emptyButton.setText(_translate("Dialog", "Empty clip"))
107 | self.groupBoxClip.setTitle(_translate("Dialog", "Clip behaviour"))
108 | self.cBoxMetronomeClip.setAccessibleName(_translate("Dialog", "Help_Clip_Metronome"))
109 | self.cBoxMetronomeClip.setText(_translate("Dialog", "Create a Click (metronome) clip"))
110 | self.cBoxOneShotClip.setText(_translate("Dialog", "One-shot clip"))
111 | self.cBoxLockRec.setText(_translate("Dialog", "Lock clip (no recording)"))
112 |
--------------------------------------------------------------------------------
/superboucle/add_clip_ui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 350
10 | 240
11 |
12 |
13 |
14 |
15 | 350
16 | 240
17 |
18 |
19 |
20 |
21 | 350
22 | 240
23 |
24 |
25 |
26 | Create new clip
27 |
28 |
29 | /* background-color: rgb(242, 242, 242);
30 |
31 |
32 | -
33 |
34 |
35 | color: rgb(0, 0, 0);
36 | font: 10pt "Noto Sans";
37 |
38 |
39 | Load new file...
40 |
41 |
42 |
43 | -
44 |
45 |
-
46 |
47 |
48 | /*color: rgb(0, 0, 0);
49 | font: 10pt "Noto Sans";
50 |
51 |
52 | Use file:
53 |
54 |
55 |
56 | -
57 |
58 |
59 |
60 | 250
61 | 0
62 |
63 |
64 |
65 | /*color: rgb(0, 0, 0);
66 |
67 |
68 |
69 |
70 |
71 | -
72 |
73 |
74 | /*color: rgb(0, 0, 0);
75 | font: 10pt "Noto Sans";
76 |
77 |
78 | Empty clip
79 |
80 |
81 |
82 | -
83 |
84 |
85 | Qt::Horizontal
86 |
87 |
88 |
89 | -
90 |
91 |
92 | /*font: italic 9pt "Noto Sans";
93 | color: rgb(0, 0, 0);
94 | border: 1;
95 |
96 |
97 | Clip behaviour
98 |
99 |
100 | false
101 |
102 |
103 |
-
104 |
105 |
106 | Help_Clip_Metronome
107 |
108 |
109 | /*color: rgb(0, 0, 0);
110 | background-color: rgb(242, 242, 242);
111 | font: 10pt "Noto Sans";
112 |
113 |
114 | Create a Click (metronome) clip
115 |
116 |
117 |
118 | -
119 |
120 |
-
121 |
122 |
123 | /*color: rgb(0, 0, 0);
124 | background-color: rgb(242, 242, 242);
125 | font: 10pt "Noto Sans";
126 |
127 |
128 | One-shot clip
129 |
130 |
131 |
132 | -
133 |
134 |
135 |
136 | Noto Sans
137 | 10
138 | 50
139 | false
140 | false
141 |
142 |
143 |
144 | /*color: rgb(0, 0, 0);
145 | background-color: rgb(242, 242, 242);
146 | font: 10pt "Noto Sans";
147 |
148 |
149 | Lock clip (no recording)
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | -
159 |
160 |
161 | Qt::Vertical
162 |
163 |
164 |
165 | 20
166 | 40
167 |
168 |
169 |
170 |
171 | -
172 |
173 |
174 | Qt::Horizontal
175 |
176 |
177 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 | buttonBox
187 | accepted()
188 | Dialog
189 | accept()
190 |
191 |
192 | 248
193 | 254
194 |
195 |
196 | 157
197 | 274
198 |
199 |
200 |
201 |
202 | buttonBox
203 | rejected()
204 | Dialog
205 | reject()
206 |
207 |
208 | 316
209 | 260
210 |
211 |
212 | 286
213 | 274
214 |
215 |
216 |
217 |
218 | useButton
219 | toggled(bool)
220 | fileList
221 | setEnabled(bool)
222 |
223 |
224 | 70
225 | 67
226 |
227 |
228 | 144
229 | 67
230 |
231 |
232 |
233 |
234 |
235 |
--------------------------------------------------------------------------------
/superboucle/add_port.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtWidgets import QDialog, QMessageBox
2 | from superboucle.add_port_ui import Ui_Dialog
3 |
4 | import common
5 | import settings
6 |
7 | class AddPortDialog(QDialog, Ui_Dialog):
8 | def __init__(self, gui, callback=None):
9 | super(AddPortDialog, self).__init__(gui)
10 | self.gui = gui
11 | self.callback = callback
12 | self.setupUi(self)
13 | self.accepted.connect(self.onOk)
14 | self.rejected.connect(self.onCancel)
15 | self.show()
16 | self.name.setFocus()
17 |
18 | def onOk(self):
19 |
20 | port_name = self.name.text().upper().strip()
21 |
22 | if (port_name == common.DEFAULT_PORT.upper() or port_name == common.MASTER_PORT.upper()
23 | or port_name == common.CLICK_PORT.upper() or port_name == common.SEND1_PORT.upper()
24 | or port_name == common.SEND2_PORT.upper()):
25 |
26 | message = QMessageBox(self)
27 | message.setWindowTitle("Can't create port " + self.name.text())
28 | message.setText(self.name.text() + " is a reserved SpinTool system port")
29 | message.show()
30 | return
31 |
32 | if "_L" in port_name or "_R" in port_name:
33 | message = QMessageBox(self)
34 | message.setWindowTitle("Can't create port " + self.name.text())
35 | message.setText("_L and _R are reserved by SpinTool and are not allowed in port name")
36 | message.show()
37 | return
38 |
39 | for existingPort in settings.output_ports.keys():
40 | if port_name == existingPort.upper():
41 | message = QMessageBox(self)
42 | message.setWindowTitle("Can't create port " + self.name.text())
43 | message.setText(self.name.text() + " output port is already existing")
44 | message.show()
45 | return
46 |
47 | self.gui.addPort(self.name.text())
48 |
49 | if self.callback:
50 | self.callback()
51 |
52 |
53 | def onCancel(self):
54 | if self.gui.last_clip:
55 | self.gui.output.setCurrentText(self.gui.last_clip.output)
56 |
--------------------------------------------------------------------------------
/superboucle/add_port_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file '/home/manu/Applicazioni/SpinTool/spintool/add_port_ui.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.12.3
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 |
10 | from PyQt5 import QtCore, QtGui, QtWidgets
11 |
12 |
13 | class Ui_Dialog(object):
14 | def setupUi(self, Dialog):
15 | Dialog.setObjectName("Dialog")
16 | Dialog.resize(301, 88)
17 | Dialog.setStyleSheet("background-color: rgb(242, 242, 242);")
18 | self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
19 | self.buttonBox.setGeometry(QtCore.QRect(70, 50, 171, 32))
20 | self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
21 | self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
22 | self.buttonBox.setCenterButtons(True)
23 | self.buttonBox.setObjectName("buttonBox")
24 | self.name = QtWidgets.QLineEdit(Dialog)
25 | self.name.setGeometry(QtCore.QRect(130, 10, 151, 23))
26 | self.name.setStyleSheet("color: rgb(0, 0, 0);\n"
27 | "background-color: rgb(255, 255, 255);")
28 | self.name.setObjectName("name")
29 | self.label = QtWidgets.QLabel(Dialog)
30 | self.label.setGeometry(QtCore.QRect(20, 15, 111, 16))
31 | self.label.setStyleSheet("color: rgb(0, 0, 0);")
32 | self.label.setObjectName("label")
33 |
34 | self.retranslateUi(Dialog)
35 | self.buttonBox.accepted.connect(Dialog.accept)
36 | self.buttonBox.rejected.connect(Dialog.reject)
37 | QtCore.QMetaObject.connectSlotsByName(Dialog)
38 |
39 | def retranslateUi(self, Dialog):
40 | _translate = QtCore.QCoreApplication.translate
41 | Dialog.setWindowTitle(_translate("Dialog", "Add new Port..."))
42 | self.label.setText(_translate("Dialog", "New Port name :"))
43 |
--------------------------------------------------------------------------------
/superboucle/add_port_ui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 301
10 | 88
11 |
12 |
13 |
14 | Add new Port...
15 |
16 |
17 | background-color: rgb(242, 242, 242);
18 |
19 |
20 |
21 |
22 | 70
23 | 50
24 | 171
25 | 32
26 |
27 |
28 |
29 | Qt::Horizontal
30 |
31 |
32 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
33 |
34 |
35 | true
36 |
37 |
38 |
39 |
40 |
41 | 130
42 | 10
43 | 151
44 | 23
45 |
46 |
47 |
48 | color: rgb(0, 0, 0);
49 | background-color: rgb(255, 255, 255);
50 |
51 |
52 |
53 |
54 |
55 | 20
56 | 15
57 | 111
58 | 16
59 |
60 |
61 |
62 | color: rgb(0, 0, 0);
63 |
64 |
65 | New Port name :
66 |
67 |
68 |
69 |
70 |
71 |
72 | buttonBox
73 | accepted()
74 | Dialog
75 | accept()
76 |
77 |
78 | 248
79 | 254
80 |
81 |
82 | 157
83 | 274
84 |
85 |
86 |
87 |
88 | buttonBox
89 | rejected()
90 | Dialog
91 | reject()
92 |
93 |
94 | 316
95 | 260
96 |
97 |
98 | 286
99 | 274
100 |
101 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/superboucle/add_scene.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import Qt
2 | from superboucle.assistant import Assistant
3 | from PyQt5.QtGui import QCursor
4 | import help
5 | from PyQt5.QtWidgets import QDialog, QApplication
6 | from superboucle.add_scene_ui import Ui_Dialog
7 |
8 | class AddSceneDialog(QDialog, Ui_Dialog):
9 | def __init__(self, gui, callback=None):
10 | super(AddSceneDialog, self).__init__(gui)
11 | self.gui = gui
12 | self.callback = callback
13 | self.setupUi(self)
14 | self.accepted.connect(self.onOk)
15 |
16 | if self.gui.song.selectedClips().__len__() > 0:
17 | # if there are some Selected clip in Song, including them is suggested:
18 | self.checkBoxIncludeSelected.setChecked(True)
19 | self.checkBoxIncludeStart.setChecked(False)
20 | else:
21 | # otherwise including starting / playing clips is suggested:
22 | self.checkBoxIncludeSelected.setChecked(False)
23 | self.checkBoxIncludeStart.setChecked(True)
24 |
25 | self.show()
26 | self.name.setFocus()
27 |
28 | def onOk(self):
29 | self.gui.song.addScene(self.name.text(), self.checkBoxIncludeStart.isChecked(), self.checkBoxIncludeSelected.isChecked())
30 | if self.callback:
31 | self.callback()
32 |
33 | # HELP management ---------------------------------------------------------
34 |
35 | def keyPressEvent(self, event):
36 |
37 | if event.key() == Qt.Key_H: # if pressed key is H (help)
38 |
39 | pos = QCursor.pos()
40 | widget = QApplication.widgetAt(pos) # this is widget under cursor
41 |
42 | if widget is None: return
43 | accName = widget.accessibleName() # this is widget accessible name
44 |
45 | if accName != "":
46 | wantedHelp = help.Context(accName) # Conversion of string accessible name to Context enum
47 | self.showContextHelp(wantedHelp)
48 |
49 |
50 | def showContextHelp(self, wantedHelp):
51 | helpText = help.getContextHelp(wantedHelp)
52 | Assistant(self, helpText, Assistant.MODE_CONTEXT)
--------------------------------------------------------------------------------
/superboucle/add_scene_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file '/home/manu/Sviluppo/SpinTool/superboucle/add_scene_ui.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.14.1
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 |
10 | from PyQt5 import QtCore, QtGui, QtWidgets
11 |
12 |
13 | class Ui_Dialog(object):
14 | def setupUi(self, Dialog):
15 | Dialog.setObjectName("Dialog")
16 | Dialog.resize(482, 171)
17 | self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
18 | self.buttonBox.setGeometry(QtCore.QRect(360, 0, 111, 91))
19 | self.buttonBox.setOrientation(QtCore.Qt.Vertical)
20 | self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
21 | self.buttonBox.setCenterButtons(True)
22 | self.buttonBox.setObjectName("buttonBox")
23 | self.name = QtWidgets.QLineEdit(Dialog)
24 | self.name.setGeometry(QtCore.QRect(130, 12, 211, 31))
25 | self.name.setObjectName("name")
26 | self.label = QtWidgets.QLabel(Dialog)
27 | self.label.setGeometry(QtCore.QRect(17, 20, 111, 16))
28 | self.label.setObjectName("label")
29 | self.checkBoxIncludeSelected = QtWidgets.QCheckBox(Dialog)
30 | self.checkBoxIncludeSelected.setGeometry(QtCore.QRect(10, 70, 341, 29))
31 | self.checkBoxIncludeSelected.setObjectName("checkBoxIncludeSelected")
32 | self.checkBoxIncludeStart = QtWidgets.QCheckBox(Dialog)
33 | self.checkBoxIncludeStart.setGeometry(QtCore.QRect(10, 110, 341, 29))
34 | self.checkBoxIncludeStart.setObjectName("checkBoxIncludeStart")
35 |
36 | self.retranslateUi(Dialog)
37 | self.buttonBox.accepted.connect(Dialog.accept)
38 | self.buttonBox.rejected.connect(Dialog.reject)
39 | QtCore.QMetaObject.connectSlotsByName(Dialog)
40 |
41 | def retranslateUi(self, Dialog):
42 | _translate = QtCore.QCoreApplication.translate
43 | Dialog.setWindowTitle(_translate("Dialog", "Add new Scene..."))
44 | self.label.setText(_translate("Dialog", "New Scene name :"))
45 | self.checkBoxIncludeSelected.setAccessibleName(_translate("Dialog", "Help_Scene_Include"))
46 | self.checkBoxIncludeSelected.setText(_translate("Dialog", "include selected clips"))
47 | self.checkBoxIncludeStart.setAccessibleName(_translate("Dialog", "Help_Scene_Include"))
48 | self.checkBoxIncludeStart.setText(_translate("Dialog", "include playing / starting clips"))
49 |
--------------------------------------------------------------------------------
/superboucle/add_scene_ui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 482
10 | 171
11 |
12 |
13 |
14 | Add new Scene...
15 |
16 |
17 |
18 |
19 | 360
20 | 0
21 | 111
22 | 91
23 |
24 |
25 |
26 | Qt::Vertical
27 |
28 |
29 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
30 |
31 |
32 | true
33 |
34 |
35 |
36 |
37 |
38 | 130
39 | 12
40 | 211
41 | 31
42 |
43 |
44 |
45 |
46 |
47 |
48 | 17
49 | 20
50 | 111
51 | 16
52 |
53 |
54 |
55 | New Scene name :
56 |
57 |
58 |
59 |
60 |
61 | 10
62 | 70
63 | 341
64 | 29
65 |
66 |
67 |
68 | Help_Scene_Include
69 |
70 |
71 | include selected clips
72 |
73 |
74 |
75 |
76 |
77 | 10
78 | 110
79 | 341
80 | 29
81 |
82 |
83 |
84 | Help_Scene_Include
85 |
86 |
87 | include playing / starting clips
88 |
89 |
90 |
91 |
92 |
93 |
94 | buttonBox
95 | accepted()
96 | Dialog
97 | accept()
98 |
99 |
100 | 248
101 | 254
102 |
103 |
104 | 157
105 | 274
106 |
107 |
108 |
109 |
110 | buttonBox
111 | rejected()
112 | Dialog
113 | reject()
114 |
115 |
116 | 316
117 | 260
118 |
119 |
120 | 286
121 | 274
122 |
123 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/superboucle/assistant.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtWidgets import QDialog
2 | from superboucle.assistant_ui import Ui_Dialog
3 | import copy
4 | import settings
5 |
6 | class Assistant(QDialog, Ui_Dialog):
7 |
8 | MODE_MANUAL = 1
9 | MODE_CONTEXT = 2
10 |
11 | def __init__(self, parent, text, mode):
12 | super(Assistant, self).__init__(parent)
13 | self.gui = parent
14 |
15 | self.setupUi(self)
16 | self.updateText(text)
17 |
18 | self.txtHelp.setReadOnly(True)
19 | self.labelLogo.setDisabled(True)
20 |
21 | self.setLayout(self.verticalLayout)
22 |
23 | if mode == self.MODE_MANUAL:
24 | self.displayAsManual()
25 | elif mode == self.MODE_CONTEXT:
26 | self.displayAsContext()
27 |
28 | self.show()
29 |
30 |
31 | def updateText(self, text):
32 | self.txtHelp.setText(text)
33 |
34 | def displayAsContext(self):
35 | self.labelAssistant.setText("Assistant")
36 | self.resize(680, 460)
37 |
38 | def displayAsManual(self):
39 | self.labelAssistant.setText("User Manual")
40 | self.resize(790, 650)
41 |
42 | def onFinished(self):
43 | pass
44 |
--------------------------------------------------------------------------------
/superboucle/assistant_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'assistant_ui.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.14.1
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 |
10 | from PyQt5 import QtCore, QtGui, QtWidgets
11 |
12 |
13 | class Ui_Dialog(object):
14 | def setupUi(self, Dialog):
15 | Dialog.setObjectName("Dialog")
16 | Dialog.setWindowModality(QtCore.Qt.WindowModal)
17 | Dialog.resize(774, 517)
18 | Dialog.setMinimumSize(QtCore.QSize(560, 360))
19 | icon = QtGui.QIcon()
20 | icon.addPixmap(QtGui.QPixmap(":/icons/icons/icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
21 | Dialog.setWindowIcon(icon)
22 | Dialog.setStyleSheet("background-color: rgb(242, 242, 242);")
23 | self.verticalLayoutWidget = QtWidgets.QWidget(Dialog)
24 | self.verticalLayoutWidget.setGeometry(QtCore.QRect(0, 10, 771, 501))
25 | self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
26 | self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
27 | self.verticalLayout.setSizeConstraint(QtWidgets.QLayout.SetMaximumSize)
28 | self.verticalLayout.setContentsMargins(0, 2, 0, 0)
29 | self.verticalLayout.setObjectName("verticalLayout")
30 | self.labelLogo = QtWidgets.QLabel(self.verticalLayoutWidget)
31 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
32 | sizePolicy.setHorizontalStretch(0)
33 | sizePolicy.setVerticalStretch(0)
34 | sizePolicy.setHeightForWidth(self.labelLogo.sizePolicy().hasHeightForWidth())
35 | self.labelLogo.setSizePolicy(sizePolicy)
36 | self.labelLogo.setMinimumSize(QtCore.QSize(0, 0))
37 | self.labelLogo.setMaximumSize(QtCore.QSize(16777215, 16777214))
38 | self.labelLogo.setText("")
39 | self.labelLogo.setPixmap(QtGui.QPixmap(":/icons/icons/ST_Logo_Small_Transparent.png"))
40 | self.labelLogo.setScaledContents(False)
41 | self.labelLogo.setAlignment(QtCore.Qt.AlignCenter)
42 | self.labelLogo.setIndent(-1)
43 | self.labelLogo.setObjectName("labelLogo")
44 | self.verticalLayout.addWidget(self.labelLogo)
45 | self.labelAssistant = QtWidgets.QLabel(self.verticalLayoutWidget)
46 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
47 | sizePolicy.setHorizontalStretch(0)
48 | sizePolicy.setVerticalStretch(0)
49 | sizePolicy.setHeightForWidth(self.labelAssistant.sizePolicy().hasHeightForWidth())
50 | self.labelAssistant.setSizePolicy(sizePolicy)
51 | self.labelAssistant.setStyleSheet("color: rgb(160, 160, 160);\n"
52 | "font: bold italic 18pt \"Noto Sans\";")
53 | self.labelAssistant.setAlignment(QtCore.Qt.AlignCenter)
54 | self.labelAssistant.setObjectName("labelAssistant")
55 | self.verticalLayout.addWidget(self.labelAssistant)
56 | self.horizontalLayout = QtWidgets.QHBoxLayout()
57 | self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetMaximumSize)
58 | self.horizontalLayout.setContentsMargins(10, 10, 10, 10)
59 | self.horizontalLayout.setSpacing(5)
60 | self.horizontalLayout.setObjectName("horizontalLayout")
61 | self.txtHelp = QtWidgets.QTextBrowser(self.verticalLayoutWidget)
62 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
63 | sizePolicy.setHorizontalStretch(1)
64 | sizePolicy.setVerticalStretch(1)
65 | sizePolicy.setHeightForWidth(self.txtHelp.sizePolicy().hasHeightForWidth())
66 | self.txtHelp.setSizePolicy(sizePolicy)
67 | self.txtHelp.setStyleSheet("color: rgb(0, 0, 0);\n"
68 | "background-color: rgb(242, 242, 242);\n"
69 | "font: 12pt \"Noto Sans\";\n"
70 | "border: None;")
71 | self.txtHelp.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
72 | self.txtHelp.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
73 | self.txtHelp.setDocumentTitle("")
74 | self.txtHelp.setReadOnly(False)
75 | self.txtHelp.setAcceptRichText(True)
76 | self.txtHelp.setObjectName("txtHelp")
77 | self.horizontalLayout.addWidget(self.txtHelp)
78 | self.verticalLayout.addLayout(self.horizontalLayout)
79 |
80 | self.retranslateUi(Dialog)
81 | QtCore.QMetaObject.connectSlotsByName(Dialog)
82 |
83 | def retranslateUi(self, Dialog):
84 | _translate = QtCore.QCoreApplication.translate
85 | Dialog.setWindowTitle(_translate("Dialog", "SpinTool Assistant"))
86 | self.labelAssistant.setText(_translate("Dialog", "assistant"))
87 | self.txtHelp.setHtml(_translate("Dialog", "\n"
88 | "
\n"
91 | "
"))
92 | import gui_rc
93 |
--------------------------------------------------------------------------------
/superboucle/assistant_ui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 | Qt::WindowModal
7 |
8 |
9 |
10 | 0
11 | 0
12 | 774
13 | 517
14 |
15 |
16 |
17 |
18 | 560
19 | 360
20 |
21 |
22 |
23 | SpinTool Assistant
24 |
25 |
26 |
27 | :/icons/icons/icon.png:/icons/icons/icon.png
28 |
29 |
30 | background-color: rgb(242, 242, 242);
31 |
32 |
33 |
34 |
35 | 0
36 | 10
37 | 771
38 | 501
39 |
40 |
41 |
42 |
43 | QLayout::SetMaximumSize
44 |
45 |
46 | 2
47 |
48 | -
49 |
50 |
51 |
52 | 0
53 | 0
54 |
55 |
56 |
57 |
58 | 0
59 | 0
60 |
61 |
62 |
63 |
64 | 16777215
65 | 16777214
66 |
67 |
68 |
69 |
70 |
71 |
72 | :/icons/icons/ST_Logo_Small_Transparent.png
73 |
74 |
75 | false
76 |
77 |
78 | Qt::AlignCenter
79 |
80 |
81 | -8
82 |
83 |
84 | -1
85 |
86 |
87 |
88 | -
89 |
90 |
91 |
92 | 0
93 | 0
94 |
95 |
96 |
97 | color: rgb(160, 160, 160);
98 | font: bold italic 18pt "Noto Sans";
99 |
100 |
101 | assistant
102 |
103 |
104 | Qt::AlignCenter
105 |
106 |
107 |
108 | -
109 |
110 |
111 | 5
112 |
113 |
114 | QLayout::SetMaximumSize
115 |
116 |
117 | 10
118 |
119 |
-
120 |
121 |
122 |
123 | 1
124 | 1
125 |
126 |
127 |
128 | color: rgb(0, 0, 0);
129 | background-color: rgb(242, 242, 242);
130 | font: 12pt "Noto Sans";
131 | border: None;
132 |
133 |
134 | Qt::ScrollBarAlwaysOn
135 |
136 |
137 | Qt::ScrollBarAlwaysOff
138 |
139 |
140 |
141 |
142 |
143 | false
144 |
145 |
146 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
147 | <html><head><meta name="qrichtext" content="1" /><style type="text/css">
148 | p, li { white-space: pre-wrap; }
149 | </style></head><body style=" font-family:'Noto Sans'; font-size:12pt; font-weight:400; font-style:normal;">
150 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;"><br /></p></body></html>
151 |
152 |
153 | true
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/superboucle/cell_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file '/home/manu/Sviluppo/SpinTool/superboucle/cell_ui.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.14.1
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 |
10 | from PyQt5 import QtCore, QtGui, QtWidgets
11 |
12 |
13 | class Ui_Cell(object):
14 | def setupUi(self, Cell):
15 | Cell.setObjectName("Cell")
16 | Cell.resize(255, 225)
17 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
18 | sizePolicy.setHorizontalStretch(1)
19 | sizePolicy.setVerticalStretch(1)
20 | sizePolicy.setHeightForWidth(Cell.sizePolicy().hasHeightForWidth())
21 | Cell.setSizePolicy(sizePolicy)
22 | Cell.setMinimumSize(QtCore.QSize(120, 112))
23 | font = QtGui.QFont()
24 | font.setFamily("Lato")
25 | Cell.setFont(font)
26 | self.cell_frame = QtWidgets.QFrame(Cell)
27 | self.cell_frame.setGeometry(QtCore.QRect(0, 0, 110, 102))
28 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
29 | sizePolicy.setHorizontalStretch(0)
30 | sizePolicy.setVerticalStretch(0)
31 | sizePolicy.setHeightForWidth(self.cell_frame.sizePolicy().hasHeightForWidth())
32 | self.cell_frame.setSizePolicy(sizePolicy)
33 | self.cell_frame.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
34 | self.cell_frame.setStyleSheet("#frame {border: 0px;\n"
35 | " background-color: rgb(190, 190, 190);\n"
36 | "border-radius: 10px;}")
37 | self.cell_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
38 | self.cell_frame.setFrameShadow(QtWidgets.QFrame.Raised)
39 | self.cell_frame.setObjectName("cell_frame")
40 | self.clip_name = QtWidgets.QLabel(self.cell_frame)
41 | self.clip_name.setGeometry(QtCore.QRect(3, 2, 105, 46))
42 | font = QtGui.QFont()
43 | font.setFamily("Noto Sans")
44 | font.setPointSize(14)
45 | font.setBold(True)
46 | font.setItalic(False)
47 | font.setWeight(75)
48 | self.clip_name.setFont(font)
49 | self.clip_name.setStyleSheet("font: bold 14pt \"Noto Sans\";\n"
50 | "color: rgb(0, 0, 0);\n"
51 | "text-align: center;")
52 | self.clip_name.setInputMethodHints(QtCore.Qt.ImhNone)
53 | self.clip_name.setText("")
54 | self.clip_name.setAlignment(QtCore.Qt.AlignCenter)
55 | self.clip_name.setWordWrap(True)
56 | self.clip_name.setObjectName("clip_name")
57 | self.clip_position = QtWidgets.QProgressBar(self.cell_frame)
58 | self.clip_position.setGeometry(QtCore.QRect(5, 85, 99, 13))
59 | self.clip_position.setStyleSheet("color: rgb(0, 85, 255);\n"
60 | "background-color: rgb(190, 190, 190);")
61 | self.clip_position.setMaximum(97)
62 | self.clip_position.setProperty("value", 0)
63 | self.clip_position.setTextVisible(False)
64 | self.clip_position.setObjectName("clip_position")
65 | self.edit = QtWidgets.QPushButton(self.cell_frame)
66 | self.edit.setGeometry(QtCore.QRect(70, 49, 33, 33))
67 | font = QtGui.QFont()
68 | font.setFamily("Noto Sans")
69 | font.setPointSize(10)
70 | font.setBold(False)
71 | font.setItalic(True)
72 | font.setWeight(50)
73 | self.edit.setFont(font)
74 | self.edit.setFocusPolicy(QtCore.Qt.NoFocus)
75 | self.edit.setStyleSheet("font: italic 10pt \"Noto Sans\";\n"
76 | "color: rgb(0, 0, 0);\n"
77 | "background-color: rgb(190, 190, 190);\n"
78 | "text-align: center;")
79 | self.edit.setText("")
80 | icon = QtGui.QIcon()
81 | icon.addPixmap(QtGui.QPixmap(":/icons/icons/clip-add.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
82 | self.edit.setIcon(icon)
83 | self.edit.setIconSize(QtCore.QSize(35, 35))
84 | self.edit.setAutoDefault(False)
85 | self.edit.setDefault(False)
86 | self.edit.setFlat(False)
87 | self.edit.setObjectName("edit")
88 | self.start_stop = QtWidgets.QPushButton(self.cell_frame)
89 | self.start_stop.setGeometry(QtCore.QRect(5, 49, 33, 33))
90 | font = QtGui.QFont()
91 | font.setFamily("Noto Sans")
92 | font.setPointSize(10)
93 | font.setBold(False)
94 | font.setItalic(True)
95 | font.setWeight(50)
96 | self.start_stop.setFont(font)
97 | self.start_stop.setFocusPolicy(QtCore.Qt.NoFocus)
98 | self.start_stop.setStyleSheet("font: italic 10pt \"Noto Sans\";\n"
99 | "background-color: rgb(190, 190, 190);\n"
100 | "color: rgb(0, 0, 0);\n"
101 | "text-align: center;")
102 | self.start_stop.setText("")
103 | icon1 = QtGui.QIcon()
104 | icon1.addPixmap(QtGui.QPixmap(":/icons/icons/clip-start-stop.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
105 | self.start_stop.setIcon(icon1)
106 | self.start_stop.setIconSize(QtCore.QSize(27, 27))
107 | self.start_stop.setObjectName("start_stop")
108 | self.labelVolume = QtWidgets.QLabel(self.cell_frame)
109 | self.labelVolume.setGeometry(QtCore.QRect(0, 49, 111, 33))
110 | self.labelVolume.setStyleSheet("font: bold 12pt \"Noto Sans\";")
111 | self.labelVolume.setTextFormat(QtCore.Qt.PlainText)
112 | self.labelVolume.setScaledContents(False)
113 | self.labelVolume.setAlignment(QtCore.Qt.AlignCenter)
114 | self.labelVolume.setWordWrap(True)
115 | self.labelVolume.setIndent(0)
116 | self.labelVolume.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
117 | self.labelVolume.setObjectName("labelVolume")
118 | self.labelVolume.raise_()
119 | self.clip_name.raise_()
120 | self.clip_position.raise_()
121 | self.edit.raise_()
122 | self.start_stop.raise_()
123 |
124 | self.retranslateUi(Cell)
125 | QtCore.QMetaObject.connectSlotsByName(Cell)
126 |
127 | def retranslateUi(self, Cell):
128 | _translate = QtCore.QCoreApplication.translate
129 | Cell.setWindowTitle(_translate("Cell", "Form"))
130 | self.cell_frame.setAccessibleName(_translate("Cell", "Help_Cell_Info"))
131 | self.clip_name.setAccessibleName(_translate("Cell", "Help_Cell_Info"))
132 | self.clip_position.setAccessibleName(_translate("Cell", "Help_Cell_Info"))
133 | self.edit.setAccessibleName(_translate("Cell", "Help_Cell_Info"))
134 | self.start_stop.setAccessibleName(_translate("Cell", "Help_Cell_Info"))
135 | self.labelVolume.setAccessibleName(_translate("Cell", "Help_Cell_Info"))
136 | self.labelVolume.setText(_translate("Cell", "5"))
137 | import gui_rc
138 |
--------------------------------------------------------------------------------
/superboucle/cell_ui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Cell
4 |
5 |
6 |
7 | 0
8 | 0
9 | 255
10 | 225
11 |
12 |
13 |
14 |
15 | 1
16 | 1
17 |
18 |
19 |
20 |
21 | 120
22 | 112
23 |
24 |
25 |
26 |
27 | Lato
28 |
29 |
30 |
31 | Form
32 |
33 |
34 |
35 |
36 | 0
37 | 0
38 | 110
39 | 102
40 |
41 |
42 |
43 |
44 | 0
45 | 0
46 |
47 |
48 |
49 | PointingHandCursor
50 |
51 |
52 | Help_Cell_Info
53 |
54 |
55 | #frame {border: 0px;
56 | background-color: rgb(190, 190, 190);
57 | border-radius: 10px;}
58 |
59 |
60 | QFrame::StyledPanel
61 |
62 |
63 | QFrame::Raised
64 |
65 |
66 |
67 |
68 | 3
69 | 2
70 | 105
71 | 46
72 |
73 |
74 |
75 |
76 | Noto Sans
77 | 14
78 | 75
79 | false
80 | true
81 |
82 |
83 |
84 | Help_Cell_Info
85 |
86 |
87 | font: bold 14pt "Noto Sans";
88 | color: rgb(0, 0, 0);
89 | text-align: center;
90 |
91 |
92 | Qt::ImhNone
93 |
94 |
95 |
96 |
97 |
98 | Qt::AlignCenter
99 |
100 |
101 | true
102 |
103 |
104 |
105 |
106 |
107 | 5
108 | 85
109 | 99
110 | 13
111 |
112 |
113 |
114 | Help_Cell_Info
115 |
116 |
117 | color: rgb(0, 85, 255);
118 | background-color: rgb(190, 190, 190);
119 |
120 |
121 | 97
122 |
123 |
124 | 0
125 |
126 |
127 | false
128 |
129 |
130 |
131 |
132 |
133 | 70
134 | 49
135 | 33
136 | 33
137 |
138 |
139 |
140 |
141 | Noto Sans
142 | 10
143 | 50
144 | true
145 | false
146 |
147 |
148 |
149 | Qt::NoFocus
150 |
151 |
152 | Help_Cell_Info
153 |
154 |
155 | font: italic 10pt "Noto Sans";
156 | color: rgb(0, 0, 0);
157 | background-color: rgb(190, 190, 190);
158 | text-align: center;
159 |
160 |
161 |
162 |
163 |
164 |
165 | :/icons/icons/clip-add.png:/icons/icons/clip-add.png
166 |
167 |
168 |
169 | 35
170 | 35
171 |
172 |
173 |
174 | false
175 |
176 |
177 | false
178 |
179 |
180 | false
181 |
182 |
183 |
184 |
185 |
186 | 5
187 | 49
188 | 33
189 | 33
190 |
191 |
192 |
193 |
194 | Noto Sans
195 | 10
196 | 50
197 | true
198 | false
199 |
200 |
201 |
202 | Qt::NoFocus
203 |
204 |
205 | Help_Cell_Info
206 |
207 |
208 | font: italic 10pt "Noto Sans";
209 | background-color: rgb(190, 190, 190);
210 | color: rgb(0, 0, 0);
211 | text-align: center;
212 |
213 |
214 |
215 |
216 |
217 |
218 | :/icons/icons/clip-start-stop.png:/icons/icons/clip-start-stop.png
219 |
220 |
221 |
222 | 27
223 | 27
224 |
225 |
226 |
227 |
228 |
229 |
230 | 0
231 | 49
232 | 111
233 | 33
234 |
235 |
236 |
237 | Help_Cell_Info
238 |
239 |
240 | font: bold 12pt "Noto Sans";
241 |
242 |
243 | 5
244 |
245 |
246 | Qt::PlainText
247 |
248 |
249 | false
250 |
251 |
252 | Qt::AlignCenter
253 |
254 |
255 | true
256 |
257 |
258 | 0
259 |
260 |
261 | 0
262 |
263 |
264 | Qt::NoTextInteraction
265 |
266 |
267 | labelVolume
268 | clip_name
269 | clip_position
270 | edit
271 | start_stop
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
--------------------------------------------------------------------------------
/superboucle/device.py:
--------------------------------------------------------------------------------
1 | from superboucle.clip import Clip
2 | from PyQt5.QtCore import QSettings
3 | from superboucle.preferences import Preferences
4 | import settings
5 |
6 | class DeviceOutput:
7 | def __init__(self, method, name=None):
8 | self.method = method
9 | self.name = name or method.__name__
10 | self.__doc__ = method.__doc__
11 |
12 | def get_mapping(self, inst):
13 | return inst.mapping
14 |
15 | def __get__(self, inst, cls=None):
16 | mapping = self.get_mapping(inst)
17 | return mapping.setdefault(self.name, self.method(inst))
18 |
19 | def __set__(self, inst, value):
20 | mapping = self.get_mapping(inst)
21 | mapping[self.name] = value
22 |
23 | def __delete__(self, inst):
24 | mapping = self.get_mapping(inst)
25 | del mapping[self.name]
26 |
27 |
28 | class DeviceInput(DeviceOutput):
29 | pass
30 |
31 |
32 | class Device:
33 |
34 | NOTEON = 0x9
35 |
36 | def __init__(self, mapping={}):
37 | self.updateMapping(mapping)
38 |
39 | def updateMapping(self, new_mapping):
40 | self.note_to_coord = {}
41 | for key in new_mapping.keys():
42 | new_mapping[key] = self._formatMapping(new_mapping[key])
43 | self.mapping = new_mapping
44 | for y in range(len(self.start_stop)):
45 | line = self.start_stop[y]
46 | for x in range(len(line)):
47 | self.note_to_coord[line[x]] = (x, y)
48 |
49 | def _formatMapping(self, value):
50 | if type(value) is not list or not len(value):
51 | return value
52 | elif type(value[0]) is int:
53 | return tuple(value)
54 | elif type(value[0]) is list:
55 | return [self._formatMapping(v) for v in value]
56 | else:
57 | return value
58 |
59 | def generateNote(self, x, y, state):
60 | (msg_type, channel, pitch, velocity) = self.start_stop[y][x]
61 | return (0x90 + channel, pitch, self.getColor(state)) # note on : 0x90
62 |
63 | def getColor(self, state):
64 |
65 | if state is None:
66 | return self.black_vel
67 |
68 | elif state == Clip.STOP:
69 | if settings.rec_color == settings.COLOR_RED:
70 | return self.amber_vel
71 | else:
72 | return self.red_vel
73 |
74 | elif state == Clip.STARTING:
75 | return self.blink_green_vel
76 |
77 | elif state == Clip.START:
78 | return self.green_vel
79 |
80 | elif state == Clip.STOPPING:
81 | if settings.rec_color == settings.COLOR_RED:
82 | return self.blink_amber_vel
83 | else:
84 | return self.blink_red_vel
85 |
86 | elif state == Clip.PREPARE_RECORD:
87 | if settings.rec_color == settings.COLOR_RED:
88 | return self.blink_red_vel
89 | else:
90 | return self.blink_amber_vel
91 |
92 | elif state == Clip.RECORDING:
93 | if settings.rec_color == settings.COLOR_RED:
94 | return self.red_vel
95 | else:
96 | return self.amber_vel
97 |
98 | else:
99 | raise Exception("Invalid state")
100 |
101 | def setAllCellsColor(self, queue_out, color):
102 | # clips
103 | for line in self.start_stop:
104 | for data in line:
105 | (m, channel, pitch, velocity) = data
106 | note = ((self.NOTEON << 4) + channel, pitch, color)
107 | queue_out.put(note)
108 |
109 | # mute buttons
110 | for btn_key in self.mute_buttons:
111 | (msg_type, channel, pitch, velocity) = btn_key
112 | note = ((self.NOTEON << 4) + channel, pitch, color)
113 | queue_out.put(note)
114 |
115 | # scenes
116 | for scene_key in self.scene_buttons:
117 | (msg_type, channel, pitch, velocity) = scene_key
118 | note = ((self.NOTEON << 4) + channel, pitch, color)
119 | queue_out.put(note)
120 |
121 | # Shift
122 | if self.shift_btn:
123 | (msg_type, channel, pitch, velocity) = self.shift_btn
124 | note = ((self.NOTEON << 4) + channel, pitch, color)
125 | queue_out.put(note)
126 |
127 | # Unlink mixer stripes
128 | if self.unlink_stripes_btn:
129 | (msg_type, channel, pitch, velocity) = self.unlink_stripes_btn
130 | note = ((self.NOTEON << 4) + channel, pitch, color)
131 | queue_out.put(note)
132 |
133 | # custom reset
134 | if self.custom_reset_btn:
135 | (msg_type, channel, pitch, velocity) = self.custom_reset_btn
136 | note = ((self.NOTEON << 4) + channel, pitch, color)
137 | queue_out.put(note)
138 |
139 |
140 | #transport
141 | if self.play_btn:
142 | (msg_type, channel, pitch, velocity) = self.play_btn
143 | note = ((self.NOTEON << 4) + channel, pitch, color)
144 | queue_out.put(note)
145 |
146 | if self.pause_btn:
147 | (msg_type, channel, pitch, velocity) = self.pause_btn
148 | note = ((self.NOTEON << 4) + channel, pitch, color)
149 | queue_out.put(note)
150 |
151 | if self.rewind_btn:
152 | (msg_type, channel, pitch, velocity) = self.rewind_btn
153 | note = ((self.NOTEON << 4) + channel, pitch, color)
154 | queue_out.put(note)
155 |
156 | if self.stop_btn:
157 | (msg_type, channel, pitch, velocity) = self.stop_btn
158 | note = ((self.NOTEON << 4) + channel, pitch, color)
159 | queue_out.put(note)
160 |
161 | if self.goto_btn:
162 | (msg_type, channel, pitch, velocity) = self.goto_btn
163 | note = ((self.NOTEON << 4) + channel, pitch, color)
164 | queue_out.put(note)
165 |
166 | if self.record_btn:
167 | (msg_type, channel, pitch, velocity) = self.record_btn
168 | note = ((self.NOTEON << 4) + channel, pitch, color)
169 | queue_out.put(note)
170 |
171 |
172 | def getXY(self, note):
173 | return self.note_to_coord[note]
174 |
175 | @property
176 | def name(self):
177 | return self.mapping.get('name', '')
178 |
179 | @name.setter
180 | def name(self, name):
181 | self.mapping['name'] = name
182 |
183 | @property
184 | def description(self):
185 | return self.mapping.get('description', '')
186 |
187 | @description.setter
188 | def description(self, description):
189 | self.mapping['description'] = description
190 |
191 | @DeviceInput
192 | def ctrls(self): # this is for the mixer strip volumes
193 | return []
194 |
195 | @DeviceInput
196 | def send1ctrls(self): # this is for the mixer strip send1
197 | return []
198 |
199 | @DeviceInput
200 | def send2ctrls(self): # this is for the mixer strip send2
201 | return []
202 |
203 |
204 | @DeviceInput
205 | def start_stop(self):
206 | return []
207 |
208 | @DeviceInput
209 | def init_command(self):
210 | return []
211 |
212 | @DeviceInput
213 | def mute_buttons(self):
214 | return []
215 |
216 | @DeviceInput
217 | def scene_buttons(self):
218 | return []
219 |
220 | @DeviceInput
221 | def song_volume_ctrl(self):
222 | return False
223 |
224 | @DeviceInput
225 | def play_btn(self):
226 | return False
227 |
228 | @DeviceInput
229 | def pause_btn(self):
230 | return False
231 |
232 | @DeviceInput
233 | def rewind_btn(self):
234 | return False
235 |
236 | @DeviceInput
237 | def goto_btn(self):
238 | return False
239 |
240 | @DeviceInput
241 | def stop_btn(self):
242 | return False
243 |
244 | @DeviceInput
245 | def shift_btn(self):
246 | return False
247 |
248 | @DeviceInput
249 | def unlink_stripes_btn(self):
250 | return False
251 |
252 | @DeviceInput
253 | def custom_reset_btn(self):
254 | return False
255 |
256 | @DeviceInput
257 | def record_btn(self):
258 | return False
259 |
260 | @DeviceOutput
261 | def black_vel(self):
262 | return 0
263 |
264 | @DeviceOutput
265 | def green_vel(self):
266 | return 0
267 |
268 | @DeviceOutput
269 | def blink_green_vel(self):
270 | return 0
271 |
272 | @DeviceOutput
273 | def red_vel(self):
274 | return 0
275 |
276 | @DeviceOutput
277 | def blink_red_vel(self):
278 | return 0
279 |
280 | @DeviceOutput
281 | def amber_vel(self):
282 | return 0
283 |
284 | @DeviceOutput
285 | def blink_amber_vel(self):
286 | return 0
287 |
--------------------------------------------------------------------------------
/superboucle/device_manager.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtWidgets import QDialog, QInputDialog, QLineEdit
2 | from superboucle.device_manager_ui import Ui_Dialog
3 | from superboucle.learn import LearnDialog
4 | from superboucle.device import Device
5 | from superboucle.clip import verify_ext
6 | import json
7 | import common
8 | import copy
9 | from PyQt5.QtWidgets import QMessageBox
10 |
11 | class ManageDialog(QDialog, Ui_Dialog):
12 | def __init__(self, parent):
13 | super(ManageDialog, self).__init__(parent)
14 | self.gui = parent
15 | self.setupUi(self)
16 |
17 | self.updateDeviceList()
18 |
19 | self.editButton.clicked.connect(self.onEdit)
20 | self.deleteButton.clicked.connect(self.onDelete)
21 | self.importButton.clicked.connect(self.onImport)
22 | self.exportButton.clicked.connect(self.onExport)
23 | self.cloneButton.clicked.connect(self.onClone)
24 | self.finished.connect(self.onFinished)
25 |
26 | self.setModal(True)
27 | self.show()
28 |
29 |
30 | def onEdit(self):
31 | if self.gui._jack_client.transport_state == 1: # ROLLING
32 |
33 | response = QMessageBox.question(self, "Enter device configuration?", "The song execution will be stopped")
34 | if response == QMessageBox.No:
35 | return
36 |
37 | self.gui._jack_client.transport_stop()
38 | self.gui._jack_client.transport_locate(0)
39 |
40 | if self.list.currentRow() != -1:
41 | device = self.gui.devices[self.list.currentRow() + 1]
42 | self.gui.learn_device = LearnDialog(self.gui,
43 | self.updateDevice,
44 | device)
45 | self.gui.is_learn_device_mode = True
46 | self.gui.update()
47 |
48 | def onClone(self):
49 | if self.list.currentRow() != -1:
50 | device = self.gui.devices[self.list.currentRow() + 1]
51 |
52 | currentName = str(self.list.currentItem().text())
53 | newName, okPressed = QInputDialog.getText(self, "Clone MIDI configuration", "Enter new MIDI configuration name:", QLineEdit.Normal, currentName)
54 |
55 | if currentName.strip() == newName.strip():
56 | print("Device won't be cloned since names are equals")
57 | return
58 |
59 | newDevice = copy.deepcopy(device)
60 | newDevice.name = newName
61 | newDevice.description = device.description + "\n\n(Cloned from " + currentName +")"
62 |
63 | self.gui.addDevice(newDevice)
64 | self.updateDeviceList()
65 |
66 |
67 | def onDelete(self):
68 | if self.list.currentRow() != -1:
69 | response = QMessageBox.question(self, "Delete MIDI configuration?", "Are you sure you want to delete this MIDI configuration?")
70 | if response == QMessageBox.No:
71 | return
72 |
73 | device = self.gui.devices[self.list.currentRow() + 1]
74 | self.gui.devices.remove(device)
75 | self.list.takeItem(self.list.currentRow())
76 |
77 |
78 |
79 | def onImport(self):
80 | file_name, a = self.gui.getOpenFileName('Import MIDI configuration',
81 | common.DEVICE_MAPPING_TYPE,
82 | self)
83 | with open(file_name, 'r') as f:
84 | read_data = f.read()
85 | mapping = json.loads(read_data)
86 | self.list.addItem(mapping['name'])
87 | self.gui.devices.append(Device(mapping))
88 |
89 |
90 | def onExport(self):
91 | device = self.gui.devices[self.list.currentRow() + 1]
92 | file_name, a = self.gui.getSaveFileName('Export MIDI configuration',
93 | common.DEVICE_MAPPING_TYPE,
94 | self)
95 | if file_name:
96 | file_name = verify_ext(file_name, common.DEVICE_MAPPING_EXT)
97 | with open(file_name, 'w') as f:
98 | f.write(json.dumps(device.mapping))
99 |
100 |
101 | def onFinished(self):
102 | self.gui.updateDevices()
103 |
104 |
105 | def updateDevice(self, device):
106 | self.updateDeviceList()
107 |
108 | self.gui.is_learn_device_mode = False
109 | self.gui.redraw()
110 |
111 |
112 | def updateDeviceList(self):
113 | self.list.clear()
114 | for device in self.gui.devices[1:]:
115 | self.list.addItem(device.name)
116 |
117 |
118 |
--------------------------------------------------------------------------------
/superboucle/device_manager_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file '/home/manu/Sviluppo/SpinTool/superboucle/device_manager_ui.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.14.1
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 |
10 | from PyQt5 import QtCore, QtGui, QtWidgets
11 |
12 |
13 | class Ui_Dialog(object):
14 | def setupUi(self, Dialog):
15 | Dialog.setObjectName("Dialog")
16 | Dialog.resize(491, 297)
17 | self.gridLayout = QtWidgets.QGridLayout(Dialog)
18 | self.gridLayout.setObjectName("gridLayout")
19 | self.list = QtWidgets.QListWidget(Dialog)
20 | self.list.setObjectName("list")
21 | self.gridLayout.addWidget(self.list, 0, 0, 1, 1)
22 | self.verticalLayout = QtWidgets.QVBoxLayout()
23 | self.verticalLayout.setObjectName("verticalLayout")
24 | self.editButton = QtWidgets.QPushButton(Dialog)
25 | self.editButton.setObjectName("editButton")
26 | self.verticalLayout.addWidget(self.editButton)
27 | self.deleteButton = QtWidgets.QPushButton(Dialog)
28 | self.deleteButton.setObjectName("deleteButton")
29 | self.verticalLayout.addWidget(self.deleteButton)
30 | self.cloneButton = QtWidgets.QPushButton(Dialog)
31 | self.cloneButton.setObjectName("cloneButton")
32 | self.verticalLayout.addWidget(self.cloneButton)
33 | spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
34 | self.verticalLayout.addItem(spacerItem)
35 | self.importButton = QtWidgets.QPushButton(Dialog)
36 | self.importButton.setObjectName("importButton")
37 | self.verticalLayout.addWidget(self.importButton)
38 | self.exportButton = QtWidgets.QPushButton(Dialog)
39 | self.exportButton.setObjectName("exportButton")
40 | self.verticalLayout.addWidget(self.exportButton)
41 | self.gridLayout.addLayout(self.verticalLayout, 0, 1, 1, 1)
42 |
43 | self.retranslateUi(Dialog)
44 | QtCore.QMetaObject.connectSlotsByName(Dialog)
45 |
46 | def retranslateUi(self, Dialog):
47 | _translate = QtCore.QCoreApplication.translate
48 | Dialog.setWindowTitle(_translate("Dialog", "Manage MIDI configurations"))
49 | self.editButton.setText(_translate("Dialog", "Edit"))
50 | self.deleteButton.setText(_translate("Dialog", "Delete"))
51 | self.cloneButton.setText(_translate("Dialog", "Clone"))
52 | self.importButton.setText(_translate("Dialog", "Import"))
53 | self.exportButton.setText(_translate("Dialog", "Export"))
54 |
--------------------------------------------------------------------------------
/superboucle/device_manager_ui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 491
10 | 297
11 |
12 |
13 |
14 | Manage MIDI configurations
15 |
16 |
17 | -
18 |
19 |
20 | -
21 |
22 |
-
23 |
24 |
25 | Edit
26 |
27 |
28 |
29 | -
30 |
31 |
32 | Delete
33 |
34 |
35 |
36 | -
37 |
38 |
39 | Clone
40 |
41 |
42 |
43 | -
44 |
45 |
46 | Qt::Vertical
47 |
48 |
49 |
50 | 20
51 | 40
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 | Import
60 |
61 |
62 |
63 | -
64 |
65 |
66 | Export
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/superboucle/edit_clips.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtWidgets import QDialog, QFileDialog, QMessageBox
2 | from superboucle.edit_clips_ui import Ui_Dialog
3 | from PyQt5 import QtGui
4 | import common
5 | import settings
6 |
7 | EDIT_ALL_SELECTED_CLIPS_MESSAGE = "Check the details you want to massively change, then fill the values and press Ok"
8 | EDIT_BY_OUTPUT_PORT_MESSAGE = "Select an output port, then check the details and fill the values you want to massively change for all the clips belonging to that port"
9 | EDIT_BY_MUTE_GROUP_MESSAGE = "Select a solo clip group, then check the details and fill the values you want to massively change for all the clips belonging to that solo clip group"
10 |
11 | EDIT_ALL_SELECTED_LABEL_STYLE = ('font: bold 11pt "Noto Sans";background-color: rgb(255, 255, 0);')
12 | EDIT_OTHER_LABEL_STYLE = ('font: bold 10pt "Noto Sans";')
13 |
14 | class EditClipsDialog(QDialog, Ui_Dialog):
15 | def __init__(self, parent, edit_mode = 0, selected_clips = None):
16 | super(EditClipsDialog, self).__init__(parent)
17 |
18 | self.gui = parent
19 | self.setupUi(self)
20 | self.initializeUI()
21 |
22 | self.proceed = False
23 | self.volume = 0
24 | self.volume_change_mode = common.SET_VOLUME
25 | self.accepted.connect(self.onOk)
26 |
27 | self.checkBoxEnableOutPortsChanges.clicked.connect(self.onEnablePortsChangeClicked)
28 | self.checkBoxEnableMutGroupChanges.clicked.connect(self.onEnableMuteGroupsChangeClicked)
29 | self.checkBoxEnableVolumeChanges.clicked.connect(self.onEnableVolumeChangeClicked)
30 |
31 | self.buttonCopyPortFromCurrentClip.clicked.connect(self.onButtonCopyPortClicked)
32 | self.buttonCopyMuteGroupFromCurrentClip.clicked.connect(self.onButtonCopyMuteGroupClicked)
33 | self.buttonCopyVolumeFromCurrentClip.clicked.connect(self.onButtonCopyVolumeClicked)
34 |
35 | self.radioButtonSetVolume.toggled.connect(self.updateVolumeRadioButtons)
36 | self.radioButtonIncreaseVolume.toggled.connect(self.updateVolumeRadioButtons)
37 | self.radioButtonDecreaseVolume.toggled.connect(self.updateVolumeRadioButtons)
38 |
39 | self.comboBoxOutputPorts.addItems(sorted(settings.output_ports.keys()))
40 |
41 | self.edit_mode = edit_mode
42 | if self.edit_mode == common.CLIPS_EDIT_MODE_ALL_SELECTED:
43 |
44 | self.checkBoxEnableOutPortsChanges.setVisible(True)
45 | self.checkBoxEnableMutGroupChanges.setVisible(True)
46 | self.checkBoxEnableVolumeChanges.setVisible(True)
47 |
48 | # I left to GUI the control that selected_clips contains some clips
49 | # so I won't check again here.
50 | text = "You have selected " + str(selected_clips.__len__()) + " clips. "
51 | self.labelMessage.setText(text + EDIT_ALL_SELECTED_CLIPS_MESSAGE)
52 | self.labelMessage.setStyleSheet(EDIT_ALL_SELECTED_LABEL_STYLE)
53 |
54 | elif edit_mode == common.CLIPS_EDIT_MODE_BY_MUTE_GROUP:
55 |
56 | self.checkBoxEnableOutPortsChanges.setVisible(True)
57 | self.checkBoxEnableMutGroupChanges.setVisible(False)
58 | self.checkBoxEnableVolumeChanges.setVisible(True)
59 |
60 | self.labelMessage.setText(EDIT_BY_MUTE_GROUP_MESSAGE)
61 | self.labelMessage.setStyleSheet(EDIT_OTHER_LABEL_STYLE)
62 |
63 | self.groupBoxMuteGroup.setEnabled(True)
64 | self.checkBoxUnselectClips.setVisible(False)
65 |
66 | self.framePorts.setGeometry(230, 70, 291, 111)
67 | self.frameMuteGroups.setGeometry(10, 70, 211, 111)
68 |
69 | elif edit_mode == common.CLIPS_EDIT_MODE_BY_OUTPUT_PORT:
70 |
71 | self.checkBoxEnableOutPortsChanges.setVisible(False)
72 | self.checkBoxEnableMutGroupChanges.setVisible(True)
73 | self.checkBoxEnableVolumeChanges.setVisible(True)
74 |
75 | self.labelMessage.setText(EDIT_BY_OUTPUT_PORT_MESSAGE)
76 | self.labelMessage.setStyleSheet(EDIT_OTHER_LABEL_STYLE)
77 |
78 | self.groupBoxPorts.setEnabled(True)
79 | self.checkBoxUnselectClips.setVisible(False)
80 |
81 | self.setFixedSize(self.size())
82 | self.setModal(True)
83 | self.show()
84 |
85 | def initializeUI(self):
86 | self.groupBoxPorts.setEnabled(False)
87 | self.groupBoxMuteGroup.setEnabled(False)
88 | self.groupBoxVolume.setEnabled(False)
89 | self.checkBoxEnableMutGroupChanges.setChecked(False)
90 | self.checkBoxEnableOutPortsChanges.setChecked(False)
91 | self.checkBoxEnableVolumeChanges.setChecked(False)
92 | self.radioButtonSetVolume.setChecked(True)
93 |
94 | def showNoClipMessage(self):
95 | message = QMessageBox(self)
96 | message.setWindowTitle("Can't read clip details")
97 | message.setText("No clip is currently selected in Edit details in SpinTool window")
98 | message.show()
99 |
100 | def onEnablePortsChangeClicked(self):
101 | self.groupBoxPorts.setEnabled(self.checkBoxEnableOutPortsChanges.isChecked())
102 |
103 | def onEnableMuteGroupsChangeClicked(self):
104 | self.groupBoxMuteGroup.setEnabled(self.checkBoxEnableMutGroupChanges.isChecked())
105 |
106 | def onEnableVolumeChangeClicked(self):
107 | self.groupBoxVolume.setEnabled(self.checkBoxEnableVolumeChanges.isChecked())
108 |
109 | def onButtonCopyPortClicked(self):
110 | if self.gui.last_clip:
111 | self.comboBoxOutputPorts.setCurrentText(self.gui.last_clip.output)
112 | else:
113 | self.showNoClipMessage()
114 |
115 | def onButtonCopyMuteGroupClicked(self):
116 | if self.gui.last_clip:
117 | self.spinBoxMuteGroups.setValue(self.gui.last_clip.mute_group)
118 | else:
119 | self.showNoClipMessage()
120 |
121 | def onButtonCopyVolumeClicked(self):
122 | if self.gui.last_clip:
123 | self.volume = self.gui.last_clip.volume
124 | self.spinBoxVolumeAmount.setValue(common.toDigitalVolumeValue(self.gui.last_clip.volume))
125 | else:
126 | self.showNoClipMessage()
127 |
128 | def updateVolumeRadioButtons(self):
129 | self.buttonCopyVolumeFromCurrentClip.setVisible(self.radioButtonSetVolume.isChecked())
130 |
131 | if self.radioButtonSetVolume.isChecked() == True:
132 | self.volume_change_mode = common.SET_VOLUME
133 |
134 | elif self.radioButtonIncreaseVolume.isChecked() == True:
135 | self.volume_change_mode = common.INCREASE_VOLUME
136 |
137 | elif self.radioButtonDecreaseVolume.isChecked() == True:
138 | self.volume_change_mode = common.DECREASE_VOLUME
139 |
140 | def getVolumeAmount(self):
141 | return self.volume, self.volume_change_mode
142 |
143 | def getOutputPort(self):
144 | return self.comboBoxOutputPorts.currentText()
145 |
146 | def getMuteGroup(self):
147 | return self.spinBoxMuteGroups.value()
148 |
149 | def getEditVolume(self):
150 | return self.checkBoxEnableVolumeChanges.isChecked()
151 |
152 | def getEditMuteGroup(self):
153 | return self.checkBoxEnableMutGroupChanges.isChecked()
154 |
155 | def getEditOutputPort(self):
156 | return self.checkBoxEnableOutPortsChanges.isChecked()
157 |
158 | def getUnselectClips(self):
159 | return self.checkBoxUnselectClips.isChecked()
160 |
161 | def onOk(self):
162 | self.volume = self.spinBoxVolumeAmount.value()
163 | self.proceed = True
164 |
165 | def onFinished(self):
166 | pass
--------------------------------------------------------------------------------
/superboucle/export_samples.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtWidgets import QDialog, QFileDialog
2 | from superboucle.export_samples_ui import Ui_Dialog
3 |
4 | class ExportAllSamplesDialog(QDialog, Ui_Dialog):
5 | def __init__(self, parent):
6 | super(ExportAllSamplesDialog, self).__init__(parent)
7 |
8 | self.gui = parent
9 | self.setupUi(self)
10 | self.accepted.connect(self.onOk)
11 | self.btnPath.clicked.connect(self.onPath)
12 | self.proceed = False
13 |
14 | self.setFixedSize(self.size())
15 | self.setModal(True)
16 | self.show()
17 |
18 | def setPath(self, path):
19 | self.labelPath.setText(path)
20 |
21 | def getPath(self):
22 | return self.labelPath.text()
23 |
24 | def getNormalize(self):
25 | return self.cBoxNormalize.isChecked()
26 |
27 | def getX(self):
28 | return self.lineX.text()
29 |
30 | def getY(self):
31 | return self.lineY.text()
32 |
33 | def onPath(self):
34 | self.labelPath.setText(QFileDialog.getExistingDirectory(self, 'Select export directory'))
35 |
36 | def onOk(self):
37 | self.proceed = True
38 |
39 | def onFinished(self):
40 | pass
--------------------------------------------------------------------------------
/superboucle/export_samples_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file '/home/manu/Sviluppo/SpinTool/superboucle/export_samples_ui.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.14.1
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 |
10 | from PyQt5 import QtCore, QtGui, QtWidgets
11 |
12 |
13 | class Ui_Dialog(object):
14 | def setupUi(self, Dialog):
15 | Dialog.setObjectName("Dialog")
16 | Dialog.setWindowModality(QtCore.Qt.WindowModal)
17 | Dialog.resize(680, 338)
18 | Dialog.setStyleSheet("background-color: rgb(242, 242, 242);")
19 | self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
20 | self.buttonBox.setGeometry(QtCore.QRect(10, 300, 661, 31))
21 | self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
22 | self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
23 | self.buttonBox.setObjectName("buttonBox")
24 | self.cBoxNormalize = QtWidgets.QCheckBox(Dialog)
25 | self.cBoxNormalize.setGeometry(QtCore.QRect(10, 110, 281, 31))
26 | font = QtGui.QFont()
27 | font.setFamily("Noto Sans")
28 | font.setPointSize(10)
29 | font.setBold(False)
30 | font.setItalic(False)
31 | font.setWeight(50)
32 | self.cBoxNormalize.setFont(font)
33 | self.cBoxNormalize.setStyleSheet("color: rgb(0, 0, 0);\n"
34 | "background-color: rgb(242, 242, 242);\n"
35 | "font: 10pt \"Noto Sans\";")
36 | self.cBoxNormalize.setObjectName("cBoxNormalize")
37 | self.labelChoosePath = QtWidgets.QLabel(Dialog)
38 | self.labelChoosePath.setGeometry(QtCore.QRect(10, 10, 381, 41))
39 | self.labelChoosePath.setStyleSheet("color: rgb(0, 0, 0);\n"
40 | "background-color: rgb(242, 242, 242);\n"
41 | "font: 10pt \"Noto Sans\";")
42 | self.labelChoosePath.setObjectName("labelChoosePath")
43 | self.btnPath = QtWidgets.QPushButton(Dialog)
44 | self.btnPath.setGeometry(QtCore.QRect(10, 50, 51, 41))
45 | self.btnPath.setStyleSheet("color: rgb(0, 0, 0);\n"
46 | "background-color: rgb(242, 242, 242);\n"
47 | "font: 10pt \"Noto Sans\";")
48 | self.btnPath.setText("")
49 | icon = QtGui.QIcon()
50 | icon.addPixmap(QtGui.QPixmap(":/icons/icons/folder.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
51 | self.btnPath.setIcon(icon)
52 | self.btnPath.setIconSize(QtCore.QSize(27, 27))
53 | self.btnPath.setObjectName("btnPath")
54 | self.labelPath = QtWidgets.QLabel(Dialog)
55 | self.labelPath.setGeometry(QtCore.QRect(70, 50, 591, 41))
56 | self.labelPath.setStyleSheet("color: rgb(0, 0, 0);\n"
57 | "background-color: rgb(242, 242, 242);\n"
58 | "font: 10pt \"Noto Sans\";")
59 | self.labelPath.setObjectName("labelPath")
60 | self.labelX = QtWidgets.QLabel(Dialog)
61 | self.labelX.setGeometry(QtCore.QRect(20, 180, 101, 18))
62 | self.labelX.setStyleSheet("color: rgb(0, 0, 0);\n"
63 | "background-color: rgb(242, 242, 242);\n"
64 | "font: 10pt \"Noto Sans\";")
65 | self.labelX.setObjectName("labelX")
66 | self.lineX = QtWidgets.QLineEdit(Dialog)
67 | self.lineX.setGeometry(QtCore.QRect(130, 170, 101, 41))
68 | self.lineX.setStyleSheet("color: rgb(0, 0, 0);\n"
69 | "background-color: rgb(242, 242, 242);\n"
70 | "font: 10pt \"Noto Sans\";")
71 | self.lineX.setAlignment(QtCore.Qt.AlignCenter)
72 | self.lineX.setObjectName("lineX")
73 | self.labelY = QtWidgets.QLabel(Dialog)
74 | self.labelY.setGeometry(QtCore.QRect(20, 240, 101, 18))
75 | self.labelY.setStyleSheet("color: rgb(0, 0, 0);\n"
76 | "background-color: rgb(242, 242, 242);\n"
77 | "font: 10pt \"Noto Sans\";")
78 | self.labelY.setObjectName("labelY")
79 | self.lineY = QtWidgets.QLineEdit(Dialog)
80 | self.lineY.setGeometry(QtCore.QRect(130, 230, 101, 41))
81 | self.lineY.setStyleSheet("color: rgb(0, 0, 0);\n"
82 | "background-color: rgb(242, 242, 242);\n"
83 | "font: 10pt \"Noto Sans\";")
84 | self.lineY.setAlignment(QtCore.Qt.AlignCenter)
85 | self.lineY.setObjectName("lineY")
86 |
87 | self.retranslateUi(Dialog)
88 | self.buttonBox.accepted.connect(Dialog.accept)
89 | self.buttonBox.rejected.connect(Dialog.reject)
90 | QtCore.QMetaObject.connectSlotsByName(Dialog)
91 |
92 | def retranslateUi(self, Dialog):
93 | _translate = QtCore.QCoreApplication.translate
94 | Dialog.setWindowTitle(_translate("Dialog", "Export all samples"))
95 | self.cBoxNormalize.setText(_translate("Dialog", "Normalize samples when exporting"))
96 | self.labelChoosePath.setText(_translate("Dialog", "Export all clip samples to:"))
97 | self.labelPath.setText(_translate("Dialog", "(select a directory for exporting)"))
98 | self.labelX.setText(_translate("Dialog", "Column prefix:"))
99 | self.lineX.setText(_translate("Dialog", "X"))
100 | self.lineX.setPlaceholderText(_translate("Dialog", "X"))
101 | self.labelY.setText(_translate("Dialog", "Row prefix:"))
102 | self.lineY.setText(_translate("Dialog", "Y"))
103 | self.lineY.setPlaceholderText(_translate("Dialog", "Y"))
104 | import gui_rc
105 |
--------------------------------------------------------------------------------
/superboucle/export_samples_ui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 | Qt::WindowModal
7 |
8 |
9 |
10 | 0
11 | 0
12 | 680
13 | 338
14 |
15 |
16 |
17 | Export all samples
18 |
19 |
20 | background-color: rgb(242, 242, 242);
21 |
22 |
23 |
24 |
25 | 10
26 | 300
27 | 661
28 | 31
29 |
30 |
31 |
32 | Qt::Horizontal
33 |
34 |
35 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
36 |
37 |
38 |
39 |
40 |
41 | 10
42 | 110
43 | 281
44 | 31
45 |
46 |
47 |
48 |
49 | Noto Sans
50 | 10
51 | 50
52 | false
53 | false
54 |
55 |
56 |
57 | color: rgb(0, 0, 0);
58 | background-color: rgb(242, 242, 242);
59 | font: 10pt "Noto Sans";
60 |
61 |
62 | Normalize samples when exporting
63 |
64 |
65 |
66 |
67 |
68 | 10
69 | 10
70 | 381
71 | 41
72 |
73 |
74 |
75 | color: rgb(0, 0, 0);
76 | background-color: rgb(242, 242, 242);
77 | font: 10pt "Noto Sans";
78 |
79 |
80 | Export all clip samples to:
81 |
82 |
83 |
84 |
85 |
86 | 10
87 | 50
88 | 51
89 | 41
90 |
91 |
92 |
93 | color: rgb(0, 0, 0);
94 | background-color: rgb(242, 242, 242);
95 | font: 10pt "Noto Sans";
96 |
97 |
98 |
99 |
100 |
101 |
102 | :/icons/icons/folder.png:/icons/icons/folder.png
103 |
104 |
105 |
106 | 27
107 | 27
108 |
109 |
110 |
111 |
112 |
113 |
114 | 70
115 | 50
116 | 591
117 | 41
118 |
119 |
120 |
121 | color: rgb(0, 0, 0);
122 | background-color: rgb(242, 242, 242);
123 | font: 10pt "Noto Sans";
124 |
125 |
126 | (select a directory for exporting)
127 |
128 |
129 |
130 |
131 |
132 | 20
133 | 180
134 | 101
135 | 18
136 |
137 |
138 |
139 | color: rgb(0, 0, 0);
140 | background-color: rgb(242, 242, 242);
141 | font: 10pt "Noto Sans";
142 |
143 |
144 | Column prefix:
145 |
146 |
147 |
148 |
149 |
150 | 130
151 | 170
152 | 101
153 | 41
154 |
155 |
156 |
157 | color: rgb(0, 0, 0);
158 | background-color: rgb(242, 242, 242);
159 | font: 10pt "Noto Sans";
160 |
161 |
162 | X
163 |
164 |
165 | Qt::AlignCenter
166 |
167 |
168 | X
169 |
170 |
171 |
172 |
173 |
174 | 20
175 | 240
176 | 101
177 | 18
178 |
179 |
180 |
181 | color: rgb(0, 0, 0);
182 | background-color: rgb(242, 242, 242);
183 | font: 10pt "Noto Sans";
184 |
185 |
186 | Row prefix:
187 |
188 |
189 |
190 |
191 |
192 | 130
193 | 230
194 | 101
195 | 41
196 |
197 |
198 |
199 | color: rgb(0, 0, 0);
200 | background-color: rgb(242, 242, 242);
201 | font: 10pt "Noto Sans";
202 |
203 |
204 | Y
205 |
206 |
207 | Qt::AlignCenter
208 |
209 |
210 | Y
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 | buttonBox
220 | accepted()
221 | Dialog
222 | accept()
223 |
224 |
225 | 248
226 | 254
227 |
228 |
229 | 157
230 | 274
231 |
232 |
233 |
234 |
235 | buttonBox
236 | rejected()
237 | Dialog
238 | reject()
239 |
240 |
241 | 316
242 | 260
243 |
244 |
245 | 286
246 | 274
247 |
248 |
249 |
250 |
251 |
252 |
--------------------------------------------------------------------------------
/superboucle/gui.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | icons/clip-behaviour.png
4 | icons/clip-functions.png
5 | icons/clip-groups.png
6 | icons/clip-measures.png
7 | icons/edit-delete.png
8 | icons/warning.png
9 | icons/Superdirt_Logo_80.png
10 | icons/sliders.png
11 | icons/stop.png
12 | icons/shift.png
13 | icons/file.png
14 | icons/fader.png
15 | icons/copy.png
16 | icons/clip-edit.png
17 | icons/clip-start-stop.png
18 | icons/clip-add.png
19 | icons/logo_sb.png
20 | icons/MeltinPop_Logo_100.png
21 | icons/ST_Logo_Small_Transparent.png
22 | icons/record_24.png
23 | icons/ST_Logo_XSmall_Transparent.png
24 | icons/white_goto_24.png
25 | icons/white_pause_24.png
26 | icons/white_play_24.png
27 | icons/white_rewind_24.png
28 | icons/black_goto_24.png
29 | icons/black_pause_24.png
30 | icons/folder.png
31 | icons/black_play_24.png
32 | icons/black_rewind_24.png
33 | icons/icon.png
34 |
35 |
36 |
--------------------------------------------------------------------------------
/superboucle/help_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file '/home/manu/Sviluppo/SpinTool/superboucle/help_ui.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.14.1
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 |
10 | from PyQt5 import QtCore, QtGui, QtWidgets
11 |
12 |
13 | class Ui_Dialog(object):
14 | def setupUi(self, Dialog):
15 | Dialog.setObjectName("Dialog")
16 | Dialog.setWindowModality(QtCore.Qt.WindowModal)
17 | Dialog.resize(621, 372)
18 | icon = QtGui.QIcon()
19 | icon.addPixmap(QtGui.QPixmap(":/icons/icons/icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
20 | Dialog.setWindowIcon(icon)
21 | Dialog.setStyleSheet("background-color: rgb(242, 242, 242);")
22 | self.formLayoutWidget = QtWidgets.QWidget(Dialog)
23 | self.formLayoutWidget.setGeometry(QtCore.QRect(10, 10, 601, 351))
24 | self.formLayoutWidget.setObjectName("formLayoutWidget")
25 | self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget)
26 | self.formLayout.setFieldGrowthPolicy(QtWidgets.QFormLayout.ExpandingFieldsGrow)
27 | self.formLayout.setRowWrapPolicy(QtWidgets.QFormLayout.WrapLongRows)
28 | self.formLayout.setFormAlignment(QtCore.Qt.AlignCenter)
29 | self.formLayout.setContentsMargins(2, 2, 2, 2)
30 | self.formLayout.setObjectName("formLayout")
31 | self.txtHelp = QtWidgets.QTextBrowser(self.formLayoutWidget)
32 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
33 | sizePolicy.setHorizontalStretch(1)
34 | sizePolicy.setVerticalStretch(1)
35 | sizePolicy.setHeightForWidth(self.txtHelp.sizePolicy().hasHeightForWidth())
36 | self.txtHelp.setSizePolicy(sizePolicy)
37 | self.txtHelp.setStyleSheet("color: rgb(0, 0, 0);\n"
38 | "background-color: rgb(242, 242, 242);\n"
39 | "font: 12pt \"Noto Sans\";\n"
40 | "border: None;")
41 | self.txtHelp.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
42 | self.txtHelp.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
43 | self.txtHelp.setDocumentTitle("")
44 | self.txtHelp.setReadOnly(False)
45 | self.txtHelp.setAcceptRichText(True)
46 | self.txtHelp.setObjectName("txtHelp")
47 | self.formLayout.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.txtHelp)
48 |
49 | self.retranslateUi(Dialog)
50 | QtCore.QMetaObject.connectSlotsByName(Dialog)
51 |
52 | def retranslateUi(self, Dialog):
53 | _translate = QtCore.QCoreApplication.translate
54 | Dialog.setWindowTitle(_translate("Dialog", "SpinTool assistant"))
55 | self.txtHelp.setHtml(_translate("Dialog", "\n"
56 | "\n"
59 | "
"))
60 | import gui_rc
61 |
--------------------------------------------------------------------------------
/superboucle/icons/MeltinPop_Logo_100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/MeltinPop_Logo_100.png
--------------------------------------------------------------------------------
/superboucle/icons/ST_Logo_Small_Transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/ST_Logo_Small_Transparent.png
--------------------------------------------------------------------------------
/superboucle/icons/ST_Logo_XSmall_Transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/ST_Logo_XSmall_Transparent.png
--------------------------------------------------------------------------------
/superboucle/icons/Superdirt_Logo_80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/Superdirt_Logo_80.png
--------------------------------------------------------------------------------
/superboucle/icons/black_goto_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/black_goto_24.png
--------------------------------------------------------------------------------
/superboucle/icons/black_pause_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/black_pause_24.png
--------------------------------------------------------------------------------
/superboucle/icons/black_play_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/black_play_24.png
--------------------------------------------------------------------------------
/superboucle/icons/black_rewind_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/black_rewind_24.png
--------------------------------------------------------------------------------
/superboucle/icons/clip-add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/clip-add.png
--------------------------------------------------------------------------------
/superboucle/icons/clip-behaviour.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/clip-behaviour.png
--------------------------------------------------------------------------------
/superboucle/icons/clip-edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/clip-edit.png
--------------------------------------------------------------------------------
/superboucle/icons/clip-functions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/clip-functions.png
--------------------------------------------------------------------------------
/superboucle/icons/clip-groups.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/clip-groups.png
--------------------------------------------------------------------------------
/superboucle/icons/clip-measures.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/clip-measures.png
--------------------------------------------------------------------------------
/superboucle/icons/clip-start-stop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/clip-start-stop.png
--------------------------------------------------------------------------------
/superboucle/icons/copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/copy.png
--------------------------------------------------------------------------------
/superboucle/icons/edit-delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/edit-delete.png
--------------------------------------------------------------------------------
/superboucle/icons/fader.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/fader.png
--------------------------------------------------------------------------------
/superboucle/icons/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/file.png
--------------------------------------------------------------------------------
/superboucle/icons/folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/folder.png
--------------------------------------------------------------------------------
/superboucle/icons/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/icon.png
--------------------------------------------------------------------------------
/superboucle/icons/icon_dev.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/icon_dev.png
--------------------------------------------------------------------------------
/superboucle/icons/info:
--------------------------------------------------------------------------------
1 | Icons and logos
2 |
--------------------------------------------------------------------------------
/superboucle/icons/logo_sb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/logo_sb.png
--------------------------------------------------------------------------------
/superboucle/icons/record_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/record_24.png
--------------------------------------------------------------------------------
/superboucle/icons/shift.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/shift.png
--------------------------------------------------------------------------------
/superboucle/icons/sliders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/sliders.png
--------------------------------------------------------------------------------
/superboucle/icons/stop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/stop.png
--------------------------------------------------------------------------------
/superboucle/icons/warning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/warning.png
--------------------------------------------------------------------------------
/superboucle/icons/white_goto_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/white_goto_24.png
--------------------------------------------------------------------------------
/superboucle/icons/white_pause_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/white_pause_24.png
--------------------------------------------------------------------------------
/superboucle/icons/white_play_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/white_play_24.png
--------------------------------------------------------------------------------
/superboucle/icons/white_rewind_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/icons/white_rewind_24.png
--------------------------------------------------------------------------------
/superboucle/learn_cell_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file '/home/manu/Applicazioni/SuperBoucle-Manu/superboucle/learn_cell_ui.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.12.3
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 |
10 | from PyQt5 import QtCore, QtGui, QtWidgets
11 |
12 |
13 | class Ui_LearnCell(object):
14 | def setupUi(self, LearnCell):
15 | LearnCell.setObjectName("LearnCell")
16 | LearnCell.resize(94, 40)
17 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
18 | sizePolicy.setHorizontalStretch(1)
19 | sizePolicy.setVerticalStretch(1)
20 | sizePolicy.setHeightForWidth(LearnCell.sizePolicy().hasHeightForWidth())
21 | LearnCell.setSizePolicy(sizePolicy)
22 | LearnCell.setMinimumSize(QtCore.QSize(40, 40))
23 | font = QtGui.QFont()
24 | font.setFamily("Lato")
25 | LearnCell.setFont(font)
26 | self.cell_frame = QtWidgets.QFrame(LearnCell)
27 | self.cell_frame.setGeometry(QtCore.QRect(0, 0, 40, 40))
28 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
29 | sizePolicy.setHorizontalStretch(0)
30 | sizePolicy.setVerticalStretch(0)
31 | sizePolicy.setHeightForWidth(self.cell_frame.sizePolicy().hasHeightForWidth())
32 | self.cell_frame.setSizePolicy(sizePolicy)
33 | self.cell_frame.setFrameShape(QtWidgets.QFrame.NoFrame)
34 | self.cell_frame.setFrameShadow(QtWidgets.QFrame.Raised)
35 | self.cell_frame.setObjectName("cell_frame")
36 | self.label = QtWidgets.QLabel(self.cell_frame)
37 | self.label.setGeometry(QtCore.QRect(3, 2, 35, 39))
38 | self.label.setText("")
39 | self.label.setAlignment(QtCore.Qt.AlignCenter)
40 | self.label.setObjectName("label")
41 |
42 | self.retranslateUi(LearnCell)
43 | QtCore.QMetaObject.connectSlotsByName(LearnCell)
44 |
45 | def retranslateUi(self, LearnCell):
46 | _translate = QtCore.QCoreApplication.translate
47 | LearnCell.setWindowTitle(_translate("LearnCell", "Form"))
48 |
--------------------------------------------------------------------------------
/superboucle/learn_cell_ui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | LearnCell
4 |
5 |
6 |
7 | 0
8 | 0
9 | 94
10 | 40
11 |
12 |
13 |
14 |
15 | 1
16 | 1
17 |
18 |
19 |
20 |
21 | 40
22 | 40
23 |
24 |
25 |
26 |
27 | Lato
28 |
29 |
30 |
31 | Form
32 |
33 |
34 |
35 |
36 | 0
37 | 0
38 | 40
39 | 40
40 |
41 |
42 |
43 |
44 | 0
45 | 0
46 |
47 |
48 |
49 | QFrame::NoFrame
50 |
51 |
52 | QFrame::Raised
53 |
54 |
55 |
56 |
57 | 3
58 | 2
59 | 35
60 | 39
61 |
62 |
63 |
64 |
65 |
66 |
67 | Qt::AlignCenter
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/superboucle/mixer.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import Qt
2 | from superboucle.assistant import Assistant
3 | from PyQt5.QtGui import QCursor
4 | import help
5 | from PyQt5.QtWidgets import QDialog, QListWidgetItem, QWidget, QSpacerItem, QSizePolicy, QApplication
6 | from superboucle.mixer_ui import Ui_Dialog
7 | from superboucle.mixerstrip import Mixerstrip
8 | from PyQt5 import QtGui
9 | import json
10 | import sys
11 | import copy
12 | import common
13 | import settings
14 |
15 | class Mixer(QDialog, Ui_Dialog):
16 |
17 | def __init__(self, parent):
18 | super(Mixer, self).__init__(parent)
19 | self.gui = parent
20 | self.setupUi(self)
21 |
22 | # signals
23 | self.song_vol_slider.valueChanged.connect(self.setSongVolume)
24 |
25 | self.masterport_vol_slider.valueChanged.connect(self.setMasterPortFinalVolume)
26 | self.masterport_mute_checkbox.clicked.connect(self.setMasterPortMute)
27 |
28 | self.custom_reset_btn.clicked.connect(self.onCustomReset)
29 | self.reset_gain_btn.clicked.connect(self.onResetGain)
30 | self.reset_send1_btn.clicked.connect(self.onResetSend1)
31 | self.reset_send2_btn.clicked.connect(self.onResetSend2)
32 | self.reset_vol_btn.clicked.connect(self.onResetVolume)
33 | self.reset_mute_btn.clicked.connect(self.onResetMute)
34 | self.unlink_stripes_btn.clicked.connect(self.onUnlinkStripes)
35 |
36 | self.advanced_checkbox.clicked.connect(self.onAdvancedMode)
37 |
38 | self.updateMasterMuteGui(settings.master_port_mute)
39 | self.updateSongVolumeGui(self.gui.song.volume * 256)
40 | self.updateMasterVolumeGui(settings.master_port_final_volume * 100)
41 |
42 |
43 | # overwrite finished signal?
44 | self.finished.connect(self.onFinished)
45 |
46 |
47 | def showEvent(self, event):
48 | if settings.mixer_geometry:
49 | self.restoreGeometry(settings.mixer_geometry)
50 |
51 | self.updateGui(settings.output_ports)
52 | self.UpdateStripesLinkGui()
53 |
54 | def moveEvent(self, event):
55 | self.geometry = self.saveGeometry()
56 | settings.mixer_geometry = copy.deepcopy(self.geometry)
57 |
58 | # setup the port mixer gui (create one mixerstrip for each port)
59 | def updateGui(self, output_ports):
60 |
61 | #reset / clear mixerstrip layout
62 | while self.mixerLayout.count():
63 | child = self.mixerLayout.takeAt(0)
64 | if child.widget():
65 | child.widget().deleteLater()
66 |
67 | index = 0
68 |
69 | self.portlist = common.toPortsList(output_ports)
70 | # create mixerstrips
71 | for i in self.portlist:
72 | # add one strip
73 | strip = Mixerstrip(self, i, index)
74 | self.mixerLayout.addWidget(strip)
75 | index = index + 1
76 |
77 | # add spacer
78 | spacer = QSpacerItem(1, 1, QSizePolicy.Expanding, QSizePolicy.Expanding)
79 | self.mixerLayout.addItem(spacer)
80 |
81 | # set dialog size according to mixerstrip amount
82 | mixerxsize = len(self.portlist)*(95)
83 | self.resize(220 + mixerxsize, 500)
84 |
85 | # update song volume fader
86 | self.updateSongVolumeGui(common.toControllerVolumeValue(self.gui.song.volume)) # = * 256
87 |
88 |
89 | def updateStripVolume(self, stripName):
90 | strip = self.findChild(Mixerstrip, stripName)
91 | if strip:
92 | strip.updateGuiVolume()
93 |
94 | def updateStripSend1(self, stripName):
95 | strip = self.findChild(Mixerstrip, stripName)
96 | if strip:
97 | strip.updateGuiSend1()
98 |
99 | def updateStripSend2(self, stripName):
100 | strip = self.findChild(Mixerstrip, stripName)
101 | if strip:
102 | strip.updateGuiSend2()
103 |
104 | def updateStripMute(self, stripName):
105 |
106 | strip = self.findChild(Mixerstrip, stripName)
107 | if strip:
108 | strip.updateGuiMute()
109 |
110 | # used by mixerstrip to notify mute value updated
111 | def muteUpdated(self, port, index):
112 | self.gui.updateMidiMute(port, index)
113 |
114 | # used by mixerstrip to notify send1 enabled value updated
115 | def send1Updated(self, port, index):
116 | self.gui.updateMidiSend1(port, index) #TODO: creare
117 |
118 | # used by mixerstrip to notify send2 enabled value updated
119 | def send2Updated(self, port, index):
120 | self.gui.updateMidiSend2(port, index) #TODO: creare
121 |
122 | def UpdateStripesLinkGui(self):
123 | if self.gui.mixer_stripes_midi_linked == True:
124 | self.unlink_stripes_btn.setIcon(QtGui.QIcon(":/icons/icons/sliders.png"))
125 | else:
126 | self.unlink_stripes_btn.setIcon(QtGui.QIcon(":/icons/icons/warning.png"))
127 |
128 | self.unlink_stripes_btn.update()
129 |
130 |
131 | # update SONG VOLUME GUI
132 | def updateSongVolumeGui(self, value):
133 | self.song_vol_slider.setValue(value)
134 | self.song_vol_label.setText(str(int(common.toAnalogVolumeValue(value)*100*2))) # = / 256
135 |
136 |
137 | # set SONG VOLUME
138 | def setSongVolume(self):
139 | self.gui.song.volume = common.toAnalogVolumeValue(self.song_vol_slider.value()) # = / 256
140 | self.gui.song_volume_knob.setValue(common.toControllerVolumeValue(self.gui.song.volume)) # = * 256)
141 |
142 |
143 |
144 | # MASTER PORT FINAL VOLUME
145 | def updateMasterVolumeGui(self, value):
146 | self.masterport_vol_slider.setValue(value)
147 |
148 | # MASTER PORT MUTE
149 | def updateMasterMuteGui(self, value):
150 | self.masterport_mute_checkbox.setChecked(not(value))
151 |
152 | # set MASTER PORT FINAL VOLUME
153 | def setMasterPortFinalVolume(self):
154 | settings.master_port_final_volume = (self.masterport_vol_slider.value() / 100)
155 |
156 | # set MASTER PORT MUTE
157 | def setMasterPortMute(self):
158 | settings.master_port_mute = not(self.masterport_mute_checkbox.checkState())
159 |
160 |
161 | # RESETS
162 | def onCustomReset(self):
163 | if settings.customreset_mixerstrip_gain == False:
164 | self.onResetGain()
165 | if settings.customreset_mixerstrip_send1 == False:
166 | self.onResetSend1()
167 | if settings.customreset_mixerstrip_send2 == False:
168 | self.onResetSend2()
169 | if settings.customreset_mixerstrip_volume == False:
170 | self.onResetVolume()
171 | if settings.customreset_mixerstrip_mute == False:
172 | self.onResetMute()
173 |
174 | def onResetGain(self):
175 | common.resetGain(settings.output_ports)
176 | self.updateGui(settings.output_ports)
177 |
178 | def onResetSend1(self):
179 | common.resetSend1(settings.output_ports)
180 | self.updateGui(settings.output_ports)
181 |
182 | def onResetSend2(self):
183 | common.resetSend2(settings.output_ports)
184 | self.updateGui(settings.output_ports)
185 |
186 | def onResetVolume(self):
187 | common.resetVolume(settings.output_ports)
188 | self.updateGui(settings.output_ports)
189 |
190 | def onResetMute(self):
191 | common.resetMute(settings.output_ports)
192 | self.updateGui(settings.output_ports)
193 | self.gui.resetMidiMute()
194 |
195 |
196 | def onUnlinkStripes(self):
197 | self.gui.mixer_stripes_midi_linked = not self.gui.mixer_stripes_midi_linked
198 | self.UpdateStripesLinkGui()
199 |
200 |
201 | def onAdvancedMode(self):
202 | common.mixer_mode = self.advanced_checkbox.isChecked()
203 | self.updateGui(settings.output_ports)
204 |
205 |
206 |
207 | # overwrite hideEvend method - can be also used with onFinished
208 | def hideEvent(self, event):
209 | self.gui.actionMixer.setEnabled(True)
210 |
211 | # triggered if dialog is closed
212 | def onFinished(self):
213 | pass
214 |
215 |
216 | # HELP management ---------------------------------------------------------
217 |
218 | def keyPressEvent(self, event):
219 |
220 | if event.key() == Qt.Key_H: # if pressed key is H (help)
221 |
222 | pos = QCursor.pos()
223 | widget = QApplication.widgetAt(pos) # this is widget under cursor
224 |
225 | if widget is None: return
226 | accName = widget.accessibleName() # this is widget accessible name
227 |
228 | if accName != "":
229 | wantedHelp = help.Context(accName) # Conversion of string accessible name to Context enum
230 | self.showContextHelp(wantedHelp)
231 |
232 |
233 | def showContextHelp(self, wantedHelp):
234 | helpText = help.getContextHelp(wantedHelp)
235 | Assistant(self, helpText, Assistant.MODE_CONTEXT)
--------------------------------------------------------------------------------
/superboucle/mixerstrip.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtWidgets import QWidget
2 | from PyQt5.QtCore import QSettings
3 | from superboucle.preferences import Preferences
4 |
5 | from superboucle.mixerstrip_ui import Ui_Mixerstrip
6 |
7 | import settings
8 | import common
9 |
10 |
11 |
12 | class Mixerstrip(QWidget, Ui_Mixerstrip):
13 |
14 | def __init__(self, parent, portname, index):
15 | super(Mixerstrip, self).__init__(parent)
16 | self.mixer = parent
17 | self.setupUi(self)
18 | self.strip_index = index
19 |
20 | # set port name
21 | self.port_name_label.setText(portname)
22 | self.port_name = portname
23 |
24 | # ...and PyQt object name:
25 | self.setObjectName(portname)
26 |
27 | # set mixer mode
28 | self.setMixerMode()
29 |
30 | # read mixer strip values
31 | self.readMixerstrip()
32 |
33 |
34 | # signals
35 | self.gain_knob.valueChanged.connect(self.writeGainValue)
36 |
37 | self.send1_knob.valueChanged.connect(self.writeSend1Value)
38 | self.send2_knob.valueChanged.connect(self.writeSend2Value)
39 |
40 | self.vol_slider.valueChanged.connect(self.writeVolumeValue)
41 | self.mute_checkbox.clicked.connect(self.writeMuteValue)
42 |
43 | self.to_master_checkbox.clicked.connect(self.writeToMasterValue)
44 |
45 |
46 | # set mixer mode
47 | def setMixerMode(self):
48 | self.drop_checkbox.hide() # always hide until drops are implemented
49 |
50 | if common.mixer_mode == False:
51 | self.to_master_checkbox.hide()
52 | else:
53 | self.to_master_checkbox.show()
54 |
55 | # get and update each mixer values from mixer dict
56 | def readMixerstrip(self):
57 | # gain
58 | gain = settings.output_ports[self.port_name][common.PORT_GAIN_DEF]
59 | self.gain_knob.setValue(gain*200)
60 | self.gain_label.setText(str(round((gain*200 - 100))))
61 |
62 | # send1
63 | self.send1_knob.setValue(settings.output_ports[self.port_name][common.PORT_SEND1_DEF] * 100)
64 |
65 | # send2
66 | self.send2_knob.setValue(settings.output_ports[self.port_name][common.PORT_SEND2_DEF] * 100)
67 |
68 | # vol
69 | self.vol_slider.setValue(settings.output_ports[self.port_name][common.PORT_VOLUME_DEF] * 100)
70 |
71 | # mute
72 | self.mute_checkbox.setChecked(settings.output_ports[self.port_name][common.PORT_MUTE_DEF])
73 |
74 | # to_master
75 | self.to_master_checkbox.setChecked(settings.output_ports[self.port_name][common.PORT_TO_MASTER_DEF])
76 |
77 |
78 | # Port name
79 | def getPortName(self):
80 | return self.port_name
81 |
82 |
83 | # write Gain into mixer dict
84 | def writeGainValue(self):
85 | gain = self.gain_knob.value()
86 | settings.output_ports[self.port_name][common.PORT_GAIN_DEF] = gain / 200
87 | self.gain_label.setText(str(round((gain-100))))
88 |
89 | # write Send1 into mixer dict
90 | def writeSend1Value(self):
91 | settings.output_ports[self.port_name][common.PORT_SEND1_DEF] = self.send1_knob.value() / 100
92 |
93 | # write Send2 into mixer dict
94 | def writeSend2Value(self):
95 | settings.output_ports[self.port_name][common.PORT_SEND2_DEF] = self.send2_knob.value() / 100
96 |
97 | # write Volume into mixer dict
98 | def writeVolumeValue(self):
99 | settings.output_ports[self.port_name][common.PORT_VOLUME_DEF] = self.vol_slider.value() / 100
100 |
101 | # write Mute into mixer dict
102 | def writeMuteValue(self):
103 | settings.output_ports[self.port_name][common.PORT_MUTE_DEF] = bool(self.mute_checkbox.checkState())
104 | self.mixer.muteUpdated(self.port_name, self.strip_index)
105 |
106 |
107 | def writeToMasterValue(self):
108 | settings.output_ports[self.port_name][common.PORT_TO_MASTER_DEF] = bool(self.to_master_checkbox.checkState())
109 |
110 | def updateGuiVolume(self):
111 | self.vol_slider.setValue(settings.output_ports[self.port_name][common.PORT_VOLUME_DEF] * 100)
112 |
113 | def updateGuiSend1(self):
114 | self.send1_knob.setValue(settings.output_ports[self.port_name][common.PORT_SEND1_DEF] * 100)
115 |
116 | def updateGuiSend2(self):
117 | self.send2_knob.setValue(settings.output_ports[self.port_name][common.PORT_SEND2_DEF] * 100)
118 |
119 | def updateGuiMute(self):
120 | self.mute_checkbox.setChecked(settings.output_ports[self.port_name][common.PORT_MUTE_DEF])
121 |
122 |
--------------------------------------------------------------------------------
/superboucle/new_song.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtWidgets import QDialog
2 | from superboucle.new_song_ui import Ui_Dialog
3 | from superboucle.clip import Song
4 | from PyQt5.QtCore import QSettings
5 | from superboucle.preferences import Preferences
6 | import settings
7 | import common
8 |
9 | class NewSongDialog(QDialog, Ui_Dialog):
10 |
11 | def __init__(self, parent):
12 | super(NewSongDialog, self).__init__(parent)
13 | self.gui = parent
14 | self.setupUi(self)
15 |
16 | self.widthSpinBox.setValue(settings.grid_columns)
17 | self.heightSpinBox.setValue(settings.grid_rows)
18 | self.spinBeats.setValue(settings.new_song_beats)
19 | self.spinBPM.setValue(settings.new_song_bpm)
20 | self.spinMasterVolume.setValue(settings.new_song_master_volume)
21 |
22 | self.show()
23 |
24 | def accept(self):
25 | volume = common.toStoredSongVolumeValue(self.spinMasterVolume.value())
26 | self.gui.initUI(Song(self.widthSpinBox.value(),
27 | self.heightSpinBox.value(),
28 | volume,
29 | self.spinBPM.value(),
30 | self.spinBeats.value()))
31 |
32 | super(NewSongDialog, self).accept()
33 |
--------------------------------------------------------------------------------
/superboucle/new_song_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'new_song_ui.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.14.1
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 |
10 | from PyQt5 import QtCore, QtGui, QtWidgets
11 |
12 |
13 | class Ui_Dialog(object):
14 | def setupUi(self, Dialog):
15 | Dialog.setObjectName("Dialog")
16 | Dialog.setWindowModality(QtCore.Qt.WindowModal)
17 | Dialog.resize(592, 206)
18 | self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
19 | self.buttonBox.setGeometry(QtCore.QRect(10, 160, 571, 41))
20 | self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
21 | self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
22 | self.buttonBox.setObjectName("buttonBox")
23 | self.labelGridSize = QtWidgets.QLabel(Dialog)
24 | self.labelGridSize.setGeometry(QtCore.QRect(20, 10, 121, 18))
25 | self.labelGridSize.setStyleSheet("color: rgb(0, 0, 0);\n"
26 | "font: bold 10pt \"Noto Sans\";")
27 | self.labelGridSize.setObjectName("labelGridSize")
28 | self.labelMasterVolume = QtWidgets.QLabel(Dialog)
29 | self.labelMasterVolume.setGeometry(QtCore.QRect(180, 10, 111, 21))
30 | self.labelMasterVolume.setStyleSheet("color: rgb(0, 0, 0);\n"
31 | "font: bold 10pt \"Noto Sans\";")
32 | self.labelMasterVolume.setObjectName("labelMasterVolume")
33 | self.spinMasterVolume = QtWidgets.QSpinBox(Dialog)
34 | self.spinMasterVolume.setGeometry(QtCore.QRect(180, 40, 71, 31))
35 | self.spinMasterVolume.setStyleSheet("color: rgb(0, 0, 0);\n"
36 | "background-color: rgb(255, 255, 255);\n"
37 | "font: 9pt \"Noto Sans\";")
38 | self.spinMasterVolume.setMinimum(0)
39 | self.spinMasterVolume.setMaximum(200)
40 | self.spinMasterVolume.setProperty("value", 100)
41 | self.spinMasterVolume.setObjectName("spinMasterVolume")
42 | self.heightSpinBox = QtWidgets.QSpinBox(Dialog)
43 | self.heightSpinBox.setGeometry(QtCore.QRect(67, 80, 72, 31))
44 | self.heightSpinBox.setStyleSheet("color: rgb(0, 0, 0);\n"
45 | "background-color: rgb(255, 255, 255);\n"
46 | "font: 9pt \"Noto Sans\";")
47 | self.heightSpinBox.setMaximum(16)
48 | self.heightSpinBox.setProperty("value", 8)
49 | self.heightSpinBox.setObjectName("heightSpinBox")
50 | self.widthSpinBox = QtWidgets.QSpinBox(Dialog)
51 | self.widthSpinBox.setGeometry(QtCore.QRect(67, 39, 72, 31))
52 | self.widthSpinBox.setStyleSheet("color: rgb(0, 0, 0);\n"
53 | "background-color: rgb(255, 255, 255);\n"
54 | "font: 9pt \"Noto Sans\";")
55 | self.widthSpinBox.setMaximum(16)
56 | self.widthSpinBox.setProperty("value", 8)
57 | self.widthSpinBox.setObjectName("widthSpinBox")
58 | self.label = QtWidgets.QLabel(Dialog)
59 | self.label.setGeometry(QtCore.QRect(20, 39, 37, 25))
60 | self.label.setStyleSheet("color: rgb(0, 0, 0);\n"
61 | "font: 10pt \"Noto Sans\";")
62 | self.label.setObjectName("label")
63 | self.label_2 = QtWidgets.QLabel(Dialog)
64 | self.label_2.setGeometry(QtCore.QRect(20, 80, 41, 31))
65 | self.label_2.setStyleSheet("color: rgb(0, 0, 0);\n"
66 | "font: 10pt \"Noto Sans\";")
67 | self.label_2.setObjectName("label_2")
68 | self.labelBeats = QtWidgets.QLabel(Dialog)
69 | self.labelBeats.setGeometry(QtCore.QRect(470, 10, 101, 21))
70 | self.labelBeats.setStyleSheet("color: rgb(0, 0, 0);\n"
71 | "font: bold 10pt \"Noto Sans\";")
72 | self.labelBeats.setObjectName("labelBeats")
73 | self.spinBeats = QtWidgets.QSpinBox(Dialog)
74 | self.spinBeats.setGeometry(QtCore.QRect(470, 40, 71, 31))
75 | self.spinBeats.setStyleSheet("color: rgb(0, 0, 0);\n"
76 | "background-color: rgb(255, 255, 255);\n"
77 | "font: 9pt \"Noto Sans\";")
78 | self.spinBeats.setMinimum(1)
79 | self.spinBeats.setMaximum(99)
80 | self.spinBeats.setProperty("value", 4)
81 | self.spinBeats.setObjectName("spinBeats")
82 | self.spinBPM = QtWidgets.QSpinBox(Dialog)
83 | self.spinBPM.setGeometry(QtCore.QRect(345, 40, 71, 31))
84 | self.spinBPM.setStyleSheet("color: rgb(0, 0, 0);\n"
85 | "background-color: rgb(255, 255, 255);\n"
86 | "font: 9pt \"Noto Sans\";")
87 | self.spinBPM.setMinimum(1)
88 | self.spinBPM.setMaximum(260)
89 | self.spinBPM.setProperty("value", 120)
90 | self.spinBPM.setObjectName("spinBPM")
91 | self.labelBPM = QtWidgets.QLabel(Dialog)
92 | self.labelBPM.setGeometry(QtCore.QRect(345, 10, 41, 21))
93 | self.labelBPM.setStyleSheet("color: rgb(0, 0, 0);\n"
94 | "font: bold 10pt \"Noto Sans\";")
95 | self.labelBPM.setObjectName("labelBPM")
96 |
97 | self.retranslateUi(Dialog)
98 | self.buttonBox.accepted.connect(Dialog.accept)
99 | self.buttonBox.rejected.connect(Dialog.reject)
100 | QtCore.QMetaObject.connectSlotsByName(Dialog)
101 |
102 | def retranslateUi(self, Dialog):
103 | _translate = QtCore.QCoreApplication.translate
104 | Dialog.setWindowTitle(_translate("Dialog", "New Song"))
105 | self.labelGridSize.setText(_translate("Dialog", "Grid size"))
106 | self.labelMasterVolume.setText(_translate("Dialog", "Master volume"))
107 | self.label.setText(_translate("Dialog", "Width"))
108 | self.label_2.setText(_translate("Dialog", "Height"))
109 | self.labelBeats.setText(_translate("Dialog", "Beats per bar"))
110 | self.labelBPM.setText(_translate("Dialog", "BPM"))
111 |
--------------------------------------------------------------------------------
/superboucle/new_song_ui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 | Qt::WindowModal
7 |
8 |
9 |
10 | 0
11 | 0
12 | 592
13 | 206
14 |
15 |
16 |
17 | New Song
18 |
19 |
20 |
21 |
22 | 10
23 | 160
24 | 571
25 | 41
26 |
27 |
28 |
29 | Qt::Horizontal
30 |
31 |
32 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
33 |
34 |
35 |
36 |
37 |
38 | 20
39 | 10
40 | 121
41 | 18
42 |
43 |
44 |
45 | color: rgb(0, 0, 0);
46 | font: bold 10pt "Noto Sans";
47 |
48 |
49 | Grid size
50 |
51 |
52 |
53 |
54 |
55 | 180
56 | 10
57 | 111
58 | 21
59 |
60 |
61 |
62 | color: rgb(0, 0, 0);
63 | font: bold 10pt "Noto Sans";
64 |
65 |
66 | Master volume
67 |
68 |
69 |
70 |
71 |
72 | 180
73 | 40
74 | 71
75 | 31
76 |
77 |
78 |
79 | color: rgb(0, 0, 0);
80 | background-color: rgb(255, 255, 255);
81 | font: 9pt "Noto Sans";
82 |
83 |
84 | 0
85 |
86 |
87 | 200
88 |
89 |
90 | 100
91 |
92 |
93 |
94 |
95 |
96 | 67
97 | 80
98 | 72
99 | 31
100 |
101 |
102 |
103 | color: rgb(0, 0, 0);
104 | background-color: rgb(255, 255, 255);
105 | font: 9pt "Noto Sans";
106 |
107 |
108 | 16
109 |
110 |
111 | 8
112 |
113 |
114 |
115 |
116 |
117 | 67
118 | 39
119 | 72
120 | 31
121 |
122 |
123 |
124 | color: rgb(0, 0, 0);
125 | background-color: rgb(255, 255, 255);
126 | font: 9pt "Noto Sans";
127 |
128 |
129 | 16
130 |
131 |
132 | 8
133 |
134 |
135 |
136 |
137 |
138 | 20
139 | 39
140 | 37
141 | 25
142 |
143 |
144 |
145 | color: rgb(0, 0, 0);
146 | font: 10pt "Noto Sans";
147 |
148 |
149 | Width
150 |
151 |
152 |
153 |
154 |
155 | 20
156 | 80
157 | 41
158 | 31
159 |
160 |
161 |
162 | color: rgb(0, 0, 0);
163 | font: 10pt "Noto Sans";
164 |
165 |
166 | Height
167 |
168 |
169 |
170 |
171 |
172 | 470
173 | 10
174 | 101
175 | 21
176 |
177 |
178 |
179 | color: rgb(0, 0, 0);
180 | font: bold 10pt "Noto Sans";
181 |
182 |
183 | Beats per bar
184 |
185 |
186 |
187 |
188 |
189 | 470
190 | 40
191 | 71
192 | 31
193 |
194 |
195 |
196 | color: rgb(0, 0, 0);
197 | background-color: rgb(255, 255, 255);
198 | font: 9pt "Noto Sans";
199 |
200 |
201 | 1
202 |
203 |
204 | 99
205 |
206 |
207 | 4
208 |
209 |
210 |
211 |
212 |
213 | 345
214 | 40
215 | 71
216 | 31
217 |
218 |
219 |
220 | color: rgb(0, 0, 0);
221 | background-color: rgb(255, 255, 255);
222 | font: 9pt "Noto Sans";
223 |
224 |
225 | 1
226 |
227 |
228 | 260
229 |
230 |
231 | 120
232 |
233 |
234 |
235 |
236 |
237 | 345
238 | 10
239 | 41
240 | 21
241 |
242 |
243 |
244 | color: rgb(0, 0, 0);
245 | font: bold 10pt "Noto Sans";
246 |
247 |
248 | BPM
249 |
250 |
251 |
252 |
253 |
254 |
255 | buttonBox
256 | accepted()
257 | Dialog
258 | accept()
259 |
260 |
261 | 248
262 | 254
263 |
264 |
265 | 157
266 | 274
267 |
268 |
269 |
270 |
271 | buttonBox
272 | rejected()
273 | Dialog
274 | reject()
275 |
276 |
277 | 316
278 | 260
279 |
280 |
281 | 286
282 | 274
283 |
284 |
285 |
286 |
287 |
288 |
--------------------------------------------------------------------------------
/superboucle/playlist.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtWidgets import QDialog, QFileDialog, QAbstractItemView, QMessageBox
2 | from superboucle.playlist_ui import Ui_Dialog
3 | from superboucle.clip import verify_ext
4 | import configparser, json
5 | from zipfile import ZipFile
6 | from os.path import basename, splitext
7 | from io import BytesIO, StringIO, TextIOWrapper
8 | from os import path
9 | import settings
10 | import common
11 |
12 | class PlaylistDialog(QDialog, Ui_Dialog):
13 |
14 | current_song_id = None
15 |
16 | def __init__(self, parent):
17 | super(PlaylistDialog, self).__init__(parent)
18 | self.gui = parent
19 | self.setupUi(self)
20 | self.updateList()
21 | self.removeSongBtn.clicked.connect(self.onRemove)
22 | self.addSongsBtn.clicked.connect(self.onAddSongs)
23 | self.loadPlaylistBtn.clicked.connect(self.onLoadPlaylist)
24 | self.savePlaylistBtn.clicked.connect(self.onSavePlaylist)
25 | self.loadSongBtn.clicked.connect(self.onLoadSong)
26 | self.playlistList.itemDoubleClicked.connect(self.onSongDoubleClick)
27 | self.playlistList.setDragDropMode(QAbstractItemView.InternalMove)
28 | self.playlistList.model().rowsMoved.connect(self.onMoveRows)
29 | self.cBoxBigFonts.setChecked(settings.use_big_fonts_playlist)
30 | self.cBoxBigFonts.stateChanged.connect(self.onBigFonts)
31 |
32 | self.geometry = settings.playlist_geometry
33 |
34 | if self.geometry:
35 | self.restoreGeometry(self.geometry)
36 |
37 | if self.isVisible() == False:
38 | self.show()
39 |
40 | self.useBigFonts(settings.use_big_fonts_playlist)
41 |
42 | def updateList(self):
43 | self.playlistList.clear()
44 | for i, song in enumerate(settings.playlist):
45 | name, ext = splitext(basename(song)) # song.file_name
46 | self.playlistList.addItem('{}. {}'.format(i + 1, name))
47 |
48 | def onRemove(self):
49 | response = QMessageBox.question(self, "Remove Song?", "Are you sure you want to remove this song from the playlist?")
50 | if response == QMessageBox.No:
51 | return
52 |
53 | id = self.playlistList.currentRow()
54 | if id != -1:
55 | del settings.playlist[id]
56 | self.updateList()
57 |
58 | def onMoveRows(self, sourceParent, sourceStart, sourceEnd,
59 | destinationParent, destinationRow):
60 | l = settings.playlist
61 | destinationRow -= destinationRow > sourceStart
62 | l.insert(destinationRow, l.pop(sourceStart))
63 | self.updateList()
64 |
65 | def onAddSongs(self):
66 | file_names, a = self.gui.getOpenFileName('Add Songs',
67 | common.SONG_FILE_TYPE,
68 | self,
69 | QFileDialog.getOpenFileNames)
70 | settings.playlist += file_names
71 | self.updateList()
72 |
73 | def onLoadPlaylist(self):
74 |
75 | file_name, a = self.gui.getOpenFileName('Import Playlist',
76 | common.PLAYLIST_FILE_TYPE,
77 | self)
78 | if not file_name:
79 | return
80 |
81 | common.updateSettingsPlaylist(file_name, settings)
82 | self.updateList()
83 |
84 | def onSavePlaylist(self):
85 | file_name, a = self.gui.getSaveFileName('Export Playlist',
86 | common.PLAYLIST_FILE_TYPE,
87 | self)
88 |
89 | if file_name:
90 | file_name = verify_ext(file_name, 'sbp')
91 | with open(file_name, 'w') as f:
92 | f.write(json.dumps(settings.playlist))
93 |
94 | def onBigFonts(self):
95 | settings.use_big_fonts_playlist = self.cBoxBigFonts.isChecked()
96 | self.useBigFonts(settings.use_big_fonts_playlist)
97 |
98 | def onLoadSong(self):
99 | id = self.playlistList.currentRow()
100 | self.loadSong(id)
101 |
102 | def onSongDoubleClick(self, item):
103 | id = self.playlistList.row(item)
104 | self.loadSong(id)
105 |
106 | def loadSong(self, id):
107 | if id == -1:
108 | return
109 | file_name = settings.playlist[id]
110 | try:
111 | self.gui.openSongFromDisk(file_name)
112 | # self.current_song_id = id
113 | except Exception as e:
114 | print("could not load File {}.\nError: {}".format(file_name, e))
115 |
116 |
117 | def useBigFonts(self, use = False):
118 | self.bigFontSize = settings.bigFontSize
119 |
120 | if use == False:
121 | stylesheet = 'font: 10pt "Noto Sans";'
122 | else:
123 | stylesheet = 'font: bold ' + str(self.bigFontSize) + 'pt "Noto Sans";'
124 |
125 | self.playlistList.setStyleSheet(stylesheet)
126 |
127 | # saving window position
128 |
129 | def resizeEvent(self, event):
130 | self.geometry = self.saveGeometry()
131 | settings.playlist_geometry = self.geometry
132 |
133 | def moveEvent(self, event):
134 | self.geometry = self.saveGeometry()
135 | settings.playlist_geometry = self.geometry
136 |
137 | def hideEvent(self, event):
138 | self.gui.actionPlaylist_Editor.setEnabled(True)
--------------------------------------------------------------------------------
/superboucle/playlist_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file '/home/manu/Sviluppo/SpinTool/superboucle/playlist_ui.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.14.1
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 |
10 | from PyQt5 import QtCore, QtGui, QtWidgets
11 |
12 |
13 | class Ui_Dialog(object):
14 | def setupUi(self, Dialog):
15 | Dialog.setObjectName("Dialog")
16 | Dialog.resize(320, 335)
17 | icon = QtGui.QIcon()
18 | icon.addPixmap(QtGui.QPixmap(":/icons/icons/icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
19 | Dialog.setWindowIcon(icon)
20 | self.gridLayout = QtWidgets.QGridLayout(Dialog)
21 | self.gridLayout.setObjectName("gridLayout")
22 | self.horizontalLayout = QtWidgets.QHBoxLayout()
23 | self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetNoConstraint)
24 | self.horizontalLayout.setObjectName("horizontalLayout")
25 | self.playlistList = QtWidgets.QListWidget(Dialog)
26 | self.playlistList.setMaximumSize(QtCore.QSize(16777215, 16777215))
27 | self.playlistList.setSizeIncrement(QtCore.QSize(100, 100))
28 | self.playlistList.setMovement(QtWidgets.QListView.Static)
29 | self.playlistList.setResizeMode(QtWidgets.QListView.Adjust)
30 | self.playlistList.setObjectName("playlistList")
31 | self.horizontalLayout.addWidget(self.playlistList)
32 | self.verticalLayout_3 = QtWidgets.QVBoxLayout()
33 | self.verticalLayout_3.setObjectName("verticalLayout_3")
34 | self.loadSongBtn = QtWidgets.QPushButton(Dialog)
35 | self.loadSongBtn.setObjectName("loadSongBtn")
36 | self.verticalLayout_3.addWidget(self.loadSongBtn)
37 | self.addSongsBtn = QtWidgets.QPushButton(Dialog)
38 | self.addSongsBtn.setObjectName("addSongsBtn")
39 | self.verticalLayout_3.addWidget(self.addSongsBtn)
40 | self.removeSongBtn = QtWidgets.QPushButton(Dialog)
41 | self.removeSongBtn.setObjectName("removeSongBtn")
42 | self.verticalLayout_3.addWidget(self.removeSongBtn)
43 | spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
44 | self.verticalLayout_3.addItem(spacerItem)
45 | self.loadPlaylistBtn = QtWidgets.QPushButton(Dialog)
46 | self.loadPlaylistBtn.setObjectName("loadPlaylistBtn")
47 | self.verticalLayout_3.addWidget(self.loadPlaylistBtn)
48 | self.savePlaylistBtn = QtWidgets.QPushButton(Dialog)
49 | self.savePlaylistBtn.setObjectName("savePlaylistBtn")
50 | self.verticalLayout_3.addWidget(self.savePlaylistBtn)
51 | self.horizontalLayout.addLayout(self.verticalLayout_3)
52 | self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
53 | self.cBoxBigFonts = QtWidgets.QCheckBox(Dialog)
54 | self.cBoxBigFonts.setObjectName("cBoxBigFonts")
55 | self.gridLayout.addWidget(self.cBoxBigFonts, 1, 0, 1, 1)
56 |
57 | self.retranslateUi(Dialog)
58 | QtCore.QMetaObject.connectSlotsByName(Dialog)
59 |
60 | def retranslateUi(self, Dialog):
61 | _translate = QtCore.QCoreApplication.translate
62 | Dialog.setWindowTitle(_translate("Dialog", "Playlist"))
63 | self.loadSongBtn.setText(_translate("Dialog", "Load Song"))
64 | self.addSongsBtn.setText(_translate("Dialog", "Add Songs"))
65 | self.removeSongBtn.setText(_translate("Dialog", "Remove Song"))
66 | self.loadPlaylistBtn.setText(_translate("Dialog", "Import Playlist"))
67 | self.savePlaylistBtn.setText(_translate("Dialog", "Export Playlist"))
68 | self.cBoxBigFonts.setText(_translate("Dialog", "Use custom font size"))
69 | import gui_rc
70 |
--------------------------------------------------------------------------------
/superboucle/playlist_ui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 320
10 | 335
11 |
12 |
13 |
14 | Playlist
15 |
16 |
17 |
18 | :/icons/icons/icon.png:/icons/icons/icon.png
19 |
20 |
21 | -
22 |
23 |
24 | QLayout::SetNoConstraint
25 |
26 |
-
27 |
28 |
29 |
30 | 16777215
31 | 16777215
32 |
33 |
34 |
35 |
36 | 100
37 | 100
38 |
39 |
40 |
41 | QListView::Static
42 |
43 |
44 | QListView::Adjust
45 |
46 |
47 |
48 | -
49 |
50 |
-
51 |
52 |
53 | Load Song
54 |
55 |
56 |
57 | -
58 |
59 |
60 | Add Songs
61 |
62 |
63 |
64 | -
65 |
66 |
67 | Remove Song
68 |
69 |
70 |
71 | -
72 |
73 |
74 | Qt::Vertical
75 |
76 |
77 |
78 | 20
79 | 40
80 |
81 |
82 |
83 |
84 | -
85 |
86 |
87 | Import Playlist
88 |
89 |
90 |
91 | -
92 |
93 |
94 | Export Playlist
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | -
103 |
104 |
105 | Use custom font size
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/superboucle/port_manager.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtWidgets import QDialog, QListWidgetItem, QMessageBox
2 | from superboucle.port_manager_ui import Ui_Dialog
3 | from superboucle.add_port import AddPortDialog
4 | from superboucle.clip import verify_ext, Clip
5 | import json
6 | import settings
7 | import common
8 |
9 | class PortManager(QDialog, Ui_Dialog):
10 | def __init__(self, parent):
11 | super(PortManager, self).__init__(parent)
12 | self.gui = parent
13 | self.setupUi(self)
14 | self.backup_indixes = []
15 | self.updateList()
16 | self.removePortBtn.clicked.connect(self.onRemove)
17 | self.addPortBtn.clicked.connect(self.onAddPort)
18 | self.loadPortlistBtn.clicked.connect(self.onLoadPortlist)
19 | self.savePortlistBtn.clicked.connect(self.onSavePortlist)
20 | self.autoconnectCBox.setChecked(settings.auto_connect_output)
21 | self.autoconnectCBox.stateChanged.connect(self.onCheckAutoconnect)
22 | self.finished.connect(self.onFinished)
23 |
24 | self.gui.updatePorts.connect(self.updateList)
25 |
26 | self.show()
27 |
28 | def updateList(self):
29 | self.portList.clear()
30 | self.backup_indixes = common.toPortsList(settings.output_ports)
31 | for name in self.backup_indixes:
32 | this_item = QListWidgetItem(name)
33 | this_item.setFlags(this_item.flags())
34 | self.portList.addItem(this_item)
35 |
36 | def onAddPort(self):
37 | AddPortDialog(self.gui, callback=self.updateList)
38 |
39 | def onRemove(self):
40 | response = QMessageBox.question(self, "Delete Port?", "Are you sure you want to delete this output port?")
41 | if response == QMessageBox.No:
42 | return
43 |
44 | currentItem = self.portList.currentItem()
45 |
46 | if currentItem:
47 |
48 | port_name = currentItem.text()
49 |
50 | if port_name == common.DEFAULT_PORT:
51 |
52 | message = QMessageBox(self)
53 | message.setWindowTitle("Can't remove port " + port_name)
54 | message.setText("It's not possible to remove this port since it's \n" +
55 | "default clips output port")
56 | message.show()
57 | return
58 |
59 | # This condition should NEVER happen; however I keep the control here.
60 | if self.portList.count() == 1:
61 |
62 | message = QMessageBox(self)
63 | message.setWindowTitle("Can't remove port " + port_name)
64 | message.setText("SpinTool must have at least one output port defined \n" +
65 | "therefore it's not possible to remove this port")
66 | message.show()
67 | return
68 |
69 | self.gui.removePort(port_name)
70 | self.updateList()
71 |
72 |
73 | def onLoadPortlist(self):
74 | file_name, a = (self.gui.getOpenFileName('Open Portlist', common.PORTLIST_FILE_TYPE, self))
75 | if not file_name:
76 | return
77 |
78 | result = QMessageBox.question(self,
79 | "JACK output ports",
80 | "Do you want to preserve connections, if some port already exixst? \n" +
81 | "If you choose 'No', existing ports will be reloaded and connections to these ports will be lost.",
82 | QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
83 | if result == QMessageBox.Cancel:
84 | return
85 |
86 | with open(file_name, 'r') as f:
87 | read_data = f.read()
88 | data = json.loads(read_data)
89 |
90 | ports = data["outputs"] # Getting from JSON data the output ports (set or list)
91 | settings.output_ports = common.toPortsDict(ports)
92 |
93 | # Updating Jack connections and Mixer layout
94 | # user could choose if deleting and creating from scratch all jack output ports,
95 | # or keeping existing jack output ports to preserve their connections
96 | if result == QMessageBox.Yes:
97 | common.updateOutputPorts(settings.output_ports, self.gui._jack_client)
98 |
99 | elif result == QMessageBox.No:
100 | common.createOutputPorts(settings.output_ports, self.gui._jack_client)
101 |
102 |
103 | self.gui.updatePorts.emit()
104 | if self.gui.output_mixer:
105 | self.gui.output_mixer.updateGui(settings.output_ports)
106 |
107 | def onSavePortlist(self):
108 | file_name, a = (self.gui.getSaveFileName('Save Portlist', common.PORTLIST_FILE_TYPE, self))
109 |
110 | if file_name:
111 | file_name = verify_ext(file_name, 'sbl')
112 |
113 | with open(file_name, 'w') as f:
114 | #data = {"clips": [[c.output if isinstance(c, Clip) else common.DEFAULT_PORT
115 | # for c in cliprow] for cliprow in self.gui.song.clips_matrix],
116 | # "outputs": common.toPortsList(settings.output_ports)}
117 |
118 | data = {"outputs": common.toPortsList(settings.output_ports)}
119 |
120 | f.write(json.dumps(data))
121 |
122 | def onCheckAutoconnect(self):
123 | settings.auto_connect_output = self.autoconnectCBox.isChecked()
124 |
125 | def hideEvent(self, event):
126 | self.gui.actionPort_Manager.setEnabled(True)
127 |
128 | def onFinished(self):
129 | pass
130 |
--------------------------------------------------------------------------------
/superboucle/port_manager_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'port_manager_ui.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.14.1
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 |
10 | from PyQt5 import QtCore, QtGui, QtWidgets
11 |
12 |
13 | class Ui_Dialog(object):
14 | def setupUi(self, Dialog):
15 | Dialog.setObjectName("Dialog")
16 | Dialog.resize(370, 308)
17 | icon = QtGui.QIcon()
18 | icon.addPixmap(QtGui.QPixmap(":/icons/icons/icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
19 | Dialog.setWindowIcon(icon)
20 | self.gridLayout = QtWidgets.QGridLayout(Dialog)
21 | self.gridLayout.setObjectName("gridLayout")
22 | self.horizontalLayout = QtWidgets.QHBoxLayout()
23 | self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetNoConstraint)
24 | self.horizontalLayout.setObjectName("horizontalLayout")
25 | self.portList = QtWidgets.QListWidget(Dialog)
26 | self.portList.setMaximumSize(QtCore.QSize(16777215, 16777215))
27 | self.portList.setSizeIncrement(QtCore.QSize(100, 100))
28 | self.portList.setMovement(QtWidgets.QListView.Static)
29 | self.portList.setResizeMode(QtWidgets.QListView.Adjust)
30 | self.portList.setObjectName("portList")
31 | self.horizontalLayout.addWidget(self.portList)
32 | self.verticalLayout_3 = QtWidgets.QVBoxLayout()
33 | self.verticalLayout_3.setObjectName("verticalLayout_3")
34 | self.addPortBtn = QtWidgets.QPushButton(Dialog)
35 | self.addPortBtn.setObjectName("addPortBtn")
36 | self.verticalLayout_3.addWidget(self.addPortBtn)
37 | self.removePortBtn = QtWidgets.QPushButton(Dialog)
38 | self.removePortBtn.setObjectName("removePortBtn")
39 | self.verticalLayout_3.addWidget(self.removePortBtn)
40 | spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
41 | self.verticalLayout_3.addItem(spacerItem)
42 | self.loadPortlistBtn = QtWidgets.QPushButton(Dialog)
43 | self.loadPortlistBtn.setObjectName("loadPortlistBtn")
44 | self.verticalLayout_3.addWidget(self.loadPortlistBtn)
45 | self.savePortlistBtn = QtWidgets.QPushButton(Dialog)
46 | self.savePortlistBtn.setObjectName("savePortlistBtn")
47 | self.verticalLayout_3.addWidget(self.savePortlistBtn)
48 | self.horizontalLayout.addLayout(self.verticalLayout_3)
49 | self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
50 | self.autoconnectCBox = QtWidgets.QCheckBox(Dialog)
51 | self.autoconnectCBox.setObjectName("autoconnectCBox")
52 | self.gridLayout.addWidget(self.autoconnectCBox, 1, 0, 1, 1)
53 |
54 | self.retranslateUi(Dialog)
55 | QtCore.QMetaObject.connectSlotsByName(Dialog)
56 |
57 | def retranslateUi(self, Dialog):
58 | _translate = QtCore.QCoreApplication.translate
59 | Dialog.setWindowTitle(_translate("Dialog", "Output Ports"))
60 | self.addPortBtn.setText(_translate("Dialog", "Add Port"))
61 | self.removePortBtn.setText(_translate("Dialog", "Remove Port"))
62 | self.loadPortlistBtn.setText(_translate("Dialog", "Load Portlist"))
63 | self.savePortlistBtn.setText(_translate("Dialog", "Save Portlist"))
64 | self.autoconnectCBox.setText(_translate("Dialog", "Autoconnect main output ports on program start"))
65 | import gui_rc
66 |
--------------------------------------------------------------------------------
/superboucle/port_manager_ui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 370
10 | 308
11 |
12 |
13 |
14 | Output Ports
15 |
16 |
17 |
18 | :/icons/icons/icon.png:/icons/icons/icon.png
19 |
20 |
21 | -
22 |
23 |
24 | QLayout::SetNoConstraint
25 |
26 |
-
27 |
28 |
29 |
30 | 16777215
31 | 16777215
32 |
33 |
34 |
35 |
36 | 100
37 | 100
38 |
39 |
40 |
41 | QListView::Static
42 |
43 |
44 | QListView::Adjust
45 |
46 |
47 |
48 | -
49 |
50 |
-
51 |
52 |
53 | Add Port
54 |
55 |
56 |
57 | -
58 |
59 |
60 | Remove Port
61 |
62 |
63 |
64 | -
65 |
66 |
67 | Qt::Vertical
68 |
69 |
70 |
71 | 20
72 | 40
73 |
74 |
75 |
76 |
77 | -
78 |
79 |
80 | Load Portlist
81 |
82 |
83 |
84 | -
85 |
86 |
87 | Save Portlist
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | -
96 |
97 |
98 | Autoconnect main output ports on program start
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/superboucle/qsuperdial.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtWidgets import QDial
2 | from PyQt5.QtGui import QPainter, QColor, QPen, QBrush
3 | from PyQt5.QtCore import Qt, QPointF
4 | from math import pi, sin, cos
5 |
6 |
7 | class QSuperDial(QDial):
8 | """Overload QDial with correct stylesheet support
9 |
10 | QSuperDial support background-color and color stylesheet
11 | properties and do NOT add "shadow"
12 |
13 | QSuperDial draw ellipse if width and height are different
14 | """
15 |
16 | _degree270 = 1.5 * pi
17 | _degree225 = 1.25 * pi
18 |
19 | def __init__(self, parent, knobRadius=5, knobMargin=5):
20 | super(QSuperDial, self).__init__(parent)
21 | self.knobRadius = knobRadius
22 | self.knobMargin = knobMargin
23 | self.setRange(0, 100)
24 |
25 | def paintEvent(self, event):
26 | # From Peter, thanks !
27 | # http://thecodeinn.blogspot.fr/2015/02/customizing-qdials-in-qt-part-1.html
28 |
29 | painter = QPainter(self)
30 |
31 | # So that we can use the background color
32 | painter.setBackgroundMode(1)
33 |
34 | # Smooth out the circle
35 | painter.setRenderHint(QPainter.Antialiasing)
36 |
37 | # Use background color
38 | painter.setBrush(painter.background())
39 |
40 | # Store color from stylesheet, pen will be overriden
41 | pointColor = QColor(painter.pen().color())
42 |
43 | # No border
44 | painter.setPen(QPen(Qt.NoPen))
45 |
46 | # Draw first circle
47 | painter.drawEllipse(0, 0, self.width(), self.height())
48 |
49 | # Reset color to pointColor from stylesheet
50 | painter.setBrush(QBrush(pointColor))
51 |
52 | # Get ratio between current value and maximum to calculate angle
53 | ratio = self.value() / self.maximum()
54 |
55 | # The maximum amount of degrees is 270, offset by 225
56 | angle = ratio * self._degree270 - self._degree225
57 |
58 | # Radius of background circle
59 | rx = self.width() / 2
60 | ry = self.height() / 2
61 |
62 | # Add r to have (0,0) in center of dial
63 | y = sin(angle) * (ry - self.knobRadius - self.knobMargin) + ry
64 | x = cos(angle) * (rx - self.knobRadius - self.knobMargin) + rx
65 |
66 | # Draw the ellipse
67 | painter.drawEllipse(QPointF(x, y),
68 | self.knobRadius,
69 | self.knobRadius)
70 |
--------------------------------------------------------------------------------
/superboucle/qtmodern/__init__.py:
--------------------------------------------------------------------------------
1 | __version__ = '0.2.0'
2 | """ str: Package version. """
3 |
--------------------------------------------------------------------------------
/superboucle/qtmodern/_utils.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from os.path import join, dirname, abspath
3 | import qtpy
4 | import platform
5 |
6 | QT_VERSION = tuple(int(v) for v in qtpy.QT_VERSION.split('.'))
7 | """ tuple: Qt version. """
8 |
9 | PLATFORM = platform.system()
10 |
11 |
12 | def resource_path(relative_path):
13 | if hasattr(sys, '_MEIPASS'):
14 | return join(sys._MEIPASS, dirname(abspath(__file__)), relative_path)
15 | return join(dirname(abspath(__file__)), relative_path)
16 |
--------------------------------------------------------------------------------
/superboucle/qtmodern/info:
--------------------------------------------------------------------------------
1 | theme for SpinTool
2 |
--------------------------------------------------------------------------------
/superboucle/qtmodern/resources/frameless.qss:
--------------------------------------------------------------------------------
1 | #windowFrame {
2 | border-radius: 5px 5px 5px 5px;
3 | background-color: palette(Window);
4 | }
5 |
6 | #titleBar {
7 | border: 0px none palette(base);
8 | border-top-left-radius: 5px;
9 | border-top-right-radius: 5px;
10 | background-color: palette(Window);
11 | height: 24px;
12 | }
13 |
14 | #btnClose, #btnRestore, #btnMaximize, #btnMinimize {
15 | min-width: 14px;
16 | min-height: 14px;
17 | max-width: 14px;
18 | max-height: 14px;
19 | border-radius: 7px;
20 | margin: 4px;
21 | }
22 |
23 | #btnRestore, #btnMaximize {
24 | background-color: hsv(123, 204, 198);
25 | }
26 |
27 | #btnRestore::hover, #btnMaximize::hover {
28 | background-color: hsv(123, 204, 148);
29 | }
30 |
31 | #btnRestore::pressed, #btnMaximize::pressed {
32 | background-color: hsv(123, 204, 98);
33 | }
34 |
35 | #btnMinimize {
36 | background-color: hsv(38, 218, 253);
37 | }
38 |
39 | #btnMinimize::hover {
40 | background-color: hsv(38, 218, 203);
41 | }
42 |
43 | #btnMinimize::pressed {
44 | background-color: hsv(38, 218, 153);
45 | }
46 |
47 | #btnClose {
48 | background-color: hsv(0, 182, 252);
49 | }
50 |
51 | #btnClose::hover {
52 | background-color: hsv(0, 182, 202);
53 | }
54 |
55 | #btnClose::pressed {
56 | background-color: hsv(0, 182, 152);
57 | }
58 |
59 | #btnClose::disabled, #btnRestore::disabled, #btnMaximize::disabled, #btnMinimize::disabled {
60 | background-color: palette(midlight);
61 | }
62 |
--------------------------------------------------------------------------------
/superboucle/qtmodern/resources/info:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/superboucle/qtmodern/resources/style (copy).qss:
--------------------------------------------------------------------------------
1 | /*
2 | * QGroupBox
3 | */
4 |
5 | QGroupBox {
6 | background-color: palette(alternate-base);
7 | border: 1px solid palette(midlight);
8 | margin-top: 25px;
9 | }
10 |
11 | QGroupBox::title {
12 | background-color: transparent;
13 | }
14 |
15 | /*
16 | * QToolBar
17 | */
18 |
19 | QToolBar {
20 | border: none;
21 | }
22 |
23 | /*
24 | * QTabBar
25 | */
26 |
27 | QTabBar{
28 | background-color: transparent;
29 | }
30 |
31 | QTabBar::tab{
32 | padding: 4px 6px;
33 | background-color: transparent;
34 | border-bottom: 2px solid transparent;
35 | }
36 |
37 | QTabBar::tab:selected, QTabBar::tab:hover {
38 | color: palette(text);
39 | border-bottom: 2px solid palette(highlight);
40 | }
41 |
42 | QTabBar::tab:selected:disabled {
43 | border-bottom: 2px solid palette(light);
44 | }
45 |
46 | /*
47 | * QScrollBar
48 | */
49 |
50 | QScrollBar:vertical {
51 | background: palette(base);
52 | border-top-right-radius: 2px;
53 | border-bottom-right-radius: 2px;
54 | width: 16px;
55 | margin: 0px;
56 | }
57 |
58 | QScrollBar::handle:vertical {
59 | background-color: palette(midlight);
60 | border-radius: 2px;
61 | min-height: 20px;
62 | margin: 2px 4px 2px 4px;
63 | }
64 |
65 | QScrollBar::handle:vertical:hover, QScrollBar::handle:horizontal:hover, QScrollBar::handle:vertical:pressed, QScrollBar::handle:horizontal:pressed {
66 | background-color:palette(highlight);
67 | }
68 |
69 | QScrollBar::add-line:vertical {
70 | background: none;
71 | height: 0px;
72 | subcontrol-position: right;
73 | subcontrol-origin: margin;
74 | }
75 |
76 | QScrollBar::sub-line:vertical {
77 | background: none;
78 | height: 0px;
79 | subcontrol-position: left;
80 | subcontrol-origin: margin;
81 | }
82 |
83 | QScrollBar:horizontal{
84 | background: palette(base);
85 | height: 16px;
86 | margin: 0px;
87 | }
88 |
89 | QScrollBar::handle:horizontal {
90 | background-color: palette(midlight);
91 | border-radius: 2px;
92 | min-width: 20px;
93 | margin: 4px 2px 4px 2px;
94 | }
95 |
96 |
97 | QScrollBar::add-line:horizontal {
98 | background: none;
99 | width: 0px;
100 | subcontrol-position: bottom;
101 | subcontrol-origin: margin;
102 | }
103 |
104 | QScrollBar::sub-line:horizontal {
105 | background: none;
106 | width: 0px;
107 | subcontrol-position: top;
108 | subcontrol-origin: margin;
109 | }
110 |
111 | /*
112 | * QScrollArea
113 | */
114 |
115 | QScrollArea {
116 | border-style: none;
117 | }
118 |
119 | QScrollArea > QWidget > QWidget {
120 | background-color: palette(alternate-base);
121 | }
122 |
123 | /*
124 | * QSlider
125 | */
126 |
127 | QSlider::handle:horizontal {
128 | border-radius: 5px;
129 | background-color: palette(light);
130 | max-height: 20px;
131 | }
132 |
133 | QSlider::add-page:horizontal {
134 | background: palette(base);
135 | }
136 |
137 | QSlider::sub-page:horizontal {
138 | background: palette(highlight);
139 | }
140 |
141 | QSlider::sub-page:horizontal:disabled {
142 | background-color: palette(light);
143 | }
144 |
145 | QTableView {
146 | background-color: palette(link-visited);
147 | alternate-background-color: palette(midlight);
148 | }
149 |
--------------------------------------------------------------------------------
/superboucle/qtmodern/resources/style.qss:
--------------------------------------------------------------------------------
1 | /*
2 | * QGroupBox
3 | */
4 |
5 | QGroupBox {
6 | background-color: palette(alternate-base);
7 | border: 1px solid palette(midlight);
8 | margin-top: 25px;
9 | }
10 |
11 | QGroupBox::title {
12 | background-color: transparent;
13 | }
14 |
15 | /*
16 | * QToolBar
17 | */
18 |
19 | QToolBar {
20 | border: none;
21 | }
22 |
23 | /*
24 | * QTabBar
25 | */
26 |
27 | QTabBar{
28 | background-color: transparent;
29 | }
30 |
31 | QTabBar::tab{
32 | padding: 4px 6px;
33 | background-color: transparent;
34 | border-bottom: 2px solid transparent;
35 | }
36 |
37 | QTabBar::tab:selected, QTabBar::tab:hover {
38 | color: palette(text);
39 | border-bottom: 2px solid palette(highlight);
40 | }
41 |
42 | QTabBar::tab:selected:disabled {
43 | border-bottom: 2px solid palette(light);
44 | }
45 |
46 | /*
47 | * QScrollBar
48 | */
49 |
50 | QScrollBar:vertical {
51 | background: palette(base);
52 | border-top-right-radius: 2px;
53 | border-bottom-right-radius: 2px;
54 | width: 16px;
55 | margin: 0px;
56 | }
57 |
58 | QScrollBar::handle:vertical {
59 | background-color: palette(midlight);
60 | border-radius: 2px;
61 | min-height: 20px;
62 | margin: 2px 4px 2px 4px;
63 | }
64 |
65 | QScrollBar::handle:vertical:hover, QScrollBar::handle:horizontal:hover, QScrollBar::handle:vertical:pressed, QScrollBar::handle:horizontal:pressed {
66 | background-color:palette(highlight);
67 | }
68 |
69 | QScrollBar::add-line:vertical {
70 | background: none;
71 | height: 0px;
72 | subcontrol-position: right;
73 | subcontrol-origin: margin;
74 | }
75 |
76 | QScrollBar::sub-line:vertical {
77 | background: none;
78 | height: 0px;
79 | subcontrol-position: left;
80 | subcontrol-origin: margin;
81 | }
82 |
83 | QScrollBar:horizontal{
84 | background: palette(base);
85 | height: 16px;
86 | margin: 0px;
87 | }
88 |
89 | QScrollBar::handle:horizontal {
90 | background-color: palette(midlight);
91 | border-radius: 2px;
92 | min-width: 20px;
93 | margin: 4px 2px 4px 2px;
94 | }
95 |
96 |
97 | QScrollBar::add-line:horizontal {
98 | background: none;
99 | width: 0px;
100 | subcontrol-position: bottom;
101 | subcontrol-origin: margin;
102 | }
103 |
104 | QScrollBar::sub-line:horizontal {
105 | background: none;
106 | width: 0px;
107 | subcontrol-position: top;
108 | subcontrol-origin: margin;
109 | }
110 |
111 | /*
112 | * QScrollArea
113 | */
114 |
115 | QScrollArea {
116 | border-style: none;
117 | }
118 |
119 | QScrollArea > QWidget > QWidget {
120 | background-color: palette(alternate-base);
121 | }
122 |
123 | /*
124 | * QSlider
125 | */
126 |
127 | QSlider::handle:horizontal {
128 | border-radius: 5px;
129 | background-color: palette(light);
130 | max-height: 20px;
131 | }
132 |
133 | QSlider::add-page:horizontal {
134 | background: palette(base);
135 | }
136 |
137 | QSlider::sub-page:horizontal {
138 | background: palette(highlight);
139 | }
140 |
141 | QSlider::sub-page:horizontal:disabled {
142 | background-color: palette(light);
143 | }
144 |
145 | QTableView {
146 | background-color: palette(link-visited);
147 | alternate-background-color: palette(midlight);
148 | }
149 |
--------------------------------------------------------------------------------
/superboucle/qtmodern/styles (copy).py:
--------------------------------------------------------------------------------
1 | from qtpy.QtGui import QPalette, QColor
2 | from ._utils import QT_VERSION, resource_path
3 |
4 | _STYLESHEET = resource_path('resources/style.qss')
5 | """ str: Main stylesheet. """
6 |
7 |
8 | def _apply_base_theme(app):
9 | """ Apply base theme to the application.
10 |
11 | Args:
12 | app (QApplication): QApplication instance.
13 | """
14 |
15 | if QT_VERSION < (5,):
16 | app.setStyle('plastique')
17 | else:
18 | app.setStyle('Fusion')
19 |
20 | with open(_STYLESHEET) as stylesheet:
21 | app.setStyleSheet(stylesheet.read())
22 |
23 |
24 | def dark(app):
25 | """ Apply Dark Theme to the Qt application instance.
26 |
27 | Args:
28 | app (QApplication): QApplication instance.
29 | """
30 |
31 | darkPalette = QPalette()
32 |
33 | # base
34 | darkPalette.setColor(QPalette.WindowText, QColor(180, 180, 180))
35 | darkPalette.setColor(QPalette.Button, QColor(53, 53, 53))
36 | darkPalette.setColor(QPalette.Light, QColor(180, 180, 180))
37 | darkPalette.setColor(QPalette.Midlight, QColor(90, 90, 90))
38 | darkPalette.setColor(QPalette.Dark, QColor(35, 35, 35))
39 | darkPalette.setColor(QPalette.Text, QColor(180, 180, 180))
40 | darkPalette.setColor(QPalette.BrightText, QColor(180, 180, 180))
41 | darkPalette.setColor(QPalette.ButtonText, QColor(180, 180, 180))
42 | darkPalette.setColor(QPalette.Base, QColor(42, 42, 42))
43 | darkPalette.setColor(QPalette.Window, QColor(53, 53, 53))
44 | darkPalette.setColor(QPalette.Shadow, QColor(20, 20, 20))
45 | darkPalette.setColor(QPalette.Highlight, QColor(42, 130, 218))
46 | darkPalette.setColor(QPalette.HighlightedText, QColor(180, 180, 180))
47 | darkPalette.setColor(QPalette.Link, QColor(56, 252, 196))
48 | darkPalette.setColor(QPalette.AlternateBase, QColor(66, 66, 66))
49 | darkPalette.setColor(QPalette.ToolTipBase, QColor(53, 53, 53))
50 | darkPalette.setColor(QPalette.ToolTipText, QColor(180, 180, 180))
51 | darkPalette.setColor(QPalette.LinkVisited, QColor(80, 80, 80))
52 |
53 | # disabled
54 | darkPalette.setColor(QPalette.Disabled, QPalette.WindowText,
55 | QColor(127, 127, 127))
56 | darkPalette.setColor(QPalette.Disabled, QPalette.Text,
57 | QColor(127, 127, 127))
58 | darkPalette.setColor(QPalette.Disabled, QPalette.ButtonText,
59 | QColor(127, 127, 127))
60 | darkPalette.setColor(QPalette.Disabled, QPalette.Highlight,
61 | QColor(80, 80, 80))
62 | darkPalette.setColor(QPalette.Disabled, QPalette.HighlightedText,
63 | QColor(127, 127, 127))
64 |
65 | app.setPalette(darkPalette)
66 |
67 | _apply_base_theme(app)
68 |
69 |
70 | def light(app):
71 | """ Apply Light Theme to the Qt application instance.
72 |
73 | Args:
74 | app (QApplication): QApplication instance.
75 | """
76 |
77 | lightPalette = QPalette()
78 |
79 | # base
80 | lightPalette.setColor(QPalette.WindowText, QColor(0, 0, 0))
81 | lightPalette.setColor(QPalette.Button, QColor(240, 240, 240))
82 | lightPalette.setColor(QPalette.Light, QColor(180, 180, 180))
83 | lightPalette.setColor(QPalette.Midlight, QColor(200, 200, 200))
84 | lightPalette.setColor(QPalette.Dark, QColor(225, 225, 225))
85 | lightPalette.setColor(QPalette.Text, QColor(0, 0, 0))
86 | lightPalette.setColor(QPalette.BrightText, QColor(0, 0, 0))
87 | lightPalette.setColor(QPalette.ButtonText, QColor(0, 0, 0))
88 | lightPalette.setColor(QPalette.Base, QColor(237, 237, 237))
89 | lightPalette.setColor(QPalette.Window, QColor(240, 240, 240))
90 | lightPalette.setColor(QPalette.Shadow, QColor(20, 20, 20))
91 | lightPalette.setColor(QPalette.Highlight, QColor(76, 163, 224))
92 | lightPalette.setColor(QPalette.HighlightedText, QColor(0, 0, 0))
93 | lightPalette.setColor(QPalette.Link, QColor(0, 162, 232))
94 | lightPalette.setColor(QPalette.AlternateBase, QColor(225, 225, 225))
95 | lightPalette.setColor(QPalette.ToolTipBase, QColor(240, 240, 240))
96 | lightPalette.setColor(QPalette.ToolTipText, QColor(0, 0, 0))
97 | lightPalette.setColor(QPalette.LinkVisited, QColor(222, 222, 222))
98 |
99 | # disabled
100 | lightPalette.setColor(QPalette.Disabled, QPalette.WindowText,
101 | QColor(115, 115, 115))
102 | lightPalette.setColor(QPalette.Disabled, QPalette.Text,
103 | QColor(115, 115, 115))
104 | lightPalette.setColor(QPalette.Disabled, QPalette.ButtonText,
105 | QColor(115, 115, 115))
106 | lightPalette.setColor(QPalette.Disabled, QPalette.Highlight,
107 | QColor(190, 190, 190))
108 | lightPalette.setColor(QPalette.Disabled, QPalette.HighlightedText,
109 | QColor(115, 115, 115))
110 |
111 | app.setPalette(lightPalette)
112 |
113 | _apply_base_theme(app)
114 |
115 |
--------------------------------------------------------------------------------
/superboucle/qtmodern/styles.py:
--------------------------------------------------------------------------------
1 | from qtpy.QtGui import QPalette, QColor
2 | from ._utils import QT_VERSION, resource_path
3 |
4 | _STYLESHEET = resource_path('resources/style.qss')
5 | """ str: Main stylesheet. """
6 |
7 |
8 | def _apply_base_theme(app):
9 | """ Apply base theme to the application.
10 |
11 | Args:
12 | app (QApplication): QApplication instance.
13 | """
14 |
15 | if QT_VERSION < (5,):
16 | app.setStyle('plastique')
17 | else:
18 | app.setStyle('Fusion')
19 |
20 | with open(_STYLESHEET) as stylesheet:
21 | app.setStyleSheet(stylesheet.read())
22 |
23 |
24 | def dark(app):
25 | """ Apply Dark Theme to the Qt application instance.
26 |
27 | Args:
28 | app (QApplication): QApplication instance.
29 | """
30 |
31 | darkPalette = QPalette()
32 |
33 | # base
34 | darkPalette.setColor(QPalette.WindowText, QColor(180, 180, 180))
35 | darkPalette.setColor(QPalette.Button, QColor(53, 53, 53))
36 | darkPalette.setColor(QPalette.Light, QColor(180, 180, 180))
37 | darkPalette.setColor(QPalette.Midlight, QColor(90, 90, 90))
38 | darkPalette.setColor(QPalette.Dark, QColor(35, 35, 35))
39 | darkPalette.setColor(QPalette.Text, QColor(180, 180, 180))
40 | darkPalette.setColor(QPalette.BrightText, QColor(180, 180, 180))
41 | darkPalette.setColor(QPalette.ButtonText, QColor(180, 180, 180))
42 | darkPalette.setColor(QPalette.Base, QColor(42, 42, 42))
43 |
44 | darkPalette.setColor(QPalette.Window, QColor(53, 53, 53))
45 | #darkPalette.setColor(QPalette.Window, QColor(66, 66, 66))
46 |
47 | darkPalette.setColor(QPalette.Shadow, QColor(20, 20, 20))
48 | darkPalette.setColor(QPalette.Highlight, QColor(42, 130, 218))
49 | darkPalette.setColor(QPalette.HighlightedText, QColor(180, 180, 180))
50 | darkPalette.setColor(QPalette.Link, QColor(56, 252, 196))
51 | darkPalette.setColor(QPalette.AlternateBase, QColor(66, 66, 66))
52 | darkPalette.setColor(QPalette.ToolTipBase, QColor(53, 53, 53))
53 | darkPalette.setColor(QPalette.ToolTipText, QColor(180, 180, 180))
54 | darkPalette.setColor(QPalette.LinkVisited, QColor(80, 80, 80))
55 |
56 | # disabled
57 | darkPalette.setColor(QPalette.Disabled, QPalette.WindowText,
58 | QColor(127, 127, 127))
59 | darkPalette.setColor(QPalette.Disabled, QPalette.Text,
60 | QColor(127, 127, 127))
61 | darkPalette.setColor(QPalette.Disabled, QPalette.ButtonText,
62 | QColor(127, 127, 127))
63 | darkPalette.setColor(QPalette.Disabled, QPalette.Highlight,
64 | QColor(80, 80, 80))
65 | darkPalette.setColor(QPalette.Disabled, QPalette.HighlightedText,
66 | QColor(127, 127, 127))
67 |
68 | app.setPalette(darkPalette)
69 |
70 | _apply_base_theme(app)
71 |
72 |
73 | def light(app):
74 | """ Apply Light Theme to the Qt application instance.
75 |
76 | Args:
77 | app (QApplication): QApplication instance.
78 | """
79 |
80 | lightPalette = QPalette()
81 |
82 | # base
83 | lightPalette.setColor(QPalette.WindowText, QColor(0, 0, 0))
84 | lightPalette.setColor(QPalette.Button, QColor(240, 240, 240))
85 | lightPalette.setColor(QPalette.Light, QColor(180, 180, 180))
86 | lightPalette.setColor(QPalette.Midlight, QColor(200, 200, 200))
87 | lightPalette.setColor(QPalette.Dark, QColor(225, 225, 225))
88 | lightPalette.setColor(QPalette.Text, QColor(0, 0, 0))
89 | lightPalette.setColor(QPalette.BrightText, QColor(0, 0, 0))
90 | lightPalette.setColor(QPalette.ButtonText, QColor(0, 0, 0))
91 | lightPalette.setColor(QPalette.Base, QColor(237, 237, 237))
92 | lightPalette.setColor(QPalette.Window, QColor(240, 240, 240))
93 | lightPalette.setColor(QPalette.Shadow, QColor(20, 20, 20))
94 | lightPalette.setColor(QPalette.Highlight, QColor(76, 163, 224))
95 | lightPalette.setColor(QPalette.HighlightedText, QColor(0, 0, 0))
96 | lightPalette.setColor(QPalette.Link, QColor(0, 162, 232))
97 | lightPalette.setColor(QPalette.AlternateBase, QColor(225, 225, 225))
98 | lightPalette.setColor(QPalette.ToolTipBase, QColor(240, 240, 240))
99 | lightPalette.setColor(QPalette.ToolTipText, QColor(0, 0, 0))
100 | lightPalette.setColor(QPalette.LinkVisited, QColor(222, 222, 222))
101 |
102 | # disabled
103 | lightPalette.setColor(QPalette.Disabled, QPalette.WindowText,
104 | QColor(115, 115, 115))
105 | lightPalette.setColor(QPalette.Disabled, QPalette.Text,
106 | QColor(115, 115, 115))
107 | lightPalette.setColor(QPalette.Disabled, QPalette.ButtonText,
108 | QColor(115, 115, 115))
109 | lightPalette.setColor(QPalette.Disabled, QPalette.Highlight,
110 | QColor(190, 190, 190))
111 | lightPalette.setColor(QPalette.Disabled, QPalette.HighlightedText,
112 | QColor(115, 115, 115))
113 |
114 | app.setPalette(lightPalette)
115 |
116 | _apply_base_theme(app)
117 |
118 |
--------------------------------------------------------------------------------
/superboucle/scene_manager_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file '/home/manu/Sviluppo/SpinTool/superboucle/scene_manager_ui.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.14.1
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 |
10 | from PyQt5 import QtCore, QtGui, QtWidgets
11 |
12 |
13 | class Ui_Dialog(object):
14 | def setupUi(self, Dialog):
15 | Dialog.setObjectName("Dialog")
16 | Dialog.resize(320, 333)
17 | icon = QtGui.QIcon()
18 | icon.addPixmap(QtGui.QPixmap(":/icons/icons/icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
19 | Dialog.setWindowIcon(icon)
20 | self.gridLayout = QtWidgets.QGridLayout(Dialog)
21 | self.gridLayout.setObjectName("gridLayout")
22 | self.horizontalLayout = QtWidgets.QHBoxLayout()
23 | self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetNoConstraint)
24 | self.horizontalLayout.setObjectName("horizontalLayout")
25 | self.scenelistList = QtWidgets.QListWidget(Dialog)
26 | self.scenelistList.setMaximumSize(QtCore.QSize(16777215, 16777215))
27 | self.scenelistList.setSizeIncrement(QtCore.QSize(100, 100))
28 | self.scenelistList.setMovement(QtWidgets.QListView.Static)
29 | self.scenelistList.setResizeMode(QtWidgets.QListView.Adjust)
30 | self.scenelistList.setObjectName("scenelistList")
31 | self.horizontalLayout.addWidget(self.scenelistList)
32 | self.verticalLayout_3 = QtWidgets.QVBoxLayout()
33 | self.verticalLayout_3.setObjectName("verticalLayout_3")
34 | self.loadScenesBtn = QtWidgets.QPushButton(Dialog)
35 | self.loadScenesBtn.setObjectName("loadScenesBtn")
36 | self.verticalLayout_3.addWidget(self.loadScenesBtn)
37 | self.addScenesBtn = QtWidgets.QPushButton(Dialog)
38 | self.addScenesBtn.setObjectName("addScenesBtn")
39 | self.verticalLayout_3.addWidget(self.addScenesBtn)
40 | self.removeScenesBtn = QtWidgets.QPushButton(Dialog)
41 | self.removeScenesBtn.setObjectName("removeScenesBtn")
42 | self.verticalLayout_3.addWidget(self.removeScenesBtn)
43 | self.renameSceneBtn = QtWidgets.QPushButton(Dialog)
44 | self.renameSceneBtn.setObjectName("renameSceneBtn")
45 | self.verticalLayout_3.addWidget(self.renameSceneBtn)
46 | self.preview = QtWidgets.QGridLayout()
47 | self.preview.setSpacing(2)
48 | self.preview.setObjectName("preview")
49 | self.verticalLayout_3.addLayout(self.preview)
50 | spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
51 | self.verticalLayout_3.addItem(spacerItem)
52 | self.setInitialSceneBtn = QtWidgets.QPushButton(Dialog)
53 | self.setInitialSceneBtn.setObjectName("setInitialSceneBtn")
54 | self.verticalLayout_3.addWidget(self.setInitialSceneBtn)
55 | self.horizontalLayout.addLayout(self.verticalLayout_3)
56 | self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
57 | self.cBoxBigFonts = QtWidgets.QCheckBox(Dialog)
58 | self.cBoxBigFonts.setObjectName("cBoxBigFonts")
59 | self.gridLayout.addWidget(self.cBoxBigFonts, 1, 0, 1, 1)
60 |
61 | self.retranslateUi(Dialog)
62 | QtCore.QMetaObject.connectSlotsByName(Dialog)
63 |
64 | def retranslateUi(self, Dialog):
65 | _translate = QtCore.QCoreApplication.translate
66 | Dialog.setWindowTitle(_translate("Dialog", "Scenes"))
67 | self.loadScenesBtn.setText(_translate("Dialog", "Trigger Scene"))
68 | self.addScenesBtn.setText(_translate("Dialog", "Add Scene"))
69 | self.removeScenesBtn.setText(_translate("Dialog", "Delete Scene"))
70 | self.renameSceneBtn.setText(_translate("Dialog", "Rename Scene"))
71 | self.setInitialSceneBtn.setText(_translate("Dialog", "Set initial Scene"))
72 | self.cBoxBigFonts.setText(_translate("Dialog", "Use custom font size"))
73 | import gui_rc
74 |
--------------------------------------------------------------------------------
/superboucle/scene_manager_ui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 320
10 | 333
11 |
12 |
13 |
14 | Scenes
15 |
16 |
17 |
18 | :/icons/icons/icon.png:/icons/icons/icon.png
19 |
20 |
21 | -
22 |
23 |
24 | QLayout::SetNoConstraint
25 |
26 |
-
27 |
28 |
29 |
30 | 16777215
31 | 16777215
32 |
33 |
34 |
35 |
36 | 100
37 | 100
38 |
39 |
40 |
41 | QListView::Static
42 |
43 |
44 | QListView::Adjust
45 |
46 |
47 |
48 | -
49 |
50 |
-
51 |
52 |
53 | Trigger Scene
54 |
55 |
56 |
57 | -
58 |
59 |
60 | Add Scene
61 |
62 |
63 |
64 | -
65 |
66 |
67 | Delete Scene
68 |
69 |
70 |
71 | -
72 |
73 |
74 | Rename Scene
75 |
76 |
77 |
78 | -
79 |
80 |
81 | 2
82 |
83 |
84 |
85 | -
86 |
87 |
88 | Qt::Vertical
89 |
90 |
91 |
92 | 20
93 | 40
94 |
95 |
96 |
97 |
98 | -
99 |
100 |
101 | Set initial Scene
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | -
110 |
111 |
112 | Use custom font size
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/superboucle/settings.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manucontrovento/SpinTool/9664552342d742f1747022cf06d93d14fcc83ce3/superboucle/settings.pyc
--------------------------------------------------------------------------------
/superboucle/song_annotation.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtWidgets import QDialog
2 | from superboucle.song_annotation_ui import Ui_Dialog
3 | import copy
4 | import settings
5 |
6 | class SongAnnotation(QDialog, Ui_Dialog):
7 |
8 | def __init__(self, parent):
9 | super(SongAnnotation, self).__init__(parent)
10 | self.gui = parent
11 | self.setupUi(self)
12 | self.txtAnnotation.clear()
13 | self.txtAnnotation.setText(self.gui.song.annotation)
14 | self.txtAnnotation.textChanged.connect(self.onTextChanged)
15 |
16 | self.setLayout(self.formLayout)
17 |
18 | if settings.song_annotation_geometry:
19 | self.restoreGeometry(settings.song_annotation_geometry)
20 |
21 | self.show()
22 |
23 | # Saving window position
24 |
25 | def onTextChanged(self):
26 | self.gui.song.annotation = str(self.txtAnnotation.toPlainText())
27 |
28 | def moveEvent(self, event):
29 | self.geometry = self.saveGeometry()
30 | settings.song_annotation_geometry = copy.deepcopy(self.geometry)
31 |
32 | def updateText(self, text):
33 | self.txtAnnotation.setText(text)
34 |
35 | def hideEvent(self, event):
36 | self.onHide()
37 |
38 | def onHide(self):
39 | self.gui.song.annotation = str(self.txtAnnotation.toPlainText())
40 | self.gui.action_SongAnnotation.setEnabled(True)
41 |
42 | def onFinished(self):
43 | pass
44 |
--------------------------------------------------------------------------------
/superboucle/song_annotation_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file '/home/manu/Applicazioni/SpinTool/spintool/song_annotation_ui.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.12.3
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 |
10 | from PyQt5 import QtCore, QtGui, QtWidgets
11 |
12 |
13 | class Ui_Dialog(object):
14 | def setupUi(self, Dialog):
15 | Dialog.setObjectName("Dialog")
16 | Dialog.setWindowModality(QtCore.Qt.NonModal)
17 | Dialog.resize(421, 372)
18 | icon = QtGui.QIcon()
19 | icon.addPixmap(QtGui.QPixmap(":/icons/icons/icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
20 | Dialog.setWindowIcon(icon)
21 | Dialog.setStyleSheet("background-color: rgb(255, 255, 170);")
22 | self.formLayoutWidget = QtWidgets.QWidget(Dialog)
23 | self.formLayoutWidget.setGeometry(QtCore.QRect(10, 10, 401, 351))
24 | self.formLayoutWidget.setObjectName("formLayoutWidget")
25 | self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget)
26 | self.formLayout.setFieldGrowthPolicy(QtWidgets.QFormLayout.ExpandingFieldsGrow)
27 | self.formLayout.setRowWrapPolicy(QtWidgets.QFormLayout.WrapLongRows)
28 | self.formLayout.setFormAlignment(QtCore.Qt.AlignCenter)
29 | self.formLayout.setContentsMargins(2, 2, 2, 2)
30 | self.formLayout.setObjectName("formLayout")
31 | self.txtAnnotation = QtWidgets.QTextBrowser(self.formLayoutWidget)
32 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
33 | sizePolicy.setHorizontalStretch(1)
34 | sizePolicy.setVerticalStretch(1)
35 | sizePolicy.setHeightForWidth(self.txtAnnotation.sizePolicy().hasHeightForWidth())
36 | self.txtAnnotation.setSizePolicy(sizePolicy)
37 | self.txtAnnotation.setStyleSheet("color: rgb(0, 0, 0);\n"
38 | "background-color: rgb(255, 255, 170);\n"
39 | "font: 11pt \"Noto Sans\";\n"
40 | "border: None;")
41 | self.txtAnnotation.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
42 | self.txtAnnotation.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
43 | self.txtAnnotation.setDocumentTitle("")
44 | self.txtAnnotation.setReadOnly(False)
45 | self.txtAnnotation.setAcceptRichText(True)
46 | self.txtAnnotation.setObjectName("txtAnnotation")
47 | self.formLayout.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.txtAnnotation)
48 |
49 | self.retranslateUi(Dialog)
50 | QtCore.QMetaObject.connectSlotsByName(Dialog)
51 |
52 | def retranslateUi(self, Dialog):
53 | _translate = QtCore.QCoreApplication.translate
54 | Dialog.setWindowTitle(_translate("Dialog", "Song annotation"))
55 | self.txtAnnotation.setHtml(_translate("Dialog", "\n"
56 | "\n"
59 | "
"))
60 | import gui_rc
61 |
--------------------------------------------------------------------------------
/superboucle/song_annotation_ui.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialog
4 |
5 |
6 | Qt::NonModal
7 |
8 |
9 |
10 | 0
11 | 0
12 | 421
13 | 372
14 |
15 |
16 |
17 | Song annotation
18 |
19 |
20 |
21 | :/icons/icons/icon.png:/icons/icons/icon.png
22 |
23 |
24 | background-color: rgb(255, 255, 170);
25 |
26 |
27 |
28 |
29 | 10
30 | 10
31 | 401
32 | 351
33 |
34 |
35 |
36 |
37 | QFormLayout::ExpandingFieldsGrow
38 |
39 |
40 | QFormLayout::WrapLongRows
41 |
42 |
43 | Qt::AlignCenter
44 |
45 |
46 | 2
47 |
48 |
49 | 2
50 |
51 |
52 | 2
53 |
54 |
55 | 2
56 |
57 | -
58 |
59 |
60 |
61 | 1
62 | 1
63 |
64 |
65 |
66 | color: rgb(0, 0, 0);
67 | background-color: rgb(255, 255, 170);
68 | font: 11pt "Noto Sans";
69 | border: None;
70 |
71 |
72 | Qt::ScrollBarAlwaysOn
73 |
74 |
75 | Qt::ScrollBarAlwaysOff
76 |
77 |
78 |
79 |
80 |
81 | false
82 |
83 |
84 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
85 | <html><head><meta name="qrichtext" content="1" /><style type="text/css">
86 | p, li { white-space: pre-wrap; }
87 | </style></head><body style=" font-family:'Noto Sans'; font-size:11pt; font-weight:400; font-style:normal;">
88 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;"><br /></p></body></html>
89 |
90 |
91 | true
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------