LCOV - code coverage report
Current view: top level - src/gui/pedalboard - pedal_widget.cpp (source / functions) Coverage Total Hit
Test: merged.info Lines: 89.8 % 137 123
Test Date: 2026-06-07 15:51:50 Functions: 45.5 % 11 5

            Line data    Source code
       1              : #include "gui/pedalboard/pedal_widget.h"
       2              : 
       3              : #include <cmath>
       4              : #include <cstring>
       5              : 
       6              : #include "audio/effects/amp_cab/amp_simulator.h"
       7              : #include "audio/effects/utility/tuner.h"
       8              : #include "audio/engine/audio_engine.h"
       9              : #include "gui/commands/command.h"
      10              : #include "gui/commands/command_history.h"
      11              : #include "gui/components/footswitch.h"
      12              : #include "gui/components/led.h"
      13              : #include "gui/components/screen.h"
      14              : #include "gui/dialogs/file_dialog.h"
      15              : #include "gui/theme/theme.h"
      16              : #include "gui/views/gui_midi.h"
      17              : 
      18              : namespace Amplitron {
      19              : 
      20              : /** @brief Construct PedalWidget and look up color scheme for the effect type. */
      21          172 : PedalWidget::PedalWidget(IAudioEngine& engine, std::shared_ptr<Effect> effect, int index)
      22          172 :     : engine_(engine), effect_(std::move(effect)), index_(index) {
      23          129 :     assign_colors();
      24          129 : }
      25              : 
      26              : /** @brief Look up pedal_color_ and led_color_ from the theme's effect color table. */
      27          129 : void PedalWidget::assign_colors() {
      28          129 :     const auto* entry = get_effect_color(effect_->name());
      29          129 :     pedal_color_ = entry->pedal_color;
      30          129 :     led_color_ = entry->led_color;
      31          129 : }
      32              : 
      33              : /** @brief Render the full pedal widget (body, knobs, switch, LED). @return true if remove
      34              :  * requested. */
      35          171 : bool PedalWidget::render(float zoom) {
      36          171 :     bool should_remove = false;
      37              : 
      38          171 :     ImGui::PushID(index_);
      39              : 
      40          171 :     bool is_amp = (std::strcmp(effect_->name(), "Amp Sim") == 0);
      41          171 :     bool is_mb_comp = (std::strcmp(effect_->name(), "MultiBand Compressor") == 0);
      42          171 :     bool enabled = effect_->is_enabled();
      43          171 :     bool is_looper = !is_amp && (std::strcmp(effect_->name(), "Looper") == 0);
      44              : 
      45          171 :     float pedal_width =
      46          171 :         is_mb_comp ? (Theme::PEDAL_WIDTH * 2.2f * zoom) : (Theme::PEDAL_WIDTH * zoom);
      47          171 :     float pedal_height = Theme::PEDAL_HEIGHT * zoom;
      48              : 
      49          171 :     ImVec2 cursor = ImGui::GetCursorScreenPos();
      50          171 :     ImDrawList* dl = ImGui::GetWindowDrawList();
      51              : 
      52              :     // Pedal body
      53          171 :     ImVec2 p0 = cursor;
      54          171 :     ImVec2 p1 = ImVec2(cursor.x + pedal_width, cursor.y + pedal_height);
      55              : 
      56              :     // Shadow
      57          285 :     dl->AddRectFilled(ImVec2(p0.x + 4 * zoom, p0.y + 4 * zoom),
      58          171 :                       ImVec2(p1.x + 4 * zoom, p1.y + 4 * zoom), Theme::PEDAL_SHADOW,
      59           57 :                       Theme::ROUNDING_MD * zoom);
      60              : 
      61          171 :     if (is_amp) {
      62           12 :         render_amp_cabinet(dl, p0, p1, pedal_width, pedal_height, zoom);
      63            4 :     } else {
      64          159 :         render_standard_pedal(dl, p0, p1, pedal_width, enabled, zoom);
      65              :     }
      66              : 
      67              :     // Dim the pedal body when bypassed so the inactive state is immediately obvious
      68          171 :     if (!enabled && !is_amp) {
      69            6 :         dl->AddRectFilled(p0, p1, Theme::PEDAL_BYPASS_OVERLAY, Theme::ROUNDING_MD * zoom);
      70            2 :     }
      71              : 
      72              :     // --- Tuner custom display ---
      73          171 :     bool is_tuner = !is_amp && (std::strcmp(effect_->name(), "Tuner") == 0);
      74          115 :     if (is_tuner) {
      75            3 :         ScreenProps props;
      76            3 :         props.type = ScreenType::Tuner;
      77            3 :         props.effect = effect_;
      78            3 :         props.index = index_;
      79            3 :         props.engine = &engine_;
      80            3 :         props.gui_midi = gui_midi_;
      81            5 :         props.on_commit_param_change = [this](int pi, float old_val, float new_val) {
      82            0 :             commit_param_change(pi, old_val, new_val);
      83            2 :         };
      84            3 :         ScreenComponent::render(dl, p0, pedal_width, zoom, props);
      85            3 :     }
      86              : 
      87              :     // --- IR Cabinet custom display ---
      88          171 :     bool is_ir_cab = !is_amp && (std::strcmp(effect_->name(), "Cabinet") == 0);
      89          115 :     if (is_ir_cab) {
      90            3 :         ScreenProps props;
      91            3 :         props.type = ScreenType::Cabinet;
      92            3 :         props.effect = effect_;
      93            3 :         props.index = index_;
      94            3 :         props.engine = &engine_;
      95            3 :         props.gui_midi = gui_midi_;
      96            5 :         props.on_commit_param_change = [this](int pi, float old_val, float new_val) {
      97            0 :             commit_param_change(pi, old_val, new_val);
      98            2 :         };
      99            3 :         ScreenComponent::render(dl, p0, pedal_width, zoom, props);
     100            3 :     }
     101              : 
     102          171 :     if (is_looper) {
     103            3 :         ScreenProps props;
     104            3 :         props.type = ScreenType::Looper;
     105            3 :         props.effect = effect_;
     106            3 :         props.index = index_;
     107            3 :         props.engine = &engine_;
     108            3 :         props.gui_midi = gui_midi_;
     109            5 :         props.on_commit_param_change = [this](int pi, float old_val, float new_val) {
     110            0 :             commit_param_change(pi, old_val, new_val);
     111            2 :         };
     112            3 :         ScreenComponent::render(dl, p0, pedal_width, zoom, props);
     113          171 :     } else if (is_mb_comp) {
     114            3 :         ScreenProps props;
     115            3 :         props.type = ScreenType::MultiBandCompressor;
     116            3 :         props.effect = effect_;
     117            3 :         props.index = index_;
     118            3 :         props.engine = &engine_;
     119            3 :         props.gui_midi = gui_midi_;
     120            5 :         props.on_commit_param_change = [this](int pi, float old_val, float new_val) {
     121            0 :             commit_param_change(pi, old_val, new_val);
     122            2 :         };
     123            3 :         ScreenComponent::render(dl, p0, pedal_width, zoom, props);
     124            3 :     } else {
     125          165 :         render_knobs(dl, p0, pedal_width, is_amp, is_tuner, is_ir_cab, zoom);
     126              :     }
     127              : 
     128          228 :     render_footswitch_and_extras(dl, p0, p1, pedal_width, pedal_height, is_amp, enabled,
     129           57 :                                  should_remove, zoom);
     130              : 
     131          171 :     ImGui::PopID();
     132          171 :     return should_remove;
     133            0 : }
     134              : 
     135          162 : void PedalWidget::render_standard_pedal(ImDrawList* dl, ImVec2 p0, ImVec2 p1, float pedal_width,
     136              :                                         bool enabled, float zoom) {
     137              :     // ========== STANDARD PEDAL VISUAL ==========
     138          162 :     ImU32 body_color = ImGui::ColorConvertFloat4ToU32(pedal_color_);
     139          162 :     dl->AddRectFilled(p0, p1, body_color, Theme::ROUNDING_MD * zoom);
     140          162 :     dl->AddRect(p0, p1, Theme::PEDAL_BORDER, Theme::ROUNDING_MD * zoom, 0, 2.0f * zoom);
     141              : 
     142              :     // Metallic top plate
     143          162 :     ImVec2 plate_p0 = ImVec2(p0.x + 8 * zoom, p0.y + 8 * zoom);
     144          162 :     ImVec2 plate_p1 = ImVec2(p1.x - 8 * zoom, p0.y + 45 * zoom);
     145          162 :     dl->AddRectFilled(plate_p0, plate_p1, Theme::PEDAL_PLATE, Theme::ROUNDING_SM * zoom);
     146              : 
     147              :     // Effect name
     148          162 :     ImGui::SetCursorScreenPos(ImVec2(p0.x + 12 * zoom, p0.y + 14 * zoom));
     149          162 :     ImGui::PushStyleColor(ImGuiCol_Text, Theme::TextPrimary());
     150          162 :     ImGui::Text("%s", effect_->name());
     151          162 :     ImGui::PopStyleColor();
     152              : 
     153              :     // Reusable status LED indicator
     154          162 :     float led_x = p0.x + pedal_width - 25 * zoom;
     155          162 :     float led_y = p0.y + 20 * zoom;
     156              : 
     157          162 :     LedProps led_props;
     158          162 :     led_props.enabled = enabled;
     159          162 :     led_props.led_color = led_color_;
     160          162 :     led_props.tooltip = enabled ? "Effect active" : "Effect bypassed";
     161              : 
     162           54 :     char led_id[64];
     163          162 :     std::snprintf(led_id, sizeof(led_id), "##led_%d", index_);
     164          162 :     LedComponent::render(led_id, led_props, zoom, ImVec2(led_x, led_y));
     165          162 : }
     166              : 
     167          171 : void PedalWidget::render_footswitch_and_extras(ImDrawList* dl, ImVec2 p0, ImVec2 p1,
     168              :                                                float pedal_width, float pedal_height, bool is_amp,
     169              :                                                bool enabled, bool& should_remove, float zoom) {
     170           57 :     (void)p1;
     171          114 :     (void)should_remove;
     172           57 :     (void)dl;
     173          171 :     bool is_looper = !is_amp && (std::strcmp(effect_->name(), "Looper") == 0);
     174              : 
     175              :     // Footswitch (toggle on/off) — amps are always on, no footswitch
     176          166 :     if (!is_amp && !is_looper) {
     177          156 :         float switch_y = p0.y + pedal_height - Theme::SWITCH_BOTTOM_OFFSET * zoom;
     178          156 :         float switch_x = p0.x + (pedal_width - 50 * zoom) / 2;
     179          156 :         ImVec2 sw_center = ImVec2(switch_x + 25 * zoom, switch_y + 15 * zoom);
     180              : 
     181          156 :         FootswitchProps fs_props;
     182          156 :         fs_props.enabled = enabled;
     183          156 :         fs_props.tooltip_prefix = "";
     184          260 :         fs_props.on_clicked = [this, enabled]() {
     185            0 :             bool new_enabled = !enabled;
     186            0 :             effect_->set_enabled(new_enabled);
     187            0 :             engine_.push_effect_enabled(index_, new_enabled ? 1.0f : 0.0f);
     188          104 :         };
     189              : 
     190           52 :         char sw_id[64];
     191          156 :         std::snprintf(sw_id, sizeof(sw_id), "##switch_%d", index_);
     192          156 :         FootswitchComponent::render(sw_id, fs_props, zoom, sw_center);
     193          156 :     }
     194          171 : }
     195              : 
     196            0 : void PedalWidget::commit_param_change(int param_index, float old_val, float new_val) {
     197            0 :     if (!history_) return;
     198            0 :     auto cmd =
     199            0 :         std::make_unique<ParameterChangeCommand>(engine_, effect_, param_index, old_val, new_val);
     200            0 :     history_->push_executed(std::move(cmd));
     201            0 : }
     202              : 
     203              : }  // namespace Amplitron
        

Generated by: LCOV version 2.0-1