Exemple #1
0
class HarmonicLevels(QWidget, ProcessorUpdater):
    def __init__(self):
        super().__init__()
        self._editor = HarmonicLevelsList()
        self.add_to_updaters(self._editor)

        self._header = HeaderLine('Harmonic levels')

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._header)
        v.addWidget(self._editor)
        self.setLayout(v)

    def _on_setup(self):
        self.register_action('signal_style_changed', self._update_style)
        self._update_style()

    def _update_style(self):
        style_mgr = self._ui_model.get_style_manager()

        self._header.update_style(style_mgr)

        self.layout().setSpacing(
            style_mgr.get_scaled_size_param('small_padding'))
Exemple #2
0
class EventMap(QWidget, AudioUnitUpdater):
    def __init__(self):
        super().__init__()

        self._event_list = EventList()
        self.add_to_updaters(self._event_list)

        self._header = HeaderLine('Event map')

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._header)
        v.addWidget(self._event_list)
        self.setLayout(v)

    def _on_setup(self):
        self.register_action('signal_style_changed', self._update_style)
        self._update_style()

    def _update_style(self):
        style_mgr = self._ui_model.get_style_manager()
        self._header.update_style(style_mgr)
        self.layout().setSpacing(
            style_mgr.get_scaled_size_param('small_padding'))
Exemple #3
0
class EventMap(QWidget, AudioUnitUpdater):

    def __init__(self):
        super().__init__()

        self._event_list = EventList()
        self.add_to_updaters(self._event_list)

        self._header = HeaderLine('Event map')

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._header)
        v.addWidget(self._event_list)
        self.setLayout(v)

    def _on_setup(self):
        self.register_action('signal_style_changed', self._update_style)
        self._update_style()

    def _update_style(self):
        style_mgr = self._ui_model.get_style_manager()
        self._header.update_style(style_mgr)
        self.layout().setSpacing(style_mgr.get_scaled_size_param('small_padding'))
Exemple #4
0
class GridEditor(QWidget, Updater):
    def __init__(self):
        super().__init__()

        self._grid_list = GridList()
        self._general_editor = GeneralEditor()

        self._grid_area = GridArea()
        self._subdiv_editor = SubdivEditor()
        self._line_editor = LineEditor()

        self.add_to_updaters(self._grid_list, self._general_editor,
                             self._grid_area, self._subdiv_editor,
                             self._line_editor)

        self._line_layout = QVBoxLayout()
        self._line_layout.setContentsMargins(0, 0, 0, 0)
        self._line_layout.setSpacing(8)
        self._line_layout.addWidget(self._subdiv_editor)
        self._line_layout.addWidget(self._line_editor)

        self._details_layout = QHBoxLayout()
        self._details_layout.setContentsMargins(0, 0, 0, 0)
        self._details_layout.setSpacing(4)
        self._details_layout.addWidget(self._grid_area)
        self._details_layout.addLayout(self._line_layout)

        self._header = HeaderLine('Grid editor')

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._grid_list, 1)
        v.addSpacing(2)
        v.addWidget(self._header)
        v.addWidget(self._general_editor)
        v.addLayout(self._details_layout, 4)
        self.setLayout(v)

    def _on_setup(self):
        self.register_action('signal_style_changed', self._update_style)

    def _update_style(self):
        style_mgr = self._ui_model.get_style_manager()

        self._header.update_style(style_mgr)

        self._line_layout.setSpacing(
            style_mgr.get_scaled_size_param('large_padding'))
        self._details_layout.setSpacing(
            style_mgr.get_scaled_size_param('medium_padding'))

        layout = self.layout()
        spacing = style_mgr.get_scaled_size_param('small_padding')
        layout.setSpacing(spacing)
        for i in range(layout.count()):
            spacer = layout.itemAt(i).spacerItem()
            if spacer:
                spacer.changeSize(2, spacing)
Exemple #5
0
class PortsEditor(QWidget, AudioUnitUpdater):

    def __init__(self):
        super().__init__()
        self._editor = PortList(
                self._get_add_text, self._get_port_ids, self._get_free_port_id)

        self.add_to_updaters(self._editor)

        self._header = HeaderLine(self._get_title())

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._header)
        v.addWidget(self._editor)
        self.setLayout(v)

    def _on_setup(self):
        self.register_action('signal_style_changed', self._update_style)
        self._update_style()

    def _update_style(self):
        style_mgr = self._ui_model.get_style_manager()
        self._header.update_style(style_mgr)
        self.layout().setSpacing(style_mgr.get_scaled_size_param('small_padding'))

    # Port editor interface

    def _get_title(self):
        raise NotImplementedError

    def _get_add_text(self):
        raise NotImplementedError

    def _get_free_port_id(self):
        raise NotImplementedError

    def _get_port_ids(self):
        raise NotImplementedError
Exemple #6
0
class PortsEditor(QWidget, AudioUnitUpdater):
    def __init__(self):
        super().__init__()
        self._editor = PortList(self._get_add_text, self._get_port_ids,
                                self._get_free_port_id)

        self.add_to_updaters(self._editor)

        self._header = HeaderLine(self._get_title())

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._header)
        v.addWidget(self._editor)
        self.setLayout(v)

    def _on_setup(self):
        self.register_action('signal_style_changed', self._update_style)
        self._update_style()

    def _update_style(self):
        style_mgr = self._ui_model.get_style_manager()
        self._header.update_style(style_mgr)
        self.layout().setSpacing(
            style_mgr.get_scaled_size_param('small_padding'))

    # Port editor interface

    def _get_title(self):
        raise NotImplementedError

    def _get_add_text(self):
        raise NotImplementedError

    def _get_free_port_id(self):
        raise NotImplementedError

    def _get_port_ids(self):
        raise NotImplementedError
