33 m_controlsSize = size;
39 return m_controlsSize;
44 switch (m_controlsSize)
58 m_boundsRealRef = boundsRealRef;
61juce::Rectangle<float> UmsciPaintNControlComponentBase::computeBaseContentBounds()
const
63 auto bounds = getLocalBounds().toFloat();
64 if (m_boundsRealRef.isEmpty())
67 if (m_boundsRealRef.getAspectRatio() > bounds.getAspectRatio())
68 return bounds.withSizeKeepingCentre(bounds.getWidth(), bounds.getWidth() / m_boundsRealRef.getAspectRatio());
70 return bounds.withSizeKeepingCentre(bounds.getHeight() * m_boundsRealRef.getAspectRatio(), bounds.getHeight());
73juce::Rectangle<float> UmsciPaintNControlComponentBase::getContentBounds()
const
75 auto base = computeBaseContentBounds();
76 if (m_zoomFactor == 1.0f && m_zoomPanOffset.isOrigin())
80 auto cx = base.getCentreX() + m_zoomPanOffset.x * base.getWidth();
81 auto cy = base.getCentreY() + m_zoomPanOffset.y * base.getHeight();
82 auto hw = base.getWidth() * m_zoomFactor * 0.5f;
83 auto hh = base.getHeight() * m_zoomFactor * 0.5f;
84 return { cx - hw, cy - hh, hw * 2.0f, hh * 2.0f };
87void UmsciPaintNControlComponentBase::applyZoomAtScreenPoint(
float newFactor, juce::Point<float> screenFocus)
89 newFactor = juce::jlimit(0.1f, 10.0f, newFactor);
90 auto rz = newFactor / m_zoomFactor;
92 auto base = computeBaseContentBounds();
96 auto Pnorm = juce::Point<float>((screenFocus.x - base.getCentreX()) / base.getWidth(),
97 (screenFocus.y - base.getCentreY()) / base.getHeight());
99 m_zoomPanOffset = Pnorm + (m_zoomPanOffset - Pnorm) * rz;
102 m_zoomFactor = newFactor;
112 const float zoomSpeed = 0.5f;
113 auto newFactor = m_zoomFactor * std::exp(wheel.deltaY * zoomSpeed);
114 applyZoomAtScreenPoint(newFactor, e.position);
124 applyZoomAtScreenPoint(m_zoomFactor * scaleFactor, e.position);
134 const int idx = e.source.getIndex();
136 if (idx < 0 || idx > 1)
141 m_pinchDown[idx] =
true;
142 m_pinchPos[idx] = e.position;
144 if (m_pinchDown[0] && m_pinchDown[1])
146 auto d = m_pinchPos[1] - m_pinchPos[0];
147 m_pinchStartDistance = std::hypot(d.x, d.y);
148 m_pinchStartZoom = m_zoomFactor;
149 if (m_pinchStartDistance > 1.0f)
150 m_pinchActive =
true;
157 const bool wasActive = m_pinchActive;
158 m_pinchDown[idx] =
false;
159 if (!m_pinchDown[0] || !m_pinchDown[1])
160 m_pinchActive =
false;
162 return idx > 0 || wasActive;
166 m_pinchPos[idx] = e.position;
168 if (m_pinchActive && m_pinchDown[0] && m_pinchDown[1])
170 auto d = m_pinchPos[1] - m_pinchPos[0];
171 const float currentDist = std::hypot(d.x, d.y);
172 if (currentDist > 1.0f && m_pinchStartDistance > 1.0f)
174 auto midpoint = (m_pinchPos[0] + m_pinchPos[1]) * 0.5f;
175 applyZoomAtScreenPoint(m_pinchStartZoom * currentDist / m_pinchStartDistance, midpoint);
182 return m_pinchActive;
188 applyZoomAtScreenPoint(m_zoomFactor * scaleFactor, centre);
201 auto clamped = juce::jlimit(0.1f, 10.0f, factor);
202 if (m_zoomFactor == clamped && m_zoomPanOffset == normalizedPanOffset)
205 m_zoomFactor = clamped;
206 m_zoomPanOffset = normalizedPanOffset;
217 if (m_zoomFactor == 1.0f && m_zoomPanOffset.isOrigin())
221 m_zoomPanOffset = {};
230 auto contentBounds = getContentBounds();
231 if (contentBounds.getWidth() == 0.0f || contentBounds.getHeight() == 0.0f)
232 return { 0.0f, 0.0f, 0.0f };
234 auto relativeX = (screenPoint.getX() - contentBounds.getX()) / contentBounds.getWidth();
235 auto relativeY = (screenPoint.getY() - contentBounds.getY()) / contentBounds.getHeight();
238 auto yReal = relativeX * m_boundsRealRef.getWidth() + m_boundsRealRef.getX();
239 auto xReal = relativeY * m_boundsRealRef.getHeight() + m_boundsRealRef.getY();
241 return { xReal, yReal, 0.0f };
246 auto& xReal = realCoordinate.at(0);
247 auto& yReal = realCoordinate.at(1);
250 if (m_boundsRealRef.getWidth() == 0.0f || m_boundsRealRef.getHeight() == 0.0f)
251 return { 0.0f, 0.0f };
254 auto relativeX = (yReal - m_boundsRealRef.getX()) / m_boundsRealRef.getWidth();
255 auto relativeY = (xReal - m_boundsRealRef.getY()) / m_boundsRealRef.getHeight();
257 return getContentBounds().getRelativePoint(relativeX, relativeY);
void mouseMagnify(const juce::MouseEvent &, float scaleFactor) override
Trackpad pinch-to-zoom (macOS).
float getZoomFactor() const
ControlsSize
Visual size of source/speaker icons. Multiplier accessible via getControlsSizeMultiplier().
void setZoom(float factor, juce::Point< float > normalizedPanOffset={})
Silently applies zoom without firing onViewportZoomChanged. Used by UmsciControlComponent to synchron...
virtual void onZoomChanged()
Called after any zoom state change.
void mouseDoubleClick(const juce::MouseEvent &) override
Double-click resets zoom to 1.0 via resetZoom().
bool processPinchGesture(const juce::MouseEvent &e, bool isDown, bool isUp)
JUCE-level two-touch pinch-zoom fallback for platforms where neither mouseMagnify nor a native gestur...
virtual ~UmsciPaintNControlComponentBase() override
std::array< float, 3 > GetRealCoordinateForPoint(const juce::Point< float > &screenPoint)
Inverse of GetPointForRealCoordinate — converts a screen pixel point back to a 3D real-world coordina...
void mouseWheelMove(const juce::MouseEvent &, const juce::MouseWheelDetails &) override
Mouse-wheel zooms about the cursor position.
std::function< void(float, juce::Point< float >)> onViewportZoomChanged
Fired after every user-initiated zoom/pan change (wheel, pinch, double-click). Parameters: (newFactor...
ControlsSize getControlsSize() const
void simulatePinchZoom(float scaleFactor, juce::Point< float > centre)
Applies an incremental pinch-zoom step, as if the user performed a native pinch gesture centred at ce...
juce::Point< float > GetPointForRealCoordinate(const std::array< float, 3 > &realCoordinate)
Converts a 3D real-world coordinate to a 2D screen pixel point.
virtual void setControlsSize(ControlsSize size)
Updates the icon size; derived classes may override to re-prerender.
void resetZoom()
Resets zoom to 1.0 / no pan and fires onViewportZoomChanged.
void setBoundsRealRef(const juce::Rectangle< float > &boundsRealRef)
Sets the real-world rectangle that the component's pixel bounds map to.
float getControlsSizeMultiplier() const
Returns a multiplier (e.g. 0.5 / 1.0 / 1.5) for S/M/L icon sizes.
UmsciPaintNControlComponentBase()