From 7c1bb8357495778076a47636c2c4192674034165 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Thu, 20 Oct 2016 23:44:12 +0200 Subject: [PATCH] Add mute buttons. Actually this is mostly because I like being able to press the mute button on my MIDI controller and have it light up :-) Internally, it's implemented by forcing the volume to zero (or sometimes -90 dB), which means we get all the nice fading properties and such. In the process, we now declare -90 dB to be truly zero, and don't bother adding it to the bus. --- audio_mixer.cpp | 16 +++++--- audio_mixer.h | 5 +++ mainwindow.cpp | 47 +++++++++++++++++++++-- mainwindow.h | 8 +++- midi_mapper.cpp | 7 ++++ midi_mapper.h | 2 + midi_mapping.proto | 79 ++++++++++++++++++++------------------- midi_mapping_dialog.cpp | 3 ++ midi_mapping_dialog.h | 2 + ui_audio_expanded_view.ui | 52 +++++++++++++++++++++++--- 10 files changed, 166 insertions(+), 55 deletions(-) diff --git a/audio_mixer.cpp b/audio_mixer.cpp index 401c89b..46ae44c 100644 --- a/audio_mixer.cpp +++ b/audio_mixer.cpp @@ -319,6 +319,7 @@ AudioMixer::BusSettings AudioMixer::get_default_bus_settings() { BusSettings settings; settings.fader_volume_db = 0.0f; + settings.muted = false; settings.locut_enabled = global_flags.locut_enabled; for (unsigned band_index = 0; band_index < NUM_EQ_BANDS; ++band_index) { settings.eq_level_db[band_index] = 0.0f; @@ -335,6 +336,7 @@ AudioMixer::BusSettings AudioMixer::get_bus_settings(unsigned bus_index) const lock_guard lock(audio_mutex); BusSettings settings; settings.fader_volume_db = fader_volume_db[bus_index]; + settings.muted = mute[bus_index]; settings.locut_enabled = locut_enabled[bus_index]; for (unsigned band_index = 0; band_index < NUM_EQ_BANDS; ++band_index) { settings.eq_level_db[band_index] = eq_level_db[bus_index][band_index]; @@ -350,6 +352,7 @@ void AudioMixer::set_bus_settings(unsigned bus_index, const AudioMixer::BusSetti { lock_guard lock(audio_mutex); fader_volume_db[bus_index] = settings.fader_volume_db; + mute[bus_index] = settings.muted; locut_enabled[bus_index] = settings.locut_enabled; for (unsigned band_index = 0; band_index < NUM_EQ_BANDS; ++band_index) { eq_level_db[bus_index][band_index] = settings.eq_level_db[band_index]; @@ -683,13 +686,14 @@ void AudioMixer::add_bus_to_master(unsigned bus_index, const vector &samp assert(samples_bus.size() == samples_out->size()); assert(samples_bus.size() % 2 == 0); unsigned num_samples = samples_bus.size() / 2; - if (fabs(fader_volume_db[bus_index] - last_fader_volume_db[bus_index]) > 1e-3) { + const float new_volume_db = mute[bus_index] ? -90.0f : fader_volume_db[bus_index].load(); + if (fabs(new_volume_db - last_fader_volume_db[bus_index]) > 1e-3) { // The volume has changed; do a fade over the course of this frame. // (We might have some numerical issues here, but it seems to sound OK.) // For the purpose of fading here, the silence floor is set to -90 dB // (the fader only goes to -84). float old_volume = from_db(max(last_fader_volume_db[bus_index], -90.0f)); - float volume = from_db(max(fader_volume_db[bus_index], -90.0f)); + float volume = from_db(max(new_volume_db, -90.0f)); float volume_inc = pow(volume / old_volume, 1.0 / num_samples); volume = old_volume; @@ -706,8 +710,8 @@ void AudioMixer::add_bus_to_master(unsigned bus_index, const vector &samp volume *= volume_inc; } } - } else { - float volume = from_db(fader_volume_db[bus_index]); + } else if (new_volume_db > -90.0f) { + float volume = from_db(new_volume_db); if (bus_index == 0) { for (unsigned i = 0; i < num_samples; ++i) { (*samples_out)[i * 2 + 0] = samples_bus[i * 2 + 0] * volume; @@ -721,13 +725,13 @@ void AudioMixer::add_bus_to_master(unsigned bus_index, const vector &samp } } - last_fader_volume_db[bus_index] = fader_volume_db[bus_index]; + last_fader_volume_db[bus_index] = new_volume_db; } void AudioMixer::measure_bus_levels(unsigned bus_index, const vector &left, const vector &right) { assert(left.size() == right.size()); - const float volume = from_db(fader_volume_db[bus_index]); + const float volume = mute[bus_index] ? 0.0f : from_db(fader_volume_db[bus_index]); const float peak_levels[2] = { find_peak(left.data(), left.size()) * volume, find_peak(right.data(), right.size()) * volume diff --git a/audio_mixer.h b/audio_mixer.h index 38b98f7..8211710 100644 --- a/audio_mixer.h +++ b/audio_mixer.h @@ -67,6 +67,9 @@ public: float get_fader_volume(unsigned bus_index) const { return fader_volume_db[bus_index]; } void set_fader_volume(unsigned bus_index, float level_db) { fader_volume_db[bus_index] = level_db; } + bool get_mute(unsigned bus_index) const { return mute[bus_index]; } + void set_mute(unsigned bus_index, bool muted) { mute[bus_index] = muted; } + // Note: This operation holds all ALSA devices (see ALSAPool::get_devices()). // You will need to call set_input_mapping() to get the hold state correctly, // or every card will be held forever. @@ -281,6 +284,7 @@ public: // or set_* functions for that bus. struct BusSettings { float fader_volume_db; + bool muted; bool locut_enabled; float eq_level_db[NUM_EQ_BANDS]; float gain_staging_db; @@ -367,6 +371,7 @@ private: MappingMode current_mapping_mode; // Under audio_mutex. InputMapping input_mapping; // Under audio_mutex. std::atomic fader_volume_db[MAX_BUSES] {{ 0.0f }}; + std::atomic mute[MAX_BUSES] {{ false }}; float last_fader_volume_db[MAX_BUSES] { 0.0f }; // Under audio_mutex. std::atomic eq_level_db[MAX_BUSES][NUM_EQ_BANDS] {{{ 0.0f }}}; float last_eq_level_db[MAX_BUSES][NUM_EQ_BANDS] {{ 0.0f }}; diff --git a/mainwindow.cpp b/mainwindow.cpp index d92847b..eb78d0e 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -452,6 +452,9 @@ void MainWindow::setup_audio_expanded_view() update_eq_label(bus_index, EQ_BAND_MID, global_audio_mixer->get_eq(bus_index, EQ_BAND_MID)); update_eq_label(bus_index, EQ_BAND_BASS, global_audio_mixer->get_eq(bus_index, EQ_BAND_BASS)); ui_audio_expanded_view->fader->setDbValue(global_audio_mixer->get_fader_volume(bus_index)); + ui_audio_expanded_view->mute_button->setChecked(global_audio_mixer->get_mute(bus_index) ? Qt::Checked : Qt::Unchecked); + connect(ui_audio_expanded_view->mute_button, &QPushButton::toggled, + bind(&MainWindow::mute_button_toggled, this, bus_index, _1)); ui->buses->addWidget(channel); ui_audio_expanded_view->locut_enabled->setChecked(global_audio_mixer->get_locut_enabled(bus_index)); @@ -733,6 +736,12 @@ void MainWindow::mini_fader_changed(int bus, double volume_db) global_audio_mixer->set_fader_volume(bus, volume_db); } +void MainWindow::mute_button_toggled(int bus, bool checked) +{ + global_audio_mixer->set_mute(bus, checked); + midi_mapper.refresh_lights(); +} + void MainWindow::reset_meters_button_clicked() { global_audio_mixer->reset_meters(); @@ -914,6 +923,11 @@ void MainWindow::set_fader(unsigned bus_idx, float value) set_relative_value_if_exists(bus_idx, &Ui::AudioExpandedView::fader, value); } +void MainWindow::toggle_mute(unsigned bus_idx) +{ + click_button_if_exists(bus_idx, &Ui::AudioExpandedView::mute_button); +} + void MainWindow::toggle_locut(unsigned bus_idx) { click_button_if_exists(bus_idx, &Ui::AudioExpandedView::locut_enabled); @@ -955,6 +969,7 @@ void MainWindow::clear_all_highlights() highlight_gain(bus_idx, false); highlight_compressor_threshold(bus_idx, false); highlight_fader(bus_idx, false); + highlight_mute(bus_idx, false); highlight_toggle_locut(bus_idx, false); highlight_toggle_auto_gain_staging(bus_idx, false); highlight_toggle_compressor(bus_idx, false); @@ -1030,6 +1045,11 @@ void MainWindow::highlight_fader(unsigned bus_idx, bool highlight) highlight_control_if_exists(bus_idx, &Ui::AudioExpandedView::fader, highlight); } +void MainWindow::highlight_mute(unsigned bus_idx, bool highlight) +{ + highlight_control_if_exists(bus_idx, &Ui::AudioExpandedView::mute_button, highlight, /*is_mute_btton=*/true); +} + void MainWindow::highlight_toggle_locut(unsigned bus_idx, bool highlight) { highlight_control_if_exists(bus_idx, &Ui::AudioExpandedView::locut_enabled, highlight); @@ -1109,11 +1129,32 @@ void MainWindow::highlight_control(T *control, bool highlight) } template -void MainWindow::highlight_control_if_exists(unsigned bus_idx, T *(Ui_AudioExpandedView::*control), bool highlight) +void MainWindow::highlight_mute_control(T *control, bool highlight) { - post_to_main_thread([this, bus_idx, control, highlight]{ + if (control == nullptr) { + return; + } + if (global_audio_mixer == nullptr || + global_audio_mixer->get_mapping_mode() != AudioMixer::MappingMode::MULTICHANNEL) { + highlight = false; + } + if (highlight) { + control->setStyleSheet("QPushButton { background: rgb(0,255,0,80); } QPushButton:checked { background: rgba(255,80,0,140); }"); + } else { + control->setStyleSheet("QPushButton:checked { background: rgba(255,0,0,80); }"); + } +} + +template +void MainWindow::highlight_control_if_exists(unsigned bus_idx, T *(Ui_AudioExpandedView::*control), bool highlight, bool is_mute_button) +{ + post_to_main_thread([this, bus_idx, control, highlight, is_mute_button]{ if (bus_idx < audio_expanded_views.size()) { - highlight_control(audio_expanded_views[bus_idx]->*control, highlight); + if (is_mute_button) { + highlight_mute_control(audio_expanded_views[bus_idx]->*control, highlight); + } else { + highlight_control(audio_expanded_views[bus_idx]->*control, highlight); + } } }); } diff --git a/mainwindow.h b/mainwindow.h index f0729a6..8dfbf83 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -60,6 +60,7 @@ public slots: void limiter_threshold_knob_changed(int value); void compressor_threshold_knob_changed(unsigned bus_index, int value); void mini_fader_changed(int bus, double db_volume); + void mute_button_toggled(int bus, bool checked); void reset_meters_button_clicked(); void relayout(); @@ -75,6 +76,7 @@ public slots: void set_compressor_threshold(unsigned bus_idx, float value) override; void set_fader(unsigned bus_idx, float value) override; + void toggle_mute(unsigned bus_idx) override; void toggle_locut(unsigned bus_idx) override; void toggle_auto_gain_staging(unsigned bus_idx) override; void toggle_compressor(unsigned bus_idx) override; @@ -95,6 +97,7 @@ public slots: void highlight_compressor_threshold(unsigned bus_idx, bool highlight) override; void highlight_fader(unsigned bus_idx, bool highlight) override; + void highlight_mute(unsigned bus_idx, bool highlight) override; void highlight_toggle_locut(unsigned bus_idx, bool highlight) override; void highlight_toggle_auto_gain_staging(unsigned bus_idx, bool highlight) override; void highlight_toggle_compressor(unsigned bus_idx, bool highlight) override; @@ -137,7 +140,10 @@ private: void highlight_control(T *control, bool highlight); template - void highlight_control_if_exists(unsigned bus_idx, T *(Ui_AudioExpandedView::*control), bool highlight); + void highlight_mute_control(T *control, bool highlight); + + template + void highlight_control_if_exists(unsigned bus_idx, T *(Ui_AudioExpandedView::*control), bool highlight, bool is_mute_button = false); Ui::MainWindow *ui; QLabel *disk_free_label; diff --git a/midi_mapper.cpp b/midi_mapper.cpp index ba996e8..8f43d21 100644 --- a/midi_mapper.cpp +++ b/midi_mapper.cpp @@ -335,6 +335,8 @@ void MIDIMapper::handle_event(snd_seq_t *seq, snd_seq_event_t *event) bind(&ControllerReceiver::toggle_compressor, receiver, _1)); match_button(note, MIDIMappingBusProto::kClearPeakFieldNumber, MIDIMappingProto::kClearPeakBankFieldNumber, bind(&ControllerReceiver::clear_peak, receiver, _1)); + match_button(note, MIDIMappingBusProto::kToggleMuteFieldNumber, MIDIMappingProto::kClearPeakBankFieldNumber, + bind(&ControllerReceiver::toggle_mute, receiver, _1)); match_button(note, MIDIMappingBusProto::kToggleLimiterFieldNumber, MIDIMappingProto::kToggleLimiterBankFieldNumber, bind(&ControllerReceiver::toggle_limiter, receiver)); match_button(note, MIDIMappingBusProto::kToggleAutoMakeupGainFieldNumber, MIDIMappingProto::kToggleAutoMakeupGainBankFieldNumber, @@ -534,6 +536,8 @@ void MIDIMapper::update_highlights() bus_idx, MIDIMappingBusProto::kCompressorThresholdFieldNumber, MIDIMappingProto::kCompressorThresholdBankFieldNumber)); receiver->highlight_fader(bus_idx, has_active_controller( bus_idx, MIDIMappingBusProto::kFaderFieldNumber, MIDIMappingProto::kFaderBankFieldNumber)); + receiver->highlight_mute(bus_idx, has_active_controller( + bus_idx, MIDIMappingBusProto::kToggleMuteFieldNumber, MIDIMappingProto::kToggleMuteBankFieldNumber)); receiver->highlight_toggle_locut(bus_idx, has_active_controller( bus_idx, MIDIMappingBusProto::kToggleLocutFieldNumber, MIDIMappingProto::kToggleLocutBankFieldNumber)); receiver->highlight_toggle_auto_gain_staging(bus_idx, has_active_controller( @@ -573,6 +577,9 @@ void MIDIMapper::update_lights_lock_held() } unsigned num_buses = min(global_audio_mixer->num_buses(), mapping_proto->bus_mapping_size()); for (unsigned bus_idx = 0; bus_idx < num_buses; ++bus_idx) { + if (global_audio_mixer->get_mute(bus_idx)) { + activate_lights(bus_idx, MIDIMappingBusProto::kIsMutedFieldNumber, &active_lights); + } if (global_audio_mixer->get_locut_enabled(bus_idx)) { activate_lights(bus_idx, MIDIMappingBusProto::kLocutIsOnFieldNumber, &active_lights); } diff --git a/midi_mapper.h b/midi_mapper.h index 6274616..04e5192 100644 --- a/midi_mapper.h +++ b/midi_mapper.h @@ -39,6 +39,7 @@ public: virtual void set_compressor_threshold(unsigned bus_idx, float value) = 0; virtual void set_fader(unsigned bus_idx, float value) = 0; + virtual void toggle_mute(unsigned bus_idx) = 0; virtual void toggle_locut(unsigned bus_idx) = 0; virtual void toggle_auto_gain_staging(unsigned bus_idx) = 0; virtual void toggle_compressor(unsigned bus_idx) = 0; @@ -61,6 +62,7 @@ public: virtual void highlight_compressor_threshold(unsigned bus_idx, bool highlight) = 0; virtual void highlight_fader(unsigned bus_idx, bool highlight) = 0; + virtual void highlight_mute(unsigned bus_idx, bool highlight) = 0; virtual void highlight_toggle_locut(unsigned bus_idx, bool highlight) = 0; virtual void highlight_toggle_auto_gain_staging(unsigned bus_idx, bool highlight) = 0; virtual void highlight_toggle_compressor(unsigned bus_idx, bool highlight) = 0; diff --git a/midi_mapping.proto b/midi_mapping.proto index d2b170d..36bfe8d 100644 --- a/midi_mapping.proto +++ b/midi_mapping.proto @@ -31,50 +31,50 @@ message MIDIMappingBusProto { optional MIDIControllerProto compressor_threshold = 6; optional MIDIControllerProto fader = 7; - // TODO: Add mute and cue? (Of course, we should those to the UI before - // making them MIDI controllable.) - optional MIDIButtonProto toggle_locut = 8; - optional MIDIButtonProto toggle_auto_gain_staging = 9; - optional MIDIButtonProto toggle_compressor = 10; - optional MIDIButtonProto clear_peak = 11; + optional MIDIButtonProto toggle_mute = 8; + optional MIDIButtonProto toggle_locut = 9; + optional MIDIButtonProto toggle_auto_gain_staging = 10; + optional MIDIButtonProto toggle_compressor = 11; + optional MIDIButtonProto clear_peak = 12; // These are really global (controller bank change affects all buss), // but it's not uncommon that we'd want one button per bus to switch banks. // E.g., if the user binds the “mute” button to “next bank”, they'd want every // mute button on the mixer to do that, so they need one mapping per bus. - optional MIDIButtonProto prev_bank = 12; - optional MIDIButtonProto next_bank = 13; - optional MIDIButtonProto select_bank_1 = 14; - optional MIDIButtonProto select_bank_2 = 15; - optional MIDIButtonProto select_bank_3 = 16; - optional MIDIButtonProto select_bank_4 = 17; - optional MIDIButtonProto select_bank_5 = 18; - optional MIDIButtonProto toggle_limiter = 19; - optional MIDIButtonProto toggle_auto_makeup_gain = 20; + optional MIDIButtonProto prev_bank = 13; + optional MIDIButtonProto next_bank = 14; + optional MIDIButtonProto select_bank_1 = 15; + optional MIDIButtonProto select_bank_2 = 16; + optional MIDIButtonProto select_bank_3 = 17; + optional MIDIButtonProto select_bank_4 = 18; + optional MIDIButtonProto select_bank_5 = 19; + optional MIDIButtonProto toggle_limiter = 20; + optional MIDIButtonProto toggle_auto_makeup_gain = 21; // These are also global (they belong to the master bus), and unlike // the bank change commands, one would usually have only one of each, // but there's no reason to limit them to one each, and the editor UI // becomes simpler if they are the treated the same way as the bank // commands. - optional MIDIControllerProto locut = 21; - optional MIDIControllerProto limiter_threshold = 22; - optional MIDIControllerProto makeup_gain = 23; + optional MIDIControllerProto locut = 22; + optional MIDIControllerProto limiter_threshold = 23; + optional MIDIControllerProto makeup_gain = 24; // Per-bus lights. - optional MIDILightProto locut_is_on = 24; - optional MIDILightProto auto_gain_staging_is_on = 25; - optional MIDILightProto compressor_is_on = 26; - optional MIDILightProto has_peaked = 27; + optional MIDILightProto is_muted = 25; + optional MIDILightProto locut_is_on = 26; + optional MIDILightProto auto_gain_staging_is_on = 27; + optional MIDILightProto compressor_is_on = 28; + optional MIDILightProto has_peaked = 29; // Global lights. Same logic as above for why they're in this proto. - optional MIDILightProto bank_1_is_selected = 28; - optional MIDILightProto bank_2_is_selected = 29; - optional MIDILightProto bank_3_is_selected = 30; - optional MIDILightProto bank_4_is_selected = 31; - optional MIDILightProto bank_5_is_selected = 32; - optional MIDILightProto limiter_is_on = 33; - optional MIDILightProto auto_makeup_gain_is_on = 34; + optional MIDILightProto bank_1_is_selected = 30; + optional MIDILightProto bank_2_is_selected = 31; + optional MIDILightProto bank_3_is_selected = 32; + optional MIDILightProto bank_4_is_selected = 33; + optional MIDILightProto bank_5_is_selected = 34; + optional MIDILightProto limiter_is_on = 35; + optional MIDILightProto auto_makeup_gain_is_on = 36; } // The top-level protobuf, containing all the bus mappings, as well as @@ -98,19 +98,20 @@ message MIDIMappingProto { optional int32 fader_bank = 7; // Bus button banks. - optional int32 toggle_locut_bank = 8; - optional int32 toggle_auto_gain_staging_bank = 9; - optional int32 toggle_compressor_bank = 10; - optional int32 clear_peak_bank = 11; + optional int32 toggle_mute_bank = 8; + optional int32 toggle_locut_bank = 9; + optional int32 toggle_auto_gain_staging_bank = 10; + optional int32 toggle_compressor_bank = 11; + optional int32 clear_peak_bank = 12; // Global controller banks. - optional int32 locut_bank = 12; - optional int32 limiter_threshold_bank = 13; - optional int32 makeup_gain_bank = 14; + optional int32 locut_bank = 13; + optional int32 limiter_threshold_bank = 14; + optional int32 makeup_gain_bank = 15; // Global buttons. - optional int32 toggle_limiter_bank = 15; - optional int32 toggle_auto_makeup_gain_bank = 16; + optional int32 toggle_limiter_bank = 16; + optional int32 toggle_auto_makeup_gain_bank = 17; - repeated MIDIMappingBusProto bus_mapping = 17; + repeated MIDIMappingBusProto bus_mapping = 18; } diff --git a/midi_mapping_dialog.cpp b/midi_mapping_dialog.cpp index 95de0d9..9e5d11b 100644 --- a/midi_mapping_dialog.cpp +++ b/midi_mapping_dialog.cpp @@ -26,6 +26,8 @@ vector per_bus_controllers = { { "Fader", MIDIMappingBusProto::kFaderFieldNumber, MIDIMappingProto::kFaderBankFieldNumber } }; vector per_bus_buttons = { + { "Toggle mute", MIDIMappingBusProto::kToggleMuteFieldNumber, + MIDIMappingProto::kToggleMuteBankFieldNumber }, { "Toggle locut", MIDIMappingBusProto::kToggleLocutFieldNumber, MIDIMappingProto::kToggleLocutBankFieldNumber }, { "Togle auto gain staging", MIDIMappingBusProto::kToggleAutoGainStagingFieldNumber, @@ -36,6 +38,7 @@ vector per_bus_buttons = { MIDIMappingProto::kClearPeakBankFieldNumber } }; vector per_bus_lights = { + { "Is muted", MIDIMappingBusProto::kIsMutedFieldNumber, 0 }, { "Locut is on", MIDIMappingBusProto::kLocutIsOnFieldNumber, 0 }, { "Auto gain staging is on", MIDIMappingBusProto::kAutoGainStagingIsOnFieldNumber, 0 }, { "Compressor is on", MIDIMappingBusProto::kCompressorIsOnFieldNumber, 0 }, diff --git a/midi_mapping_dialog.h b/midi_mapping_dialog.h index 465f8fd..a413ef1 100644 --- a/midi_mapping_dialog.h +++ b/midi_mapping_dialog.h @@ -51,6 +51,7 @@ public: void set_compressor_threshold(unsigned bus_idx, float value) override {} void set_fader(unsigned bus_idx, float value) override {} + void toggle_mute(unsigned bus_idx) override {} void toggle_locut(unsigned bus_idx) override {} void toggle_auto_gain_staging(unsigned bus_idx) override {} void toggle_compressor(unsigned bus_idx) override {} @@ -71,6 +72,7 @@ public: void highlight_compressor_threshold(unsigned bus_idx, bool highlight) override {} void highlight_fader(unsigned bus_idx, bool highlight) override {} + void highlight_mute(unsigned bus_idx, bool highlight) override {} void highlight_toggle_locut(unsigned bus_idx, bool highlight) override {} void highlight_toggle_auto_gain_staging(unsigned bus_idx, bool highlight) override {} void highlight_toggle_compressor(unsigned bus_idx, bool highlight) override {} diff --git a/ui_audio_expanded_view.ui b/ui_audio_expanded_view.ui index 489e4b2..46142e3 100644 --- a/ui_audio_expanded_view.ui +++ b/ui_audio_expanded_view.ui @@ -401,7 +401,47 @@ - + + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 40 + 22 + + + + + 8 + + + + QPushButton:checked { background: rgba(255,0,0,80); } + + + Mute + + + true + + + + + @@ -451,6 +491,11 @@
vumeter.h
1 + + ClickableLabel + QLabel +
clickable_label.h
+
NonLinearFader QSlider @@ -461,11 +506,6 @@ QLabel
ellipsis_label.h
- - ClickableLabel - QLabel -
clickable_label.h
-
-- 2.39.2