Exemple #7
0
class Hits(QWidget, AudioUnitUpdater):
    def __init__(self):
        super().__init__()

        self._hit_selector = AuHitSelector()
        self._hit_editor = HitEditor()

        self._hits_header = HeaderLine('Hits')
        self._properties_header = HeaderLine('Hit properties')

        v = QVBoxLayout()
        v.setContentsMargins(4, 4, 4, 4)
        v.setSpacing(4)
        v.addWidget(self._hits_header)
        v.addWidget(self._hit_selector)
        v.addWidget(self._properties_header)
        v.addWidget(self._hit_editor)
        v.addStretch(1)
        self.setLayout(v)

    def _on_setup(self):
        module = self._ui_model.get_module()
        au = module.get_audio_unit(self._au_id)
        if au.is_instrument():
            self.add_to_updaters(self._hit_selector, self._hit_editor)
            self.register_action('signal_style_changed', self._update_style)
            self._update_style()

    def _update_style(self):
        style_mgr = self._ui_model.get_style_manager()
        self._hits_header.update_style(style_mgr)
        self._properties_header.update_style(style_mgr)
        margin = style_mgr.get_scaled_size_param('medium_padding')
        self.layout().setContentsMargins(margin, margin, margin, margin)
        self.layout().setSpacing(
            style_mgr.get_scaled_size_param('small_padding'))
Exemple #8
0
class Hits(QWidget, AudioUnitUpdater):

    def __init__(self):
        super().__init__()

        self._hit_selector = AuHitSelector()
        self._hit_editor = HitEditor()

        self._hits_header = HeaderLine('Hits')
        self._properties_header = HeaderLine('Hit properties')

        v = QVBoxLayout()
        v.setContentsMargins(4, 4, 4, 4)
        v.setSpacing(4)
        v.addWidget(self._hits_header)
        v.addWidget(self._hit_selector)
        v.addWidget(self._properties_header)
        v.addWidget(self._hit_editor)
        v.addStretch(1)
        self.setLayout(v)

    def _on_setup(self):
        module = self._ui_model.get_module()
        au = module.get_audio_unit(self._au_id)
        if au.is_instrument():
            self.add_to_updaters(self._hit_selector, self._hit_editor)
            self.register_action('signal_style_changed', self._update_style)
            self._update_style()

    def _update_style(self):
        style_mgr = self._ui_model.get_style_manager()
        self._hits_header.update_style(style_mgr)
        self._properties_header.update_style(style_mgr)
        margin = style_mgr.get_scaled_size_param('medium_padding')
        self.layout().setContentsMargins(margin, margin, margin, margin)
        self.layout().setSpacing(style_mgr.get_scaled_size_param('small_padding'))
Exemple #9
0
class AudioUnitTimeEnvelope(QWidget, AudioUnitUpdater):
    def __init__(self):
        super().__init__()
        self._header = HeaderLine(self._get_title())

        if self._allow_toggle_enabled():
            self._enabled_toggle = QCheckBox('Enabled')
        if self._allow_loop():
            self._loop_toggle = QCheckBox('Loop')
        if self._allow_release_toggle():
            self._release_toggle = QCheckBox('Release')

        h = QHBoxLayout()
        if self._allow_toggle_enabled():
            h.addWidget(self._enabled_toggle)
        if self._allow_loop():
            h.addWidget(self._loop_toggle)
        if self._allow_release_toggle():
            h.addWidget(self._release_toggle)
        h.addStretch()

        self._envelope = self._make_envelope_widget()

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._header)
        v.addLayout(h)
        v.addWidget(self._envelope)
        self.setLayout(v)

    def _on_setup(self):
        self.register_action('signal_au', self._update_envelope)
        self.register_action(self._get_update_signal_type(),
                             self._update_envelope)
        self.register_action('signal_style_changed', self._update_style)

        self._envelope.set_ui_model(self._ui_model)

        if self._allow_toggle_enabled():
            self._enabled_toggle.stateChanged.connect(self._enabled_changed)
        if self._allow_loop():
            self._loop_toggle.stateChanged.connect(self._loop_enabled_changed)
        if self._allow_release_toggle():
            self._release_toggle.stateChanged.connect(self._release_changed)
        self._envelope.get_envelope_view().envelopeChanged.connect(
            self._envelope_changed)

        self._update_envelope()
        self._update_style()

    def _on_teardown(self):
        self._envelope.unregister_updaters()

    def _update_style(self):
        style_mgr = self._ui_model.get_style_manager()
        self._header.update_style(style_mgr)
        self.layout().setSpacing(
            style_mgr.get_scaled_size_param('small_padding'))
        self._envelope.update_style(style_mgr)

    def _update_envelope(self):
        is_enabled = True
        if self._allow_toggle_enabled():
            old_block = self._enabled_toggle.blockSignals(True)
            self._enabled_toggle.setCheckState(
                Qt.Checked if self._get_enabled() else Qt.Unchecked)
            self._enabled_toggle.blockSignals(old_block)

            is_enabled = self._get_enabled()

        self._envelope.setEnabled(is_enabled)

        if self._allow_loop():
            old_block = self._loop_toggle.blockSignals(True)
            self._loop_toggle.setEnabled(is_enabled)
            self._loop_toggle.setCheckState(
                Qt.Checked if self._get_loop_enabled() else Qt.Unchecked)
            self._loop_toggle.blockSignals(old_block)

        if self._allow_release_toggle():
            old_block = self._release_toggle.blockSignals(True)
            self._release_toggle.setEnabled(is_enabled)
            self._release_toggle.setCheckState(
                Qt.Checked if self._get_release_enabled() else Qt.Unchecked)
            self._release_toggle.blockSignals(old_block)

        envelope = self._get_envelope_data()
        ev = self._envelope.get_envelope_view()
        ev.set_nodes(envelope['nodes'])
        if self._allow_loop():
            ev.set_loop_markers(envelope['marks'])
            ev.set_loop_enabled(self._get_loop_enabled())

    def _enabled_changed(self, state):
        new_enabled = (state == Qt.Checked)
        self._set_enabled(new_enabled)
        self._updater.signal_update(self._get_update_signal_type())

    def _loop_enabled_changed(self, state):
        new_enabled = (state == Qt.Checked)
        self._set_loop_enabled(new_enabled)
        self._updater.signal_update(self._get_update_signal_type())

    def _release_changed(self, state):
        new_enabled = (state == Qt.Checked)
        self._set_release_enabled(new_enabled)
        self._updater.signal_update(self._get_update_signal_type())

    def _envelope_changed(self):
        new_nodes, new_loop = self._envelope.get_envelope_view(
        ).get_clear_changed()

        envelope = self._get_envelope_data()
        if new_nodes:
            envelope['nodes'] = new_nodes
        if new_loop:
            envelope['marks'] = new_loop

        if new_nodes or new_loop:
            if self._allow_toggle_enabled():
                self._set_enabled(True)

        self._set_envelope_data(envelope)
        self._updater.signal_update(self._get_update_signal_type())

    # Protected callbacks

    def _get_title(self):
        raise NotImplementedError

    def _allow_toggle_enabled(self):
        return True

    def _allow_loop(self):
        raise NotImplementedError

    def _allow_release_toggle(self):
        return False

    def _make_envelope_widget(self):
        raise NotImplementedError

    def _get_update_signal_type(self):
        raise NotImplementedError

    def _get_enabled(self):
        raise NotImplementedError

    def _set_enabled(self, enabled):
        raise NotImplementedError

    def _get_loop_enabled(self):
        raise NotImplementedError

    def _set_loop_enabled(self, enabled):
        raise NotImplementedError

    def _get_release_enabled(self):
        raise NotImplementedError

    def _set_release_enabled(self, enabled):
        raise NotImplementedError

    def _get_envelope_data(self):
        raise NotImplementedError

    def _set_envelope_data(self, envelope):
        raise NotImplementedError
