Skip to content

Commit

Permalink
Part activation and deactivation (#1385)
Browse files Browse the repository at this point in the history
* Part activation and deactivation

Closes #1142

- Rudimentary part activation and deactiviation support.
- Respect the part active in sidecard display
- Have an 'add part' option
- Selection menu properly bounded
- Play screen does the right thing also
- Deactivate part works
- Engine obeys activation
- Select Deactivation selects antoher part

* Add discord link to readme
  • Loading branch information
baconpaul authored Sep 28, 2024
1 parent 7f8e579 commit 675804b
Show file tree
Hide file tree
Showing 12 changed files with 190 additions and 21 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ are reflected in the code.

If you are going to use the product now, though, many things will be incomplete or
mysteriously not work. Really the best way to particpate is to join the [surge synth team
discord](https://raw.githubusercontent.com/surge-synthesizer/surge-synthesizer.github.io/master/_includes/discord_invite_link)
discord](https://discord.gg/RcHTt5M55M)
and come say hi in the #sc-development channel.

There's lots of ways you can help. Of course, developers are always welcome. But testers,
Expand Down
Binary file modified resources/InitSettings.dat
Binary file not shown.
65 changes: 57 additions & 8 deletions src-ui/app/edit-screen/components/PartGroupSidebar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct PartSidebar : juce::Component, HasEditor
std::unique_ptr<jcmp::Viewport> viewport;
std::unique_ptr<juce::Component> viewportContents;
std::array<std::unique_ptr<shared::PartSidebarCard>, scxt::numParts> parts;
std::unique_ptr<jcmp::TextPushButton> addPartButton;

PartSidebar(PartGroupSidebar *p) : partGroupSidebar(p), HasEditor(p->editor)
{
Expand All @@ -56,23 +57,67 @@ struct PartSidebar : juce::Component, HasEditor
for (int i = 0; i < scxt::numParts; ++i)
{
parts[i] = std::make_unique<shared::PartSidebarCard>(i, editor);
viewportContents->addAndMakeVisible(*parts[i]);
viewportContents->addChildComponent(*parts[i]);
}
addPartButton = std::make_unique<jcmp::TextPushButton>();
addPartButton->setLabel("Add Part");
addPartButton->setOnCallback([w = juce::Component::SafePointer(this)]() {
w->sendToSerialization(cmsg::ActivateNextPart(true));
});
viewportContents->addChildComponent(*addPartButton);
viewport->setViewedComponent(viewportContents.get(), false);
addAndMakeVisible(*viewport);
}
void resized() override
{
auto w = shared::PartSidebarCard::width + viewport->getScrollBarThickness() + 2;
viewport->setBounds(getLocalBounds().withWidth(w).translated(3, 0));
auto nDispParts{0};
for (int i = 0; i < scxt::numParts; ++i)
{
if (parts[i]->isVisible())
{
nDispParts++;
}
}
int extraSpace{0};
if (nDispParts < scxt::numParts)
extraSpace = 30;
viewportContents->setBounds(0, 0, shared::PartSidebarCard::width,
shared::PartSidebarCard::height * scxt::numParts);
shared::PartSidebarCard::height * nDispParts + extraSpace);
auto ct{0};
for (int i = 0; i < scxt::numParts; ++i)
{
parts[i]->setBounds(0, i * shared::PartSidebarCard::height,
shared::PartSidebarCard::width, shared::PartSidebarCard::height);
if (parts[i]->isVisible())
{
parts[i]->setBounds(0, ct * shared::PartSidebarCard::height,
shared::PartSidebarCard::width,
shared::PartSidebarCard::height);
ct++;
}
}

if (nDispParts < scxt::numParts)
{
addPartButton->setBounds(10, ct * shared::PartSidebarCard::height + 4,
shared::PartSidebarCard::width - 20, 22);
}
}

void restackForActive()
{
int nDispParts{0};
for (int i = 0; i < scxt::numParts; ++i)
{
if (editor->partConfigurations[i].active)
{
nDispParts++;
}
parts[i]->setVisible(editor->partConfigurations[i].active);
}
addPartButton->setVisible(nDispParts < scxt::numParts);
resized();
}
};

