weGraph.cpp (6669B)
1 #include "weGraph.h" 2 3 #include "xtWaveEditor.h" 4 5 #include "dsp56kEmu/fastmath.h" 6 7 namespace xtJucePlugin 8 { 9 Graph::Graph(WaveEditor& _editor) : m_editor(_editor), m_data(_editor.getGraphData()) 10 { 11 m_onDataChanged.set(m_data.onChanged, [this]() 12 { 13 onSourceChanged(); 14 }); 15 } 16 17 void Graph::paint(juce::Graphics& g) 18 { 19 g.fillAll(findColour(juce::TreeView::ColourIds::backgroundColourId)); 20 21 paint(getData(), getDataSize(),g, 0, 0, getWidth(), getHeight()); 22 } 23 24 void Graph::parentHierarchyChanged() 25 { 26 juce::Component::parentHierarchyChanged(); 27 28 const auto* parent = getParentComponent(); 29 if(!parent) 30 return; 31 32 setSize(parent->getWidth(), parent->getHeight()); 33 } 34 35 void Graph::paint(const float* _data, const size_t _size, juce::Graphics& _g, const int _x, const int _y, const int _width, const int _height) const 36 { 37 const auto& style = m_editor.getStyle(); 38 39 const float scaleX = static_cast<float>(_width) / static_cast<float>(_size); 40 const float scaleY = static_cast<float>(_height); 41 42 const float x = static_cast<float>(_x) + scaleX * 0.5f; 43 const float y = static_cast<float>(_y); 44 45 const float h = static_cast<float>(_height); 46 47 for(uint32_t i=0; i<_size; ++i) 48 { 49 const auto x0 = static_cast<float>(i ? (i - 1) : i) * scaleX + x; 50 const auto x1 = static_cast<float>(i ) * scaleX + x; 51 52 const auto y0 = h - (normalize(_data[i ? (i - 1) : i])) * scaleY + y - 1; 53 const auto y1 = h - (normalize(_data[i ])) * scaleY + y - 1; 54 55 if(i) 56 { 57 _g.setColour(juce::Colour(style.colGraphLine)); 58 _g.drawLine(x0, y0, x1, y1, style.graphLineThickness); 59 } 60 61 if(m_highlightedIndices.find(i) != m_highlightedIndices.end()) 62 { 63 _g.setColour(style.colGraphLineHighlighted); 64 const auto s = style.graphPointSizeHighlighted; 65 _g.fillEllipse(x1 - s * 0.5f, y1 - s * 0.5f, s, s); 66 } 67 else 68 { 69 _g.setColour(style.colGraphLine); 70 const auto s = style.graphPointSize; 71 _g.fillEllipse(x1 - s * 0.5f, y1 - s * 0.5f, s, s); 72 } 73 } 74 } 75 76 bool Graph::updateHoveredIndex(const juce::MouseEvent& _e) 77 { 78 const auto index = mouseToIndex(_e); 79 if(!isValidIndex(index)) 80 { 81 setHoveredIndex(InvalidIndex); 82 return false; 83 } 84 setHoveredIndex(static_cast<uint32_t>(index)); 85 return true; 86 } 87 88 void Graph::mouseDown(const juce::MouseEvent& _e) 89 { 90 Component::mouseDown(_e); 91 92 if (_e.mods.isPopupMenu()) 93 { 94 m_editor.openGraphPopupMenu(*this, _e); 95 return; 96 } 97 98 setLastMouseEvent(_e); 99 const auto i = mouseToIndex(_e); 100 if(isValidIndex(i)) 101 modifyValue(static_cast<uint32_t>(i), mouseToUnnormalizedValue(_e)); 102 } 103 104 void Graph::mouseMove(const juce::MouseEvent& _e) 105 { 106 Component::mouseMove(_e); 107 108 if (_e.mods.isPopupMenu()) 109 return; 110 111 updateHoveredIndex(_e); 112 } 113 114 void Graph::mouseEnter(const juce::MouseEvent& _e) 115 { 116 Component::mouseEnter(_e); 117 updateHoveredIndex(_e); 118 } 119 120 void Graph::mouseExit(const juce::MouseEvent& _e) 121 { 122 Component::mouseExit(_e); 123 setHoveredIndex(InvalidIndex); 124 } 125 126 void Graph::mouseDrag(const juce::MouseEvent& _e) 127 { 128 Component::mouseDrag(_e); 129 130 if (_e.mods.isPopupMenu()) 131 return; 132 133 if(!_e.mods.isShiftDown()) 134 { 135 updateHoveredIndex(_e); 136 137 if(m_lastMouseEvent) 138 { 139 modifyValuesForRange(*m_lastMouseEvent, _e); 140 } 141 else if(isValidIndex(m_hoveredIndex)) 142 { 143 modifyValue(m_hoveredIndex, mouseToUnnormalizedValue(_e)); 144 } 145 } 146 else 147 { 148 if(isValidIndex(m_hoveredIndex)) 149 modifyValue(m_hoveredIndex, mouseToUnnormalizedValue(_e)); 150 } 151 152 setLastMouseEvent(_e); 153 } 154 155 int32_t Graph::mouseToIndex(const juce::MouseEvent& _e) const 156 { 157 return _e.x * static_cast<int32_t>(getDataSize()) / (int32_t)getWidth(); 158 } 159 160 float Graph::mouseToNormalizedValue(const juce::MouseEvent& _e) const 161 { 162 const auto v = 1.0f - static_cast<float>(_e.y) / static_cast<float>(getHeight() - 1); 163 return dsp56k::clamp(v, 0.0f, 1.0f); 164 } 165 166 float Graph::mouseToUnnormalizedValue(const juce::MouseEvent& _e) const 167 { 168 return unnormalize(mouseToNormalizedValue(_e)); 169 } 170 171 const juce::MouseEvent* Graph::lastMouseEvent() const 172 { 173 return m_lastMouseEvent.get(); 174 } 175 176 bool Graph::isInterestedInDragSource(const SourceDetails& _dragSourceDetails) 177 { 178 return false; 179 } 180 181 void Graph::itemDropped(const SourceDetails& _dragSourceDetails) 182 { 183 } 184 185 bool Graph::isInterestedInFileDrag(const juce::StringArray& _files) 186 { 187 if (_files.size() != 1) 188 return false; 189 return _files[0].endsWithIgnoreCase(".wav"); 190 } 191 192 void Graph::filesDropped(const juce::StringArray& _files, int _x, int _y) 193 { 194 if (_files.size() != 1) 195 return; 196 if (auto res = m_editor.importWaveFile(_files[0].toStdString())) 197 m_editor.getGraphData().set(*res); 198 } 199 200 void Graph::onSourceChanged() 201 { 202 repaint(); 203 } 204 205 void Graph::onHoveredIndexChanged(const uint32_t _index) 206 { 207 if(_index == InvalidIndex) 208 { 209 if(!m_highlightedIndices.empty()) 210 m_highlightedIndices.clear(); 211 212 onHighlightedIndicesChanged(m_highlightedIndices); 213 } 214 215 setHighlightedIndices({_index}); 216 } 217 218 void Graph::onHighlightedIndicesChanged(const std::set<uint32_t>& _indices) 219 { 220 repaint(); 221 } 222 223 void Graph::setHighlightedIndices(const std::set<uint32_t>& _indices) 224 { 225 bool changed = false; 226 227 for (auto existing : m_highlightedIndices) 228 { 229 if(_indices.find(existing) == _indices.end()) 230 { 231 changed = true; 232 break; 233 } 234 } 235 236 if(!changed) 237 { 238 for (uint32_t newIndex : _indices) 239 { 240 if(m_highlightedIndices.find(newIndex) == m_highlightedIndices.end()) 241 { 242 changed = true; 243 break; 244 } 245 } 246 } 247 248 if(!changed) 249 return; 250 251 m_highlightedIndices = _indices; 252 253 onHighlightedIndicesChanged(m_highlightedIndices); 254 } 255 256 void Graph::modifyValue(uint32_t _index, float _unnormalizedValue) 257 { 258 } 259 260 void Graph::setHoveredIndex(uint32_t _index) 261 { 262 if(_index == m_hoveredIndex) 263 return; 264 m_hoveredIndex = _index; 265 onHoveredIndexChanged(m_hoveredIndex); 266 } 267 268 void Graph::setLastMouseEvent(const juce::MouseEvent& _e) 269 { 270 m_lastMouseEvent = std::make_unique<juce::MouseEvent>(_e); 271 } 272 273 void Graph::modifyValuesForRange(const juce::MouseEvent& _a, const juce::MouseEvent& _b) 274 { 275 auto indexA = mouseToIndex(_a); 276 auto indexB = mouseToIndex(_b); 277 278 auto valueA = mouseToUnnormalizedValue(_a); 279 auto valueB = mouseToUnnormalizedValue(_b); 280 281 if(indexA > indexB) 282 { 283 std::swap(indexA, indexB); 284 std::swap(valueA, valueB); 285 } 286 287 const auto count = indexB - indexA + 1; 288 289 const auto valueDiff = valueB - valueA; 290 const auto factor = valueDiff / static_cast<float>(count); 291 292 auto v = valueA; 293 294 for(auto i = indexA; i <= indexB; ++i) 295 { 296 if(i < 0) 297 continue; 298 299 if(i >= static_cast<int32_t>(getDataSize())) 300 return; 301 302 modifyValue(i, v); 303 v += factor; 304 } 305 } 306 }