Mema
Memory Matrix — multi-channel audio matrix monitor and router
Loading...
Searching...
No Matches
CrosspointsControlComponent.h
Go to the documentation of this file.
1/* Copyright (c) 2024, Christian Ahrens
2 *
3 * This file is part of Mema <https://github.com/ChristianAhrens/Mema>
4 *
5 * This tool is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU Lesser General Public License version 3.0 as published
7 * by the Free Software Foundation.
8 *
9 * This tool is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 * details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this tool; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19#pragma once
20
21#include <JuceHeader.h>
22
23#include "../MemaProcessor/MemaCommanders.h"
24#include "../MemaProcessor/ProcessorDataAnalyzer.h"
25
26#include <CustomLookAndFeel.h>
27
28
29namespace Mema
30{
31
33class CrosspointComponent : public juce::Component
34{
35public:
36 using CrosspointIdent = std::pair<int, int>;
37
38 static constexpr auto pi = juce::MathConstants<float>::pi;
39 static constexpr auto arcStartRad = 0.0f;
40
41public:
42 CrosspointComponent(const CrosspointIdent& ident) : juce::Component::Component() { m_ident = ident; }
44
45 const CrosspointIdent& getIdent() { return m_ident; }
46
47 //==============================================================================
48 void paint(Graphics& g) override
49 {
50 auto bounds = getLocalBounds().reduced(2).toFloat();
51 g.setColour(getLookAndFeel().findColour(juce::TextButton::ColourIds::textColourOnId));
52 if (m_checked)
53 {
54 auto circleBounds = bounds.reduced(2);
55 auto centre = circleBounds.getCentre();
56 juce::Path p;
57 p.addCentredArc(centre.getX(),
58 centre.getY(),
59 0.25f * circleBounds.getWidth(),
60 0.25f * circleBounds.getHeight(),
61 0.0f,
63 arcStartRad + 2.0f * pi * (m_isDragging ? m_tempFactorWhileDragging : m_factor),
64 true);
65 g.strokePath(p, { 0.5f * circleBounds.getWidth(), juce::PathStrokeType::mitered });
66 }
67
68 g.drawEllipse(bounds, 1.0f);
69
70#if !funktioniertnochtnicht
71 if (m_isDragging)
72 {
73 g.setColour(getLookAndFeel().findColour(JUCEAppBasics::CustomLookAndFeel::ColourIds::MeteringRmsColourId));
74 g.setFont(g.getCurrentFont().withStyle(juce::Font::FontStyleFlags::bold).withHeight(0.4f * getHeight()));
75 g.drawFittedText(juce::String(juce::Decibels::gainToDecibels(m_factor, static_cast<float>(ProcessorDataAnalyzer::getGlobalMindB())), 1) + " dB", getLocalBounds(), juce::Justification::centred, 1);
76 }
77#endif
78 }
79
80 //==============================================================================
81 void setChecked(bool checked)
82 {
83 m_checked = checked;
84 repaint();
85 }
87 {
88 setChecked(!m_checked);
89
91 onCheckedChanged(m_checked, this);
93 onFactorChanged(m_factor, this);
94 }
95
96 //==============================================================================
97 void setFactor(float factor)
98 {
99 m_factor = factor;
100 repaint();
101 }
102 float getFactor()
103 {
104 return m_factor;
105 }
106
107 //==============================================================================
108 void mouseUp(const MouseEvent& e) override
109 {
110 if (!m_isDragging && getLocalBounds().contains(e.getPosition()))
112
113 if (m_isDragging)
114 {
115 m_factor = m_tempFactorWhileDragging;
116 if (onFactorChanged)
117 onFactorChanged(m_factor, this);
118 m_isDragging = false;
119
120#if funktioniertnochnicht
121 if (auto claf = dynamic_cast<JUCEAppBasics::CustomLookAndFeel*>(&getLookAndFeel()))
122 claf->setMouseCursor(juce::MouseCursor(juce::MouseCursor::StandardCursorType::NoCursor));
123#endif
124 }
125 }
126 void mouseDrag(const MouseEvent& e) override
127 {
128 auto offset = e.getOffsetFromDragStart();
129 if (std::abs(offset.getY()) > 1)
130 {
131 m_isDragging = true;
132
133 m_tempFactorWhileDragging = jlimit(0.0f, 1.0f, m_factor - (offset.getY() / 800.0f));
134
135#if funktioniertnochnicht
136 if (auto claf = dynamic_cast<JUCEAppBasics::CustomLookAndFeel*>(&getLookAndFeel()))
137 {
138 juce::Image cursorImage(juce::Image::PixelFormat::ARGB, 35, 15, true);
139 juce::Graphics g(cursorImage);
140 g.setColour(getLookAndFeel().findColour(juce::TextButton::ColourIds::textColourOnId));
141 g.drawSingleLineText(juce::String(juce::Decibels::gainToDecibels(m_factor, static_cast<float>(ProcessorDataAnalyzer::getGlobalMindB()))) + " dB", 0, 0);
142 claf->setMouseCursor(juce::MouseCursor(cursorImage, 0, 0));
143 }
144#endif
145
146 DBG(juce::String(__FUNCTION__) << " " << int(m_ident.first) << "/" << int(m_ident.second) << " new factor: " << m_tempFactorWhileDragging);
147
148 repaint();
149
150 if (onFactorChanged)
151 onFactorChanged(m_tempFactorWhileDragging, this);
152 }
153 }
154
155 std::function<void(bool, CrosspointComponent*)> onCheckedChanged;
156 std::function<void(float, CrosspointComponent*)> onFactorChanged;
157
158private:
159 bool m_checked = false;
160 float m_factor = 1.0f;
161 float m_tempFactorWhileDragging = 1.0f;
162 CrosspointIdent m_ident = { -1, -1 };
163 bool m_isDragging = false;
164};
165
167class CrosspointsControlComponent : public juce::Component,
169{
170public:
173
174 //==============================================================================
175 void paint (Graphics&) override;
176 void resized() override;
177
178 //==============================================================================
179 void setCrosspointEnabledValue(std::uint16_t input, std::uint16_t output, bool enabledState, int userId = -1) override;
180 void setCrosspointFactorValue(std::uint16_t input, std::uint16_t output, float factor, int userId = -1) override;
181
182 //==============================================================================
183 std::function<void()> onBoundsRequirementChange;
184 juce::Rectangle<int> getRequiredSize();
185
186 //==============================================================================
187 void setIOCount(std::uint16_t inputCount, std::uint16_t outputCount) override;
188
189private:
190 //==============================================================================
191 std::map<std::uint16_t, std::map<std::uint16_t, bool>> m_crosspointEnabledValues;
192 std::map<std::uint16_t, std::map<std::uint16_t, float>> m_crosspointFactorValues;
193 std::map<std::uint16_t, std::map<std::uint16_t, std::unique_ptr<CrosspointComponent>>> m_crosspointComponent;
194
195 //==============================================================================
196 juce::Grid m_matrixGrid;
197
198 std::pair<int, int> m_ioCount{ std::make_pair(-1, -1) };
199
200 static constexpr int s_nodeSize = 24;
201 static constexpr double s_nodeGap = 1;
202
203 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CrosspointsControlComponent)
204};
205
206}
CrosspointComponent(const CrosspointIdent &ident)
const CrosspointIdent & getIdent()
std::function< void(bool, CrosspointComponent *)> onCheckedChanged
void paint(Graphics &g) override
void mouseDrag(const MouseEvent &e) override
std::function< void(float, CrosspointComponent *)> onFactorChanged
void mouseUp(const MouseEvent &e) override
void setCrosspointEnabledValue(std::uint16_t input, std::uint16_t output, bool enabledState, int userId=-1) override
void setCrosspointFactorValue(std::uint16_t input, std::uint16_t output, float factor, int userId=-1) override
void setIOCount(std::uint16_t inputCount, std::uint16_t outputCount) override
Definition Mema.cpp:27