Skip to content

Commit c6195b2

Browse files
authored
Convolution FX IR prev/next buttons (#8342)
* Convolution FX IR prev/next buttons
1 parent 45b935a commit c6195b2

File tree

3 files changed

+197
-8
lines changed

3 files changed

+197
-8
lines changed

src/surge-xt/gui/SurgeGUIEditor.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6362,6 +6362,27 @@ void SurgeGUIEditor::hidePatchCommentTooltip()
63626362
}
63636363
}
63646364

6365+
void SurgeGUIEditor::showIRNameTooltip(const std::string &text,
6366+
const juce::Rectangle<int> &frameBounds)
6367+
{
6368+
if (patchSelectorComment)
6369+
{
6370+
patchSelectorComment->positionForComment(
6371+
frameBounds.getCentre().withY(frameBounds.getBottom()), text, frameBounds.getWidth());
6372+
patchSelectorComment->setVisible(true);
6373+
patchSelectorComment->getParentComponent()->toFront(false);
6374+
patchSelectorComment->toFront(false);
6375+
}
6376+
}
6377+
6378+
void SurgeGUIEditor::hideIRNameTooltip()
6379+
{
6380+
if (patchSelectorComment && patchSelectorComment->isVisible())
6381+
{
6382+
patchSelectorComment->setVisible(false);
6383+
}
6384+
}
6385+
63656386
void SurgeGUIEditor::addComponentWithTracking(juce::Component *target, juce::Component &source)
63666387
{
63676388
if (target->getIndexOfChildComponent(&source) >= 0)

src/surge-xt/gui/SurgeGUIEditor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,8 @@ class SurgeGUIEditor : public Surge::GUI::IComponentTagValue::Listener,
637637
public:
638638
void showPatchCommentTooltip(const std::string &comment);
639639
void hidePatchCommentTooltip();
640+
void showIRNameTooltip(const std::string &text, const juce::Rectangle<int> &frameBounds);
641+
void hideIRNameTooltip();
640642
void showInfowindow(int ptag, juce::Rectangle<int> relativeTo, bool isModulated);
641643
void showInfowindowSelfDismiss(int ptag, juce::Rectangle<int> relativeTo, bool isModulated);
642644
void updateInfowindowContents(int ptag, bool isModulated);

src/surge-xt/gui/widgets/CurrentFxDisplay.cpp

Lines changed: 174 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "RuntimeFont.h"
1010
#include "SkinModel.h"
1111
#include "SurgeGUIEditor.h"
12+
#include "SurgeJUCEHelpers.h"
1213
#include "SurgeGUIEditorTags.h"
1314
#include "dsp/effects/ConditionerEffect.h"
1415
#include "dsp/effects/ConvolutionEffect.h"
@@ -60,28 +61,127 @@ struct ConvolutionButton : public juce::Component
6061

6162
void mouseDown(const juce::MouseEvent &event) override
6263
{
64+
hideTooltip();
65+
6366
if (event.mods.isMiddleButtonDown() && sge)
6467
{
6568
sge->frame->mouseDown(event);
6669
return;
6770
}
6871

72+
if (!event.mods.isPopupMenu())
73+
{
74+
if (leftJog.contains(event.position))
75+
{
76+
jogIR(-1);
77+
return;
78+
}
79+
else if (rightJog.contains(event.position))
80+
{
81+
jogIR(1);
82+
return;
83+
}
84+
}
85+
6986
showIRMenu();
7087
}
7188

72-
bool isMousedOver = false;
89+
bool isMousedOver{false};
90+
bool isJogLHovered{false}, isJogRHovered{false}, isNameHovered{false};
91+
juce::Rectangle<float> leftJog, rightJog, irNameRect;
92+
93+
int tooltipCountdown{-1};
94+
bool tooltipShowing{false};
95+
96+
bool isNameTruncated() const
97+
{
98+
if (!sge)
99+
return false;
100+
auto ft = sge->currentSkin->fontManager->getLatoAtSize(9);
101+
auto textW = SST_STRING_WIDTH_FLOAT(ft, juce::String(irname));
102+
return textW > irNameRect.getWidth() - 2;
103+
}
104+
105+
void hideTooltip()
106+
{
107+
tooltipCountdown = -1;
108+
if (sge && tooltipShowing)
109+
{
110+
sge->hideIRNameTooltip();
111+
}
112+
tooltipShowing = false;
113+
}
114+
115+
void shouldTooltip()
116+
{
117+
if (tooltipCountdown < 0)
118+
return;
119+
120+
tooltipCountdown--;
121+
122+
if (tooltipCountdown == 0)
123+
{
124+
tooltipCountdown = -1;
125+
if (sge && isNameTruncated())
126+
{
127+
auto b = sge->frame->getLocalArea(this, getLocalBounds());
128+
sge->showIRNameTooltip(irname, b);
129+
tooltipShowing = true;
130+
}
131+
}
132+
else
133+
{
134+
juce::Timer::callAfterDelay(100, Surge::GUI::makeSafeCallback<ConvolutionButton>(
135+
this, [](auto *that) { that->shouldTooltip(); }));
136+
}
137+
}
73138

74139
void mouseEnter(const juce::MouseEvent &event) override
75140
{
76141
isMousedOver = true;
77142
repaint();
78143
}
144+
79145
void mouseExit(const juce::MouseEvent &event) override
80146
{
81147
isMousedOver = false;
148+
isJogLHovered = false;
149+
isJogRHovered = false;
150+
isNameHovered = false;
151+
hideTooltip();
82152
repaint();
83153
}
84154

155+
void mouseMove(const juce::MouseEvent &event) override
156+
{
157+
auto njl = leftJog.contains(event.position);
158+
auto njr = rightJog.contains(event.position);
159+
auto nnm = irNameRect.contains(event.position);
160+
161+
if (njl != isJogLHovered || njr != isJogRHovered || nnm != isNameHovered)
162+
{
163+
isJogLHovered = njl;
164+
isJogRHovered = njr;
165+
isNameHovered = nnm;
166+
repaint();
167+
}
168+
169+
if (nnm)
170+
{
171+
if (tooltipCountdown < 0 && !tooltipShowing)
172+
{
173+
tooltipCountdown = 3;
174+
juce::Timer::callAfterDelay(100,
175+
Surge::GUI::makeSafeCallback<ConvolutionButton>(
176+
this, [](auto *that) { that->shouldTooltip(); }));
177+
}
178+
}
179+
else
180+
{
181+
hideTooltip();
182+
}
183+
}
184+
85185
void paint(juce::Graphics &g) override
86186
{
87187
if (!fx)
@@ -97,16 +197,48 @@ struct ConvolutionButton : public juce::Component
97197
auto fgframeHov = skin->getColor(Colors::Effect::Grid::Scene::BackgroundHover);
98198
auto fgtextHov = skin->getColor(Colors::Effect::Grid::Scene::TextHover);
99199

100-
auto irr = getLocalBounds();
200+
auto irr = getLocalBounds().toFloat();
201+
auto h = irr.getHeight();
101202

102-
bool focused = isMousedOver || hasKeyboardFocus(true);
103-
g.setColour(focused ? fgcolHov : fgcol);
104-
g.fillRect(irr);
105-
g.setColour(focused ? fgframeHov : fgframe);
203+
leftJog = irr.withRight(h);
204+
rightJog = irr.withLeft(irr.getWidth() - h);
205+
irNameRect = irr.withTrimmedLeft(h).withTrimmedRight(h);
206+
207+
float triO = 3;
208+
209+
// Fill each region individually for per-region hover.
210+
g.setColour(isJogLHovered ? fgcolHov : fgcol);
211+
g.fillRect(leftJog);
212+
g.setColour(isJogRHovered ? fgcolHov : fgcol);
213+
g.fillRect(rightJog);
214+
bool nameFocused = isNameHovered || hasKeyboardFocus(true);
215+
g.setColour(nameFocused ? fgcolHov : fgcol);
216+
g.fillRect(irNameRect);
217+
218+
// Single outer border.
219+
g.setColour(fgframe);
106220
g.drawRect(irr);
107-
g.setColour(focused ? fgtextHov : fgtext);
221+
222+
// Left jog arrow
223+
g.setColour(isJogLHovered ? fgtextHov : fgtext);
224+
auto triL = juce::Path();
225+
triL.addTriangle(leftJog.getTopRight().translated(-triO, triO),
226+
leftJog.getBottomRight().translated(-triO, -triO),
227+
leftJog.getCentre().withX(leftJog.getX() + triO));
228+
g.fillPath(triL);
229+
230+
// Right jog arrow
231+
g.setColour(isJogRHovered ? fgtextHov : fgtext);
232+
auto triR = juce::Path();
233+
triR.addTriangle(rightJog.getTopLeft().translated(triO, triO),
234+
rightJog.getBottomLeft().translated(triO, -triO),
235+
rightJog.getCentre().withX(rightJog.getX() + rightJog.getWidth() - triO));
236+
g.fillPath(triR);
237+
238+
// IR name text
239+
g.setColour(nameFocused ? fgtextHov : fgtext);
108240
g.setFont(skin->fontManager->getLatoAtSize(9));
109-
g.drawText(juce::String(irname), irr, juce::Justification::centred);
241+
g.drawText(juce::String(irname), irNameRect, juce::Justification::centred);
110242
}
111243

112244
void showIRMenu()
@@ -293,6 +425,40 @@ struct ConvolutionButton : public juce::Component
293425
sge->synth->load_fx_needed = true;
294426
}
295427

428+
void jogIR(int dir)
429+
{
430+
if (!storage || storage->irOrdering.empty())
431+
return;
432+
433+
// Find current IR's position in the display ordering by name.
434+
int currentPos = -1;
435+
for (int i = 0; i < (int)storage->irOrdering.size(); i++)
436+
{
437+
if (storage->ir_list[storage->irOrdering[i]].name == irname)
438+
{
439+
currentPos = i;
440+
break;
441+
}
442+
}
443+
444+
int newPos;
445+
if (currentPos < 0)
446+
{
447+
// Current IR not in the list, start from beginning or end.
448+
newPos = (dir > 0) ? 0 : (int)storage->irOrdering.size() - 1;
449+
}
450+
else
451+
{
452+
newPos = currentPos + dir;
453+
if (newPos < 0)
454+
newPos = (int)storage->irOrdering.size() - 1;
455+
if (newPos >= (int)storage->irOrdering.size())
456+
newPos = 0;
457+
}
458+
459+
loadIR(storage->irOrdering[newPos]);
460+
}
461+
296462
void loadIR(int id)
297463
{
298464
if (id >= 0 && id < storage->ir_list.size() && sge)

0 commit comments

Comments
 (0)