From d7113254492403d0b70f0a6bb0a9c8670e636445 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 22 Jan 2020 13:54:34 -0500 Subject: [PATCH] Better Slider Modulation Visualization (#1498) The sliders are always confusing as to exactly how far you are modulationg, especially with hidden bi- and uni-polar stuff. So draw a distance line which acts accordingly under the handles in modulation mode. Also, remove the annoying modulation blink --- src/common/SurgeSynthesizer.cpp | 30 ++++ src/common/SurgeSynthesizer.h | 1 + src/common/gui/CModulationSourceButton.cpp | 4 +- src/common/gui/CSurgeSlider.cpp | 168 +++++++++++++++++++-- src/common/gui/CSurgeSlider.h | 7 +- src/common/gui/SurgeGUIEditor.cpp | 8 +- 6 files changed, 195 insertions(+), 23 deletions(-) diff --git a/src/common/SurgeSynthesizer.cpp b/src/common/SurgeSynthesizer.cpp index fd72c08dec0..fcd5b32aa21 100644 --- a/src/common/SurgeSynthesizer.cpp +++ b/src/common/SurgeSynthesizer.cpp @@ -1647,6 +1647,36 @@ bool SurgeSynthesizer::isActiveModulation(long ptag, modsources modsource) return false; } +bool SurgeSynthesizer::isBipolarModulation(modsources tms) +{ + // HERE + int scene_ms = storage.getPatch().scene_active.val.i; + /* You would think you could just do this nad ask for is_bipolar but remember the LFOs are made at voice time so... */ + // auto ms = storage.getPatch().scene[scene_ms].modsources.at(tms); + + // FIX - this will break in S++ + if( tms >= ms_lfo1 && tms <= ms_slfo6 ) + { + bool isup = storage.getPatch().scene[scene_ms].lfo[tms-ms_lfo1].unipolar.val.i; + // For now + return !isup; + } + if( tms >= ms_ctrl1 && tms <= ms_ctrl8 ) + { + // Controls can also be bipolar + auto ms = storage.getPatch().scene[scene_ms].modsources[tms]; + if( ms ) + return ms->is_bipolar(); + else + return false; + } + else + { + return false; + } +} + + bool SurgeSynthesizer::isModDestUsed(long ptag) { int scene_ms = storage.getPatch().scene_active.val.i; diff --git a/src/common/SurgeSynthesizer.h b/src/common/SurgeSynthesizer.h index d53e237d154..b7a79282de5 100644 --- a/src/common/SurgeSynthesizer.h +++ b/src/common/SurgeSynthesizer.h @@ -128,6 +128,7 @@ class alignas(16) SurgeSynthesizer // float getParameter (long index); bool isValidModulation(long ptag, modsources modsource); bool isActiveModulation(long ptag, modsources modsource); + bool isBipolarModulation(modsources modsources); bool isModsourceUsed(modsources modsource); bool isModDestUsed(long moddest); ModulationRouting* getModRouting(long ptag, modsources modsource); diff --git a/src/common/gui/CModulationSourceButton.cpp b/src/common/gui/CModulationSourceButton.cpp index c5b4261e0b4..7f2d59d6c0d 100644 --- a/src/common/gui/CModulationSourceButton.cpp +++ b/src/common/gui/CModulationSourceButton.cpp @@ -142,8 +142,8 @@ void CModulationSourceButton::draw(CDrawContext* dc) FontCol = UsedOrActive ? ColEdge : ColSemiTint; if (ActiveModSource) { - FrameCol = blink ? ColBlink : ColTint; - FillCol = blink ? ColBlink : ColTint; + FrameCol = ColBlink; // blink ? ColBlink : ColTint; + FillCol = ColBlink; // blink ? ColBlink : ColTint; FontCol = ColBG; } else if (SelectedModSource) diff --git a/src/common/gui/CSurgeSlider.cpp b/src/common/gui/CSurgeSlider.cpp index 663b0d86109..1301eb40e89 100644 --- a/src/common/gui/CSurgeSlider.cpp +++ b/src/common/gui/CSurgeSlider.cpp @@ -226,30 +226,170 @@ void CSurgeSlider::draw(CDrawContext* dc) dc->drawString(leftlabel, trect, kLeftText, true); } - if (pHandle && (modmode != 2)) + CRect hrect(headrect); + handle_rect = handle_rect_orig; + hrect.offset(size.left, size.top); + if (style & CSlider::kHorizontal) + hrect.offset(0, 3); + + float dispv = limit_range(qdvalue, 0.f, 1.f); + if (style & CSlider::kRight || style & CSlider::kBottom) + dispv = 1 - dispv; + dispv *= range; + + if (style & CSlider::kHorizontal) { - CRect hrect(headrect); - handle_rect = handle_rect_orig; - hrect.offset(size.left, size.top); - if (style & CSlider::kHorizontal) - hrect.offset(0, 3); + hrect.offset(dispv + 1, 0); + handle_rect.offset(dispv + 1, 0); + } + else + { + hrect.offset(1, dispv); + handle_rect.offset(1, dispv); + } - float dispv = limit_range(qdvalue, 0.f, 1.f); - if (style & CSlider::kRight || style & CSlider::kBottom) - dispv = 1 - dispv; - dispv *= range; + if( modmode ) + { + CRect trect = hrect; + const CColor ColBar = CColor(173, 255, 107, 255 ); + + // float moddist = modval * range; + // We want modval + value to be bould by -1 and 1. So + float modup = modval; + bool overtop = false; + float moddn = modval; + bool overbot = false; + if( modup + value > 1.f ) + { + overtop = true; + modup = 1.f - value; + } + if( modup + value < 0.f ) + { + overbot = true; + modup = 0.f - value; + } + if( value - moddn < 0.f ) + { + overbot = true; + moddn = value + 0.f; + } + if( value - moddn > 1.f ) + { + overtop = true; + moddn = value - 1.f; + } + // at some point in the future draw something special with overtop and overbot + + modup *= range; + moddn *= range; + /* + if( modval != 0 ) + std::cout << "mv=" << modval + << " val=" << value + << " rn=" << range + << " mu=" << modup + << " md=" << moddn << std::endl; + */ + + std::vector drawThese; if (style & CSlider::kHorizontal) { - hrect.offset(dispv + 1, 0); - handle_rect.offset(dispv + 1, 0); + trect.top += 7; + trect.bottom = trect.top + 4; + float modDistance = 40; + if( ! modulation_is_bipolar ) + { + trect.left += 11; + trect.right = trect.left + modup; + } + else + { + trect.left += 11; + trect.right = trect.left + modup; + trect.left -= moddn; + } + if( trect.left > trect.right ) + std::swap( trect.left, trect.right ); + drawThese.push_back( trect ); + + if( overtop ) + { + CRect topr; + topr.top = trect.top; + topr.bottom = trect.bottom; + topr.left = trect.right + 1; + topr.right = topr.left + 3; + drawThese.push_back(topr); + } + + if( overbot ) + { + CRect topr; + topr.top = trect.top; + topr.bottom = trect.bottom; + topr.left = trect.left - 4; + topr.right = topr.left + 3; + drawThese.push_back(topr); + } } else { - hrect.offset(1, dispv); - handle_rect.offset(1, dispv); + trect.left += 7; + trect.right = trect.left + 4; + if( ! modulation_is_bipolar ) + { + trect.top += 11; + trect.bottom = trect.top - modup; + } + else + { + trect.top += 11; + trect.bottom = trect.top - modup; + trect.top += moddn; + } + + if( overbot ) + { + CRect topr; + topr.left = trect.left; + topr.right = trect.right; + topr.bottom = trect.top + 1; + topr.top = topr.bottom + 3; + drawThese.push_back(topr); + } + + if( overtop ) + { + CRect topr; + topr.left = trect.left; + topr.right = trect.right; + topr.top = trect.top - 1; + topr.bottom = topr.top - 3; + drawThese.push_back(topr); + } + + if( trect.top < trect.bottom ) + std::swap( trect.top, trect.bottom ); + drawThese.push_back( trect ); } + for( auto r : drawThese ) + { + dc->setFillColor( ColBar ); + dc->drawRect( r, VSTGUI::kDrawFilled ); + dc->setLineWidth( 0.5 ); + dc->setFrameColor( VSTGUI::kBlackCColor ); + r.right += 0.9; + r.bottom += 0.9; + dc->drawRect( r, VSTGUI::kDrawStroked ); + } + } + + + if (pHandle && (modmode != 2)) + { if (style & CSlider::kHorizontal) { pHandle->draw(dc, hrect, CPoint(0, 24 * typehy), modmode ? 0x7f : 0xff); diff --git a/src/common/gui/CSurgeSlider.h b/src/common/gui/CSurgeSlider.h index 5d705fd7496..f186a1a14b8 100644 --- a/src/common/gui/CSurgeSlider.h +++ b/src/common/gui/CSurgeSlider.h @@ -49,9 +49,10 @@ class CSurgeSlider : public CCursorHidingControl { has_modulation = b; } // true if the slider has modulation routings assigned to it - virtual void setModCurrent(bool b) + virtual void setModCurrent(bool isCurrent, bool isBipolarModulator) { - has_modulation_current = b; + has_modulation_current = isCurrent; + modulation_is_bipolar = isBipolarModulator; invalid(); } // - " " - for the currently selected modsource virtual void bounceValue(const bool keeprest = false); @@ -94,7 +95,7 @@ class CSurgeSlider : public CCursorHidingControl float moverate, statezoom; int typex, typey; int typehx, typehy; - bool has_modulation, has_modulation_current; + bool has_modulation, has_modulation_current, modulation_is_bipolar = false; bool is_temposync = false; VSTGUI::CPoint lastpoint, sourcepoint; float oldVal, *edit_value; diff --git a/src/common/gui/SurgeGUIEditor.cpp b/src/common/gui/SurgeGUIEditor.cpp index 9494ce478b3..5b86403f929 100644 --- a/src/common/gui/SurgeGUIEditor.cpp +++ b/src/common/gui/SurgeGUIEditor.cpp @@ -606,7 +606,7 @@ void SurgeGUIEditor::refresh_mod() { s->setModMode(mod_editor ? 1 : 0); s->setModPresent(synth->isModDestUsed(i)); - s->setModCurrent(synth->isActiveModulation(i, thisms)); + s->setModCurrent(synth->isActiveModulation(i, thisms), synth->isBipolarModulation(thisms)); } // s->setDirty(); s->setModValue(synth->getModulation(i, thisms)); @@ -1369,7 +1369,7 @@ void SurgeGUIEditor::openOrRecreateEditor() hs->setModMode(mod_editor ? 1 : 0); hs->setModValue(synth->getModulation(p->id, modsource)); hs->setModPresent(synth->isModDestUsed(p->id)); - hs->setModCurrent(synth->isActiveModulation(p->id, modsource)); + hs->setModCurrent(synth->isActiveModulation(p->id, modsource), synth->isBipolarModulation(modsource)); hs->setValue(p->get_value_f01()); hs->setLabel(p->get_name()); hs->setMoveRate(p->moverate); @@ -2413,7 +2413,7 @@ int32_t SurgeGUIEditor::controlModifierClicked(CControl* control, CButtonState b synth->clearModulation(ptag, thisms); ((CSurgeSlider*)control)->setModValue(synth->getModulation(p->id, thisms)); ((CSurgeSlider*)control)->setModPresent(synth->isModDestUsed(p->id)); - ((CSurgeSlider*)control)->setModCurrent(synth->isActiveModulation(p->id, thisms)); + ((CSurgeSlider*)control)->setModCurrent(synth->isActiveModulation(p->id, thisms), synth->isBipolarModulation(thisms)); // control->setGhostValue(p->get_value_f01()); oscdisplay->invalid(); return 1; @@ -2717,7 +2717,7 @@ void SurgeGUIEditor::valueChanged(CControl* control) } synth->setModulation(ptag, thisms, ((CSurgeSlider*)control)->getModValue()); ((CSurgeSlider*)control)->setModPresent(synth->isModDestUsed(p->id)); - ((CSurgeSlider*)control)->setModCurrent(synth->isActiveModulation(p->id, thisms)); + ((CSurgeSlider*)control)->setModCurrent(synth->isActiveModulation(p->id, thisms), synth->isBipolarModulation(thisms)); synth->getParameterName(ptag, txt); sprintf(pname, "%s -> %s", modsource_abberations_short[thisms], txt);