Exemple #10
0
class SubdivEditor(QWidget, Updater):
    def __init__(self):
        super().__init__()
        self._subdiv_count = QSpinBox()
        self._subdiv_count.setMinimum(2)
        self._subdiv_count.setMaximum(32)
        self._subdiv_line_style = LineStyle()
        self._subdiv_warp = NumberSlider(3, 0.001, 0.999)
        self._subdiv_apply = QPushButton('Subdivide (Insert)')

        self._subdiv_line_style.select_line_style(1)

        self._controls_layout = QGridLayout()
        self._controls_layout.setContentsMargins(0, 0, 0, 0)
        self._controls_layout.setSpacing(2)
        self._controls_layout.setColumnStretch(0, 0)
        self._controls_layout.setColumnStretch(1, 1)
        self._controls_layout.addWidget(QLabel('Parts:'), 0, 0)
        self._controls_layout.addWidget(self._subdiv_count, 0, 1)
        self._controls_layout.addWidget(QLabel('Style:'), 1, 0)
        self._controls_layout.addWidget(self._subdiv_line_style, 1, 1)
        self._controls_layout.addWidget(QLabel('Warp:'), 2, 0)
        self._controls_layout.addWidget(self._subdiv_warp, 2, 1)

        self._header = HeaderLine('Create subdivision')

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._header, 0, Qt.AlignTop)
        v.addLayout(self._controls_layout, 0)
        v.addWidget(self._subdiv_apply, 0)
        self.setLayout(v)

    def _on_setup(self):
        self.register_action('signal_grid_pattern_selection', self._update_all)
        self.register_action('signal_grid_pattern_line_selection',
                             self._update_all)
        self.register_action('signal_grid_pattern_modified', self._update_all)
        self.register_action('signal_grid_pattern_subdiv', self._update_all)
        self.register_action('signal_style_changed', self._update_style)

        self._update_config()

        self._subdiv_count.valueChanged.connect(self._change_count)
        self._subdiv_line_style.currentIndexChanged.connect(
            self._change_line_style)
        self._subdiv_warp.numberChanged.connect(self._change_warp)
        self._subdiv_apply.clicked.connect(self._apply_subdivision)

        self._update_all()

    def _update_style(self):
        self._header.update_style(self._ui_model.get_style_manager())
        self._update_config()
        self.update()

    def _update_config(self):
        style_mgr = self._ui_model.get_style_manager()
        config = DEFAULT_CONFIG.copy()
        custom_config = get_config_with_custom_style(style_mgr)
        config.update(custom_config)

        spacing = style_mgr.get_scaled_size_param('small_padding')
        self._controls_layout.setSpacing(spacing)
        self.layout().setSpacing(spacing)

        self._subdiv_line_style.set_config(config, style_mgr)

    def _get_selected_line_ts(self):
        grid_mgr = self._ui_model.get_grid_manager()
        gp_id = grid_mgr.get_selected_grid_pattern_id()
        if gp_id == None:
            return None

        # Get line selection info
        gp = grid_mgr.get_grid_pattern(gp_id)
        gp_lines = gp.get_lines()
        lines_dict = dict(gp_lines)
        selected_line_ts = gp.get_selected_line()

        return selected_line_ts if selected_line_ts in lines_dict else None

    def _update_all(self):
        selected_line_ts = self._get_selected_line_ts()
        self.setEnabled(selected_line_ts != None)

        grid_mgr = self._ui_model.get_grid_manager()

        old_block = self._subdiv_count.blockSignals(True)
        self._subdiv_count.setValue(
            grid_mgr.get_grid_pattern_subdiv_part_count())
        self._subdiv_count.blockSignals(old_block)

        self._subdiv_line_style.select_line_style(
            grid_mgr.get_grid_pattern_subdiv_line_style())
        self._subdiv_warp.set_number(grid_mgr.get_grid_pattern_subdiv_warp())

    def _change_count(self, new_count):
        grid_mgr = self._ui_model.get_grid_manager()
        grid_mgr.set_grid_pattern_subdiv_part_count(new_count)
        self._updater.signal_update('signal_grid_pattern_subdiv')

    def _change_line_style(self, dummy):
        new_style = self._subdiv_line_style.get_current_line_style()
        grid_mgr = self._ui_model.get_grid_manager()
        grid_mgr.set_grid_pattern_subdiv_line_style(new_style)
        self._updater.signal_update('signal_grid_pattern_subdiv')

    def _change_warp(self, new_warp):
        grid_mgr = self._ui_model.get_grid_manager()
        grid_mgr.set_grid_pattern_subdiv_warp(new_warp)
        self._updater.signal_update('signal_grid_pattern_subdiv')

    def _apply_subdivision(self):
        selected_line_ts = self._get_selected_line_ts()
        assert selected_line_ts != None

        grid_mgr = self._ui_model.get_grid_manager()
        gp_id = grid_mgr.get_selected_grid_pattern_id()
        gp = grid_mgr.get_grid_pattern(gp_id)

        part_count = grid_mgr.get_grid_pattern_subdiv_part_count()
        warp_value = grid_mgr.get_grid_pattern_subdiv_warp()
        line_style = grid_mgr.get_grid_pattern_subdiv_line_style()

        gp.subdivide_interval(selected_line_ts, part_count, warp_value,
                              line_style)
        self._updater.signal_update('signal_grid_pattern_modified')
Exemple #11
0
class WaveformEditor(QWidget, ProcessorUpdater):

    def __init__(self):
        super().__init__()
        self._prewarp_list = WarpList(
                'pre', self._get_base_wave, self._get_update_signal_type)
        self._base_func_selector = KqtComboBox()
        self._postwarp_list = WarpList(
                'post', self._get_base_wave, self._get_update_signal_type)
        self._waveform = Waveform()

        pw_layout = QVBoxLayout()
        pw_layout.setSpacing(0)
        pw_layout.addWidget(self._prewarp_list)
        pw_layout.addWidget(self._base_func_selector)
        pw_layout.addWidget(self._postwarp_list)

        ed_layout = QHBoxLayout()
        ed_layout.setSpacing(0)
        ed_layout.addLayout(pw_layout)
        ed_layout.addWidget(self._waveform)

        self._header = HeaderLine('Waveshaping')

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._header)
        v.addLayout(ed_layout)
        self.setLayout(v)

    def _on_setup(self):
        self.add_to_updaters(self._prewarp_list, self._postwarp_list)
        self.register_action('signal_au', self._update_all)
        self.register_action(self._get_update_signal_type(), self._update_all)
        self.register_action('signal_style_changed', self._update_style)

        self._update_style()
        self._update_all()

        self._base_func_selector.currentIndexChanged.connect(self._base_func_selected)

    def _update_style(self):
        style_mgr = self._ui_model.get_style_manager()

        self._header.update_style(style_mgr)
        self.layout().setSpacing(style_mgr.get_scaled_size_param('small_padding'))

        def get_colour(name):
            return QColor(style_mgr.get_style_param(name))

        disabled_colour = QColor(get_colour('bg_colour'))
        disabled_colour.setAlpha(0x7f)

        config = {
            'bg_colour': get_colour('waveform_bg_colour'),
            'centre_line_colour': get_colour('waveform_centre_line_colour'),
            'waveform_colour': get_colour('waveform_zoomed_out_colour'),
            'disabled_colour': disabled_colour,
            'line_thickness' : style_mgr.get_scaled_size(0.1),
        }

        self._waveform.set_config(config)

    def _update_all(self):
        base_wave = self._get_base_wave()

        selected_base_func = base_wave.get_waveform_func()
        enable_warps = (selected_base_func != None)

        self._prewarp_list.setEnabled(enable_warps)

        old_block = self._base_func_selector.blockSignals(True)
        func_names = list(base_wave.get_waveform_func_names())
        if not selected_base_func:
            func_names.append('Custom')
        self._base_func_selector.set_items(func_names)
        self._base_func_selector.setCurrentIndex(
                self._base_func_selector.findText(selected_base_func or 'Custom'))
        self._base_func_selector.blockSignals(old_block)

        self._postwarp_list.setEnabled(enable_warps)

        self._waveform.set_waveform(base_wave.get_waveform())

    def _base_func_selected(self, index):
        base_wave = self._get_base_wave()
        func_names = base_wave.get_waveform_func_names()
        base_wave.set_waveform_func(func_names[index])
        self._updater.signal_update(self._get_update_signal_type())

    # Protected interface

    def _get_base_wave(self):
        raise NotImplementedError

    def _get_update_signal_type(self):
        raise NotImplementedError
Exemple #12
0
class LineEditor(QWidget, Updater):
    def __init__(self):
        super().__init__()
        self._line_style = LineStyle()
        self._remove_button = QPushButton('Remove line (Delete)')

        self._controls_layout = QHBoxLayout()
        self._controls_layout.setContentsMargins(0, 0, 0, 0)
        self._controls_layout.setSpacing(2)
        self._controls_layout.addWidget(QLabel('Style:'), 0)
        self._controls_layout.addWidget(self._line_style, 1)

        self._header = HeaderLine('Current line')

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._header, 0, Qt.AlignTop)
        v.addLayout(self._controls_layout, 0)
        v.addWidget(self._remove_button, 0, Qt.AlignTop)
        v.addWidget(QWidget(), 1)
        self.setLayout(v)

    def _on_setup(self):
        self.register_action('signal_grid_pattern_selection', self._update_all)
        self.register_action('signal_grid_pattern_line_selection',
                             self._update_all)
        self.register_action('signal_grid_pattern_modified', self._update_all)
        self.register_action('signal_style_changed', self._update_config)

        self._update_config()

        self._line_style.currentIndexChanged.connect(self._change_line_style)
        self._remove_button.clicked.connect(self._remove_selected_line)

        self._update_all()

    def _update_config(self):
        style_mgr = self._ui_model.get_style_manager()
        self._header.update_style(style_mgr)
        config = DEFAULT_CONFIG.copy()
        custom_config = get_config_with_custom_style(style_mgr)
        config.update(custom_config)

        spacing = style_mgr.get_scaled_size_param('small_padding')
        self._controls_layout.setSpacing(spacing)
        self.layout().setSpacing(spacing)

        self._line_style.set_config(config, style_mgr)

    def _get_grid_pattern(self):
        grid_mgr = self._ui_model.get_grid_manager()
        gp_id = grid_mgr.get_selected_grid_pattern_id()
        if gp_id == None:
            return None

        return grid_mgr.get_grid_pattern(gp_id)

    def _update_all(self):
        gp = self._get_grid_pattern()
        if gp == None:
            self.setEnabled(False)
            return

        selected_line_ts = gp.get_selected_line()

        # Get line selection info
        gp_lines = gp.get_lines()
        lines_dict = dict(gp_lines)
        has_selected_line = selected_line_ts in lines_dict
        is_selected_line_major = (lines_dict.get(selected_line_ts, None) == 0)

        # Set editor parts as enabled if we have an appropriate selection
        self.setEnabled(has_selected_line)

        self._remove_button.setEnabled(not is_selected_line_major)
        self._line_style.setEnabled(not is_selected_line_major)

        # Set line style selection
        if has_selected_line:
            selected_line_style = lines_dict[selected_line_ts]
            self._line_style.select_line_style(selected_line_style)

    def _change_line_style(self, ls_index):
        line_style = self._line_style.get_current_line_style()
        assert line_style != None

        gp = self._get_grid_pattern()
        assert gp != None
        selected_line_ts = gp.get_selected_line()

        gp.change_line_style(selected_line_ts, line_style)
        self._updater.signal_update('signal_grid_pattern_modified')

    def _remove_selected_line(self):
        gp = self._get_grid_pattern()
        assert gp != None
        selected_line_ts = gp.get_selected_line()

        gp.remove_line(selected_line_ts)
        self._updater.signal_update('signal_grid_pattern_modified')
Exemple #13
0
class AudioUnitTimeEnvelope(QWidget, AudioUnitUpdater):

    def __init__(self):
        super().__init__()
        self._header = HeaderLine(self._get_title())

        if self._allow_toggle_enabled():
            self._enabled_toggle = QCheckBox('Enabled')
        if self._allow_loop():
            self._loop_toggle = QCheckBox('Loop')
        if self._allow_release_toggle():
            self._release_toggle = QCheckBox('Release')

        h = QHBoxLayout()
        if self._allow_toggle_enabled():
            h.addWidget(self._enabled_toggle)
        if self._allow_loop():
            h.addWidget(self._loop_toggle)
        if self._allow_release_toggle():
            h.addWidget(self._release_toggle)
        h.addStretch()

        self._envelope = self._make_envelope_widget()

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._header)
        v.addLayout(h)
        v.addWidget(self._envelope)
        self.setLayout(v)

    def _on_setup(self):
        self.register_action('signal_au', self._update_envelope)
        self.register_action(self._get_update_signal_type(), self._update_envelope)
        self.register_action('signal_style_changed', self._update_style)

        self._envelope.set_ui_model(self._ui_model)

        if self._allow_toggle_enabled():
            self._enabled_toggle.stateChanged.connect(self._enabled_changed)
        if self._allow_loop():
            self._loop_toggle.stateChanged.connect(self._loop_enabled_changed)
        if self._allow_release_toggle():
            self._release_toggle.stateChanged.connect(self._release_changed)
        self._envelope.get_envelope_view().envelopeChanged.connect(
                self._envelope_changed)

        self._update_envelope()
        self._update_style()

    def _on_teardown(self):
        self._envelope.unregister_updaters()

    def _update_style(self):
        style_mgr = self._ui_model.get_style_manager()
        self._header.update_style(style_mgr)
        self.layout().setSpacing(style_mgr.get_scaled_size_param('small_padding'))
        self._envelope.update_style(style_mgr)

    def _update_envelope(self):
        is_enabled = True
        if self._allow_toggle_enabled():
            old_block = self._enabled_toggle.blockSignals(True)
            self._enabled_toggle.setCheckState(
                    Qt.Checked if self._get_enabled() else Qt.Unchecked)
            self._enabled_toggle.blockSignals(old_block)

            is_enabled = self._get_enabled()

        self._envelope.setEnabled(is_enabled)

        if self._allow_loop():
            old_block = self._loop_toggle.blockSignals(True)
            self._loop_toggle.setEnabled(is_enabled)
            self._loop_toggle.setCheckState(
                    Qt.Checked if self._get_loop_enabled() else Qt.Unchecked)
            self._loop_toggle.blockSignals(old_block)

        if self._allow_release_toggle():
            old_block = self._release_toggle.blockSignals(True)
            self._release_toggle.setEnabled(is_enabled)
            self._release_toggle.setCheckState(
                    Qt.Checked if self._get_release_enabled() else Qt.Unchecked)
            self._release_toggle.blockSignals(old_block)

        envelope = self._get_envelope_data()
        ev = self._envelope.get_envelope_view()
        ev.set_nodes(envelope['nodes'])
        if self._allow_loop():
            ev.set_loop_markers(envelope['marks'])
            ev.set_loop_enabled(self._get_loop_enabled())

    def _enabled_changed(self, state):
        new_enabled = (state == Qt.Checked)
        self._set_enabled(new_enabled)
        self._updater.signal_update(self._get_update_signal_type())

    def _loop_enabled_changed(self, state):
        new_enabled = (state == Qt.Checked)
        self._set_loop_enabled(new_enabled)
        self._updater.signal_update(self._get_update_signal_type())

    def _release_changed(self, state):
        new_enabled = (state == Qt.Checked)
        self._set_release_enabled(new_enabled)
        self._updater.signal_update(self._get_update_signal_type())

    def _envelope_changed(self):
        new_nodes, new_loop = self._envelope.get_envelope_view().get_clear_changed()

        envelope = self._get_envelope_data()
        if new_nodes:
            envelope['nodes'] = new_nodes
        if new_loop:
            envelope['marks'] = new_loop

        if new_nodes or new_loop:
            if self._allow_toggle_enabled():
                self._set_enabled(True)

        self._set_envelope_data(envelope)
        self._updater.signal_update(self._get_update_signal_type())

    # Protected callbacks

    def _get_title(self):
        raise NotImplementedError

    def _allow_toggle_enabled(self):
        return True

    def _allow_loop(self):
        raise NotImplementedError

    def _allow_release_toggle(self):
        return False

    def _make_envelope_widget(self):
        raise NotImplementedError

    def _get_update_signal_type(self):
        raise NotImplementedError

    def _get_enabled(self):
        raise NotImplementedError

    def _set_enabled(self, enabled):
        raise NotImplementedError

    def _get_loop_enabled(self):
        raise NotImplementedError

    def _set_loop_enabled(self, enabled):
        raise NotImplementedError

    def _get_release_enabled(self):
        raise NotImplementedError

    def _set_release_enabled(self, enabled):
        raise NotImplementedError

    def _get_envelope_data(self):
        raise NotImplementedError

    def _set_envelope_data(self, envelope):
        raise NotImplementedError
Exemple #14
0
class AudioUnitSimpleEnvelope(QWidget, AudioUnitUpdater):
    def __init__(self):
        super().__init__()
        self._header = HeaderLine(self._get_title())

        self._enabled_toggle = QCheckBox('Enabled')

        self._envelope = self._make_envelope_widget()

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._header)
        v.addWidget(self._enabled_toggle)
        v.addWidget(self._envelope)
        self.setLayout(v)

    def _on_setup(self):
        self.register_action('signal_au', self._update_envelope)
        self.register_action(self._get_update_signal_type(),
                             self._update_envelope)
        self.register_action('signal_style_changed', self._update_style)

        self._envelope.set_ui_model(self._ui_model)

        self._enabled_toggle.stateChanged.connect(self._enabled_changed)
        self._envelope.get_envelope_view().envelopeChanged.connect(
            self._envelope_changed)

        self._update_envelope()
        self._update_style()

    def _on_teardown(self):
        self._envelope.unregister_updaters()

    def _update_style(self):
        style_mgr = self._ui_model.get_style_manager()
        self._header.update_style(style_mgr)
        self.layout().setSpacing(
            style_mgr.get_scaled_size_param('small_padding'))
        self._envelope.update_style(style_mgr)

    def _update_envelope(self):
        old_block = self._enabled_toggle.blockSignals(True)
        self._enabled_toggle.setCheckState(
            Qt.Checked if self._get_enabled() else Qt.Unchecked)
        self._enabled_toggle.blockSignals(old_block)

        self._envelope.setEnabled(self._get_enabled())

        envelope = self._get_envelope_data()
        ev = self._envelope.get_envelope_view()
        ev.set_nodes(envelope['nodes'])

    def _enabled_changed(self, state):
        new_enabled = (state == Qt.Checked)
        self._set_enabled(new_enabled)
        self._updater.signal_update(self._get_update_signal_type())

    def _envelope_changed(self):
        new_nodes, _ = self._envelope.get_envelope_view().get_clear_changed()

        envelope = self._get_envelope_data()
        if new_nodes:
            envelope['nodes'] = new_nodes

        if new_nodes:
            self._set_enabled(True)

        self._set_envelope_data(envelope)
        self._updater.signal_update(self._get_update_signal_type())

    # Protected interface

    def _get_update_signal_type(self):
        raise NotImplementedError

    def _get_title(self):
        raise NotImplementedError

    def _make_envelope_widget(self):
        raise NotImplementedError

    def _get_enabled(self):
        raise NotImplementedError

    def _set_enabled(self, enabled):
        raise NotImplementedError

    def _get_envelope_data(self):
        raise NotImplementedError

    def _set_envelope_data(self, envelope):
        raise NotImplementedError
Exemple #15
0
class LineEditor(QWidget, Updater):

    def __init__(self):
        super().__init__()
        self._line_style = LineStyle()
        self._remove_button = QPushButton('Remove line (Delete)')

        self._controls_layout = QHBoxLayout()
        self._controls_layout.setContentsMargins(0, 0, 0, 0)
        self._controls_layout.setSpacing(2)
        self._controls_layout.addWidget(QLabel('Style:'), 0)
        self._controls_layout.addWidget(self._line_style, 1)

        self._header = HeaderLine('Current line')

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._header, 0, Qt.AlignTop)
        v.addLayout(self._controls_layout, 0)
        v.addWidget(self._remove_button, 0, Qt.AlignTop)
        v.addWidget(QWidget(), 1)
        self.setLayout(v)

    def _on_setup(self):
        self.register_action('signal_grid_pattern_selection', self._update_all)
        self.register_action('signal_grid_pattern_line_selection', self._update_all)
        self.register_action('signal_grid_pattern_modified', self._update_all)
        self.register_action('signal_style_changed', self._update_config)

        self._update_config()

        self._line_style.currentIndexChanged.connect(self._change_line_style)
        self._remove_button.clicked.connect(self._remove_selected_line)

        self._update_all()

    def _update_config(self):
        style_mgr = self._ui_model.get_style_manager()
        self._header.update_style(style_mgr)
        config = DEFAULT_CONFIG.copy()
        custom_config = get_config_with_custom_style(style_mgr)
        config.update(custom_config)

        spacing = style_mgr.get_scaled_size_param('small_padding')
        self._controls_layout.setSpacing(spacing)
        self.layout().setSpacing(spacing)

        self._line_style.set_config(config, style_mgr)

    def _get_grid_pattern(self):
        grid_mgr = self._ui_model.get_grid_manager()
        gp_id = grid_mgr.get_selected_grid_pattern_id()
        if gp_id == None:
            return None

        return grid_mgr.get_grid_pattern(gp_id)

    def _update_all(self):
        gp = self._get_grid_pattern()
        if gp == None:
            self.setEnabled(False)
            return

        selected_line_ts = gp.get_selected_line()

        # Get line selection info
        gp_lines = gp.get_lines()
        lines_dict = dict(gp_lines)
        has_selected_line = selected_line_ts in lines_dict
        is_selected_line_major = (lines_dict.get(selected_line_ts, None) == 0)

        # Set editor parts as enabled if we have an appropriate selection
        self.setEnabled(has_selected_line)

        self._remove_button.setEnabled(not is_selected_line_major)
        self._line_style.setEnabled(not is_selected_line_major)

        # Set line style selection
        if has_selected_line:
            selected_line_style = lines_dict[selected_line_ts]
            self._line_style.select_line_style(selected_line_style)

    def _change_line_style(self, ls_index):
        line_style = self._line_style.get_current_line_style()
        assert line_style != None

        gp = self._get_grid_pattern()
        assert gp != None
        selected_line_ts = gp.get_selected_line()

        gp.change_line_style(selected_line_ts, line_style)
        self._updater.signal_update('signal_grid_pattern_modified')

    def _remove_selected_line(self):
        gp = self._get_grid_pattern()
        assert gp != None
        selected_line_ts = gp.get_selected_line()

        gp.remove_line(selected_line_ts)
        self._updater.signal_update('signal_grid_pattern_modified')
Exemple #16
0
class GridEditor(QWidget, Updater):

    def __init__(self):
        super().__init__()

        self._grid_list = GridList()
        self._general_editor = GeneralEditor()

        self._grid_area = GridArea()
        self._subdiv_editor = SubdivEditor()
        self._line_editor = LineEditor()

        self.add_to_updaters(
                self._grid_list,
                self._general_editor,
                self._grid_area,
                self._subdiv_editor,
                self._line_editor)

        self._line_layout = QVBoxLayout()
        self._line_layout.setContentsMargins(0, 0, 0, 0)
        self._line_layout.setSpacing(8)
        self._line_layout.addWidget(self._subdiv_editor)
        self._line_layout.addWidget(self._line_editor)

        self._details_layout = QHBoxLayout()
        self._details_layout.setContentsMargins(0, 0, 0, 0)
        self._details_layout.setSpacing(4)
        self._details_layout.addWidget(self._grid_area)
        self._details_layout.addLayout(self._line_layout)

        self._header = HeaderLine('Grid editor')

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._grid_list, 1)
        v.addSpacing(2)
        v.addWidget(self._header)
        v.addWidget(self._general_editor)
        v.addLayout(self._details_layout, 4)
        self.setLayout(v)

    def _on_setup(self):
        self.register_action('signal_style_changed', self._update_style)

    def _update_style(self):
        style_mgr = self._ui_model.get_style_manager()

        self._header.update_style(style_mgr)

        self._line_layout.setSpacing(style_mgr.get_scaled_size_param('large_padding'))
        self._details_layout.setSpacing(
                style_mgr.get_scaled_size_param('medium_padding'))

        layout = self.layout()
        spacing = style_mgr.get_scaled_size_param('small_padding')
        layout.setSpacing(spacing)
        for i in range(layout.count()):
            spacer = layout.itemAt(i).spacerItem()
            if spacer:
                spacer.changeSize(2, spacing)
Exemple #17
0
class SubdivEditor(QWidget, Updater):

    def __init__(self):
        super().__init__()
        self._subdiv_count = QSpinBox()
        self._subdiv_count.setMinimum(2)
        self._subdiv_count.setMaximum(32)
        self._subdiv_line_style = LineStyle()
        self._subdiv_warp = NumberSlider(3, 0.001, 0.999)
        self._subdiv_apply = QPushButton('Subdivide (Insert)')

        self._subdiv_line_style.select_line_style(1)

        self._controls_layout = QGridLayout()
        self._controls_layout.setContentsMargins(0, 0, 0, 0)
        self._controls_layout.setSpacing(2)
        self._controls_layout.setColumnStretch(0, 0)
        self._controls_layout.setColumnStretch(1, 1)
        self._controls_layout.addWidget(QLabel('Parts:'), 0, 0)
        self._controls_layout.addWidget(self._subdiv_count, 0, 1)
        self._controls_layout.addWidget(QLabel('Style:'), 1, 0)
        self._controls_layout.addWidget(self._subdiv_line_style, 1, 1)
        self._controls_layout.addWidget(QLabel('Warp:'), 2, 0)
        self._controls_layout.addWidget(self._subdiv_warp, 2, 1)

        self._header = HeaderLine('Create subdivision')

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._header, 0, Qt.AlignTop)
        v.addLayout(self._controls_layout, 0)
        v.addWidget(self._subdiv_apply, 0)
        self.setLayout(v)

    def _on_setup(self):
        self.register_action('signal_grid_pattern_selection', self._update_all)
        self.register_action('signal_grid_pattern_line_selection', self._update_all)
        self.register_action('signal_grid_pattern_modified', self._update_all)
        self.register_action('signal_grid_pattern_subdiv', self._update_all)
        self.register_action('signal_style_changed', self._update_style)

        self._update_config()

        self._subdiv_count.valueChanged.connect(self._change_count)
        self._subdiv_line_style.currentIndexChanged.connect(self._change_line_style)
        self._subdiv_warp.numberChanged.connect(self._change_warp)
        self._subdiv_apply.clicked.connect(self._apply_subdivision)

        self._update_all()

    def _update_style(self):
        self._header.update_style(self._ui_model.get_style_manager())
        self._update_config()
        self.update()

    def _update_config(self):
        style_mgr = self._ui_model.get_style_manager()
        config = DEFAULT_CONFIG.copy()
        custom_config = get_config_with_custom_style(style_mgr)
        config.update(custom_config)

        spacing = style_mgr.get_scaled_size_param('small_padding')
        self._controls_layout.setSpacing(spacing)
        self.layout().setSpacing(spacing)

        self._subdiv_line_style.set_config(config, style_mgr)

    def _get_selected_line_ts(self):
        grid_mgr = self._ui_model.get_grid_manager()
        gp_id = grid_mgr.get_selected_grid_pattern_id()
        if gp_id == None:
            return None

        # Get line selection info
        gp = grid_mgr.get_grid_pattern(gp_id)
        gp_lines = gp.get_lines()
        lines_dict = dict(gp_lines)
        selected_line_ts = gp.get_selected_line()

        return selected_line_ts if selected_line_ts in lines_dict else None

    def _update_all(self):
        selected_line_ts = self._get_selected_line_ts()
        self.setEnabled(selected_line_ts != None)

        grid_mgr = self._ui_model.get_grid_manager()

        old_block = self._subdiv_count.blockSignals(True)
        self._subdiv_count.setValue(grid_mgr.get_grid_pattern_subdiv_part_count())
        self._subdiv_count.blockSignals(old_block)

        self._subdiv_line_style.select_line_style(
                grid_mgr.get_grid_pattern_subdiv_line_style())
        self._subdiv_warp.set_number(grid_mgr.get_grid_pattern_subdiv_warp())

    def _change_count(self, new_count):
        grid_mgr = self._ui_model.get_grid_manager()
        grid_mgr.set_grid_pattern_subdiv_part_count(new_count)
        self._updater.signal_update('signal_grid_pattern_subdiv')

    def _change_line_style(self, dummy):
        new_style = self._subdiv_line_style.get_current_line_style()
        grid_mgr = self._ui_model.get_grid_manager()
        grid_mgr.set_grid_pattern_subdiv_line_style(new_style)
        self._updater.signal_update('signal_grid_pattern_subdiv')

    def _change_warp(self, new_warp):
        grid_mgr = self._ui_model.get_grid_manager()
        grid_mgr.set_grid_pattern_subdiv_warp(new_warp)
        self._updater.signal_update('signal_grid_pattern_subdiv')

    def _apply_subdivision(self):
        selected_line_ts = self._get_selected_line_ts()
        assert selected_line_ts != None

        grid_mgr = self._ui_model.get_grid_manager()
        gp_id = grid_mgr.get_selected_grid_pattern_id()
        gp = grid_mgr.get_grid_pattern(gp_id)

        part_count = grid_mgr.get_grid_pattern_subdiv_part_count()
        warp_value = grid_mgr.get_grid_pattern_subdiv_warp()
        line_style = grid_mgr.get_grid_pattern_subdiv_line_style()

        gp.subdivide_interval(selected_line_ts, part_count, warp_value, line_style)
        self._updater.signal_update('signal_grid_pattern_modified')
Exemple #18
0
class AudioUnitSimpleEnvelope(QWidget, AudioUnitUpdater):

    def __init__(self):
        super().__init__()
        self._header = HeaderLine(self._get_title())

        self._enabled_toggle = QCheckBox('Enabled')

        self._envelope = self._make_envelope_widget()

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._header)
        v.addWidget(self._enabled_toggle)
        v.addWidget(self._envelope)
        self.setLayout(v)

    def _on_setup(self):
        self.register_action('signal_au', self._update_envelope)
        self.register_action(self._get_update_signal_type(), self._update_envelope)
        self.register_action('signal_style_changed', self._update_style)

        self._envelope.set_ui_model(self._ui_model)

        self._enabled_toggle.stateChanged.connect(self._enabled_changed)
        self._envelope.get_envelope_view().envelopeChanged.connect(
                self._envelope_changed)

        self._update_envelope()
        self._update_style()

    def _on_teardown(self):
        self._envelope.unregister_updaters()

    def _update_style(self):
        style_mgr = self._ui_model.get_style_manager()
        self._header.update_style(style_mgr)
        self.layout().setSpacing(style_mgr.get_scaled_size_param('small_padding'))
        self._envelope.update_style(style_mgr)

    def _update_envelope(self):
        old_block = self._enabled_toggle.blockSignals(True)
        self._enabled_toggle.setCheckState(
                Qt.Checked if self._get_enabled() else Qt.Unchecked)
        self._enabled_toggle.blockSignals(old_block)

        self._envelope.setEnabled(self._get_enabled())

        envelope = self._get_envelope_data()
        ev = self._envelope.get_envelope_view()
        ev.set_nodes(envelope['nodes'])

    def _enabled_changed(self, state):
        new_enabled = (state == Qt.Checked)
        self._set_enabled(new_enabled)
        self._updater.signal_update(self._get_update_signal_type())

    def _envelope_changed(self):
        new_nodes, _ = self._envelope.get_envelope_view().get_clear_changed()

        envelope = self._get_envelope_data()
        if new_nodes:
            envelope['nodes'] = new_nodes

        if new_nodes:
            self._set_enabled(True)

        self._set_envelope_data(envelope)
        self._updater.signal_update(self._get_update_signal_type())

    # Protected interface

    def _get_update_signal_type(self):
        raise NotImplementedError

    def _get_title(self):
        raise NotImplementedError

    def _make_envelope_widget(self):
        raise NotImplementedError

    def _get_enabled(self):
        raise NotImplementedError

    def _set_enabled(self, enabled):
        raise NotImplementedError

    def _get_envelope_data(self):
        raise NotImplementedError

    def _set_envelope_data(self, envelope):
        raise NotImplementedError
Exemple #19
0
class WaveformEditor(QWidget, ProcessorUpdater):
    def __init__(self):
        super().__init__()
        self._prewarp_list = WarpList('pre', self._get_base_wave,
                                      self._get_update_signal_type)
        self._base_func_selector = KqtComboBox()
        self._postwarp_list = WarpList('post', self._get_base_wave,
                                       self._get_update_signal_type)
        self._waveform = Waveform()

        pw_layout = QVBoxLayout()
        pw_layout.setSpacing(0)
        pw_layout.addWidget(self._prewarp_list)
        pw_layout.addWidget(self._base_func_selector)
        pw_layout.addWidget(self._postwarp_list)

        ed_layout = QHBoxLayout()
        ed_layout.setSpacing(0)
        ed_layout.addLayout(pw_layout)
        ed_layout.addWidget(self._waveform)

        self._header = HeaderLine('Waveshaping')

        v = QVBoxLayout()
        v.setContentsMargins(0, 0, 0, 0)
        v.setSpacing(2)
        v.addWidget(self._header)
        v.addLayout(ed_layout)
        self.setLayout(v)

    def _on_setup(self):
        self.add_to_updaters(self._prewarp_list, self._postwarp_list)
        self.register_action('signal_au', self._update_all)
        self.register_action(self._get_update_signal_type(), self._update_all)
        self.register_action('signal_style_changed', self._update_style)

        self._update_style()
        self._update_all()

        self._base_func_selector.currentIndexChanged.connect(
            self._base_func_selected)

    def _update_style(self):
        style_mgr = self._ui_model.get_style_manager()

        self._header.update_style(style_mgr)
        self.layout().setSpacing(
            style_mgr.get_scaled_size_param('small_padding'))

        def get_colour(name):
            return QColor(style_mgr.get_style_param(name))

        disabled_colour = QColor(get_colour('bg_colour'))
        disabled_colour.setAlpha(0x7f)

        config = {
            'bg_colour': get_colour('waveform_bg_colour'),
            'centre_line_colour': get_colour('waveform_centre_line_colour'),
            'waveform_colour': get_colour('waveform_zoomed_out_colour'),
            'disabled_colour': disabled_colour,
            'line_thickness': style_mgr.get_scaled_size(0.1),
        }

        self._waveform.set_config(config)

    def _update_all(self):
        base_wave = self._get_base_wave()

        selected_base_func = base_wave.get_waveform_func()
        enable_warps = (selected_base_func != None)

        self._prewarp_list.setEnabled(enable_warps)

        old_block = self._base_func_selector.blockSignals(True)
        func_names = list(base_wave.get_waveform_func_names())
        if not selected_base_func:
            func_names.append('Custom')
        self._base_func_selector.set_items(func_names)
        self._base_func_selector.setCurrentIndex(
            self._base_func_selector.findText(selected_base_func or 'Custom'))
        self._base_func_selector.blockSignals(old_block)

        self._postwarp_list.setEnabled(enable_warps)

        self._waveform.set_waveform(base_wave.get_waveform())

    def _base_func_selected(self, index):
        base_wave = self._get_base_wave()
        func_names = base_wave.get_waveform_func_names()
        base_wave.set_waveform_func(func_names[index])
        self._updater.signal_update(self._get_update_signal_type())

    # Protected interface

    def _get_base_wave(self):
        raise NotImplementedError

    def _get_update_signal_type(self):
        raise NotImplementedError