template <typename T, bool forZone>
Expand Down Expand Up @@ -120,10 +165,13 @@ struct GroupZoneSidebarBase : juce::Component, HasEditor, juce::DragAndDropConta
p.addSeparator();
for (int i = 0; i < scxt::numParts; ++i)
{
p.addItem("Part " + std::to_string(i + 1), true, i == editor->selectedPart,
[w = juce::Component::SafePointer(this), index = i]() {
w->sendToSerialization(cmsg::SelectPart(index));
});
if (editor->partConfigurations[i].active)
{
p.addItem("Part " + std::to_string(i + 1), true, i == editor->selectedPart,
[w = juce::Component::SafePointer(this), index = i]() {
w->sendToSerialization(cmsg::SelectPart(index));
});
}
}
p.showMenuAsync(editor->defaultPopupMenuOptions());
}
Expand Down Expand Up @@ -471,5 +519,6 @@ void PartGroupSidebar::setSelectedTab(int t)
void PartGroupSidebar::partConfigurationChanged(int i)
{
partSidebar->parts[i]->resetFromEditorCache();
partSidebar->restackForActive();
}
} // namespace scxt::ui::app::edit_screen
2 changes: 2 additions & 0 deletions src-ui/app/editor-impl/SCXTEditorResponseHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,8 @@ void SCXTEditor::onPartConfiguration(
// When I have active show/hide i will need to rewrite this i bet
if (playScreen && playScreen->partSidebars[pt])
playScreen->partSidebars[pt]->resetFromEditorCache();
playScreen->partConfigurationChanged();

if (editScreen && editScreen->partSidebar)
editScreen->partSidebar->partConfigurationChanged(pt);
}
Expand Down
43 changes: 34 additions & 9 deletions src-ui/app/play-screen/PlayScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,26 @@ struct ViewportComponent : juce::Component, HasEditor

void paint(juce::Graphics &g)
{
auto viz = [this](int i) { return editor->partConfigurations[i].active; };

int ct{0};
for (int i = 0; i < scxt::numParts; ++i)
{
if (!viz(i))
continue;

auto col = editor->themeColor(theme::ColorMap::grid_secondary);
if (i == editor->selectedPart)
{
col = editor->themeColor(theme::ColorMap::accent_1a);
}
g.setColour(col);
auto bx =
playScreen->rectangleForPart(i).withTrimmedBottom(PlayScreen::interPartMargin);
playScreen->rectangleForPart(ct).withTrimmedBottom(PlayScreen::interPartMargin);
g.drawRoundedRectangle(bx.toFloat(), 2, 1);
g.drawVerticalLine(bx.getX() + shared::PartSidebarCard::width, bx.getY(),
bx.getY() + bx.getHeight());
++ct;
}
}
};
Expand All @@ -79,11 +86,11 @@ PlayScreen::PlayScreen(SCXTEditor *e) : HasEditor(e)
{
partSidebars[i] = std::make_unique<shared::PartSidebarCard>(i, editor);
partSidebars[i]->selfAccent = false;
viewportContents->addAndMakeVisible(*partSidebars[i]);
viewportContents->addChildComponent(*partSidebars[i]);

skinnyPage[i] = 0;
auto ms = std::make_unique<jcmp::MultiSwitch>();
viewportContents->addAndMakeVisible(*ms);
viewportContents->addChildComponent(*ms);
auto ds = std::make_unique<skinnyPage_t>(ms, skinnyPage[i]);
static_assert(scxt::macrosPerPart == 16); // assuming this here for now
ds->valueToString = [](auto b) {
Expand All @@ -107,7 +114,7 @@ PlayScreen::PlayScreen(SCXTEditor *e) : HasEditor(e)
sed = std::make_unique<shared::SingleMacroEditor>(editor, pt, id, true);
sed->changePart(pt);
id++;
viewportContents->addAndMakeVisible(*sed);
viewportContents->addChildComponent(*sed);
}
pt++;
}
Expand All @@ -123,30 +130,37 @@ PlayScreen::~PlayScreen() {}

void PlayScreen::rebuildPositionsAndVisibilites()
{
auto viz = [this](int i) { return editor->partConfigurations[i].active; };
if (tallMode)
{
for (int p = 0; p < scxt::numParts; ++p)
{
skinnyPageSwitches[p]->widget->setVisible(false);
for (int i = 0; i < scxt::macrosPerPart; ++i)
{
macroEditors[p][i]->setVisible(true);
macroEditors[p][i]->setVisible(true && viz(p));
}
}
}
else
{
for (int p = 0; p < scxt::numParts; ++p)
{
skinnyPageSwitches[p]->widget->setVisible(true);
skinnyPageSwitches[p]->widget->setVisible(true && viz(p));
static_assert(scxt::macrosPerPart == 16); // assuming this here too
for (int i = 0; i < scxt::macrosPerPart; ++i)
{
auto firstHalf = (i < scxt::macrosPerPart / 2);
macroEditors[p][i]->setVisible(firstHalf == !skinnyPage[p]);
macroEditors[p][i]->setVisible(viz(p) && firstHalf == !skinnyPage[p]);
}
}
}

for (int p = 0; p < scxt::numParts; ++p)
{
partSidebars[p]->setVisible(viz(p));
}

if (isVisible())
resized();
}
Expand Down Expand Up @@ -175,6 +189,13 @@ void PlayScreen::showMenu()
});
p.showMenuAsync(editor->defaultPopupMenuOptions());
}

void PlayScreen::partConfigurationChanged()
{
rebuildPositionsAndVisibilites();
resized();
}

void PlayScreen::visibilityChanged()
{
if (isVisible())
Expand All @@ -201,8 +222,12 @@ void PlayScreen::resized()

viewport->setBounds(playNamedPanel->getContentArea());
auto w = viewport->getWidth() - viewport->getScrollBarThickness() - 2;
viewportContents->setBounds(
0, 0, w, shared::PartSidebarCard::height * scxt::numParts * (tallMode ? 2 : 1));
int npt{0};
for (int i = 0; i < scxt::numParts; ++i)
npt += editor->partConfigurations[i].active;

viewportContents->setBounds(0, 0, w,
shared::PartSidebarCard::height * npt * (tallMode ? 2 : 1));
for (int i = 0; i < scxt::numParts; ++i)
{
auto rb = rectangleForPart(i);
Expand Down
2 changes: 2 additions & 0 deletions src-ui/app/play-screen/PlayScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ struct PlayScreen : juce::Component, HasEditor
void rebuildPositionsAndVisibilites();
void showMenu();

void partConfigurationChanged();

bool tallMode{true};
static constexpr size_t interPartMargin{3};
juce::Rectangle<int> rectangleForPart(int part);
Expand Down
25 changes: 25 additions & 0 deletions src-ui/app/shared/PartSidebarCard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,27 @@ PartSidebarCard::PartSidebarCard(int p, SCXTEditor *e) : part(p), HasEditor(e)

void PartSidebarCard::mouseDown(const juce::MouseEvent &event)
{
if (event.mods.isPopupMenu())
{
showPopup();
return;
}
sendToSerialization(cmsg::SelectPart(part));
}

void PartSidebarCard::showPopup()
{
auto p = juce::PopupMenu();
p.addSectionHeader("Part " + std::to_string(part + 1));
p.addSeparator();
p.addItem("Deactivate Part", [p = this->part, w = juce::Component::SafePointer(this)]() {
if (!w)
return;
w->sendToSerialization(cmsg::DeactivatePart(p));
});
p.showMenuAsync(editor->defaultPopupMenuOptions());
}

void PartSidebarCard::paint(juce::Graphics &g)
{
if (editor->getSelectedPart() == part)
Expand Down Expand Up @@ -151,6 +169,13 @@ void PartSidebarCard::paint(juce::Graphics &g)
jcmp::GlyphPainter::paintGlyph(g, r, jcmp::GlyphPainter::GlyphType::PAN, med);
r = r.translated(0, rowHeight);
jcmp::GlyphPainter::paintGlyph(g, r, jcmp::GlyphPainter::GlyphType::TUNING, med);

auto &cfg = editor->partConfigurations[part];
if (!cfg.active)
{
g.setColour(juce::Colour(255, 0, 0).withAlpha(0.1f));
g.fillRect(getLocalBounds());
}
}

void PartSidebarCard::resized()
Expand Down
2 changes: 2 additions & 0 deletions src-ui/app/shared/PartSidebarCard.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ struct PartSidebarCard : juce::Component, HasEditor
void mouseDown(const juce::MouseEvent &e) override;
void resized() override;

void showPopup();

void resetFromEditorCache();
};
} // namespace scxt::ui::app::shared
Expand Down
2 changes: 1 addition & 1 deletion src/engine/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ struct Engine : MoveableOnly<Engine>, SampleRateSupport
size_t idx{0};
for (const auto &[pidx, part] : sst::cpputils::enumerate(*patch))
{
if (!part->configuration.mute &&
if (!part->configuration.mute && part->configuration.active &&
(part->configuration.channel == channel ||
part->configuration.channel == Part::PartConfiguration::omniChannel))
{
Expand Down
8 changes: 6 additions & 2 deletions src/engine/part.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ struct Part : MoveableOnly<Part>, SampleRateSupport
idx++;
}
configuration.channel = c;
if (c == 0)
{
configuration.active = true;
}
}
virtual ~Part() = default;

Expand All @@ -68,7 +72,7 @@ struct Part : MoveableOnly<Part>, SampleRateSupport
{
static constexpr int16_t omniChannel{-1};

bool active{true};
bool active{false};
int16_t channel{omniChannel}; // a midi channel or a special value like omni
bool mute{false};
bool solo{false};
Expand Down Expand Up @@ -154,7 +158,7 @@ struct Part : MoveableOnly<Part>, SampleRateSupport
}

uint32_t activeGroups{0};
bool isActive() { return activeGroups != 0; }
bool isActive() { return activeGroups != 0 && configuration.active; }
void addActiveGroup() { activeGroups++; }
void removeActiveGroup()
{
Expand Down
4 changes: 4 additions & 0 deletions src/messaging/client/client_serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ enum ClientToSerializationMessagesIds

c2s_resolve_sample,

// part activation
c2s_activate_next_part,
c2s_deactivate_part,

num_clientToSerializationMessages
};

Expand Down
Loading

0 comments on commit 675804b

Please sign in to comment.