// SPDX-License-Identifier: GPLv3-or-later WITH Appstore-exception // Copyright (C) 2020 Jesse Chappell #include "SonoTextButton.h" #include "CustomLookAndFeel.h" #include SonoTextButton::SonoTextButton(const String & name) : TextButton(name), _buttonStyle(SonoButtonStyleNormal) { } SonoTextButton::~SonoTextButton() { } void SonoTextButton::setButtonStyle(SonoButtonStyle style) { _buttonStyle = style; } void SonoTextButton::drawButtonBackground(Graphics& g, bool isMouseOverButton, bool isButtonDown) { Colour bgcolor = findColour (getToggleState() ? buttonOnColourId : buttonColourId); Colour bordcolor = isColourSpecified(outlineColourId) ? findColour (outlineColourId) : Colour::fromFloatRGBA(0.3, 0.3, 0.3, 0.5); if (isButtonDown) { bgcolor = bgcolor.withMultipliedBrightness(1.8); } else if (isMouseOverButton) { bgcolor = bgcolor.withMultipliedBrightness(1.3); } g.setColour(bgcolor); g.fillPath(fillPath); g.setColour(bordcolor); g.strokePath(borderPath, PathStrokeType(1.0)); } void SonoTextButton::paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown) { LookAndFeel& lf = getLookAndFeel(); drawButtonBackground(g, isMouseOverButton, isButtonDown); if (auto * tetlf = dynamic_cast(&lf)) { Justification just = textJustification; switch (_buttonStyle) { case SonoButtonStyleLowerLeftCorner: just = Justification::centredLeft; break; case SonoButtonStyleLowerRightCorner: just = Justification::centredRight; break; default: break; } tetlf->drawButtonTextWithAlignment (g, *this, isMouseOverButton, isButtonDown, just); } else { lf.drawButtonText (g, *this, isMouseOverButton, isButtonDown); } } bool SonoTextButton::hitTest (int x, int y) { return fillPath.contains(x, y); } void SonoTextButton::resized() { TextButton::resized(); setupPath(); } void SonoTextButton::setupPath() { float borderOffset = 0.5; // _borderWidth*1.5f; float width = getWidth(); float height = getHeight(); fillPath.clear(); borderPath.clear(); if (_buttonStyle == SonoButtonStyleTop) { fillPath.startNewSubPath(borderOffset, borderOffset); fillPath.quadraticTo(width/2.0, height-borderOffset, width - borderOffset, borderOffset); fillPath.lineTo(borderOffset, borderOffset); borderPath.startNewSubPath(borderOffset, borderOffset); borderPath.quadraticTo(width/2.0, height-borderOffset, width - borderOffset, borderOffset); //[fillPath moveToPoint:CGPointMake(borderOffset, borderOffset)]; //[fillPath addQuadCurveToPoint:CGPointMake(width - borderOffset, borderOffset) controlPoint:CGPointMake(width/2.0, height-borderOffset) ]; //[fillPath addLineToPoint:CGPointMake(borderOffset, borderOffset)]; //[borderPath moveToPoint:CGPointMake(borderOffset, borderOffset)]; //[borderPath addQuadCurveToPoint:CGPointMake(width - borderOffset, borderOffset) controlPoint:CGPointMake(width/2.0, height-borderOffset) ]; } else if (_buttonStyle == SonoButtonStyleBottom) { // H /2 + W^2 / 8H float maxdim = jmax(width, height); float radius = circleRadius > 0.0f ? circleRadius : height * 0.5 + (width*width)/(8.0f * height); float startAng = atan2(height - radius, maxdim/2 - width); float endAng = atan2(height - radius, width - maxdim/2); startAng += M_PI_2; endAng += M_PI_2; DBG("Start ang " << radiansToDegrees(startAng) << " end " << radiansToDegrees(endAng) << " h: " << height << " rad: " << radius); fillPath.startNewSubPath(borderOffset, height - borderOffset); fillPath.addCentredArc(maxdim/2, radius, radius, radius, 0.0f, startAng, endAng); fillPath.lineTo(borderOffset, height - borderOffset); borderPath.startNewSubPath(borderOffset, height - borderOffset); borderPath.addCentredArc(maxdim/2, radius, radius, radius, 0.0f, startAng, endAng); borderPath.lineTo(borderOffset, height - borderOffset); //[fillPath moveToPoint:CGPointMake(borderOffset, height - borderOffset)]; //[fillPath addArcWithCenter:CGPointMake(maxdim/2, radius) radius:radius startAngle:startAng endAngle:endAng clockwise:YES]; //[fillPath addLineToPoint:CGPointMake(borderOffset, height - borderOffset)]; //borderPath = [UIBezierPath bezierPath]; //[borderPath moveToPoint:CGPointMake(borderOffset, height -borderOffset)]; //[borderPath addArcWithCenter:CGPointMake(maxdim/2, radius) radius:radius startAngle:startAng endAngle:endAng clockwise:YES]; //[borderPath addLineToPoint:CGPointMake(borderOffset, height - borderOffset)]; } else if (_buttonStyle == SonoButtonStyleLeft) { fillPath.startNewSubPath(borderOffset, borderOffset); fillPath.quadraticTo(width - borderOffset, borderOffset, width - borderOffset, height/2); fillPath.quadraticTo(width - borderOffset, height-borderOffset, borderOffset, height-borderOffset); fillPath.lineTo(borderOffset, borderOffset); borderPath.startNewSubPath(borderOffset, borderOffset); borderPath.quadraticTo(width - borderOffset, borderOffset, width - borderOffset, height/2); borderPath.quadraticTo(width - borderOffset, height-borderOffset, borderOffset, height-borderOffset); //fillPath = [UIBezierPath bezierPath]; //[fillPath moveToPoint:CGPointMake(borderOffset, borderOffset)]; //[fillPath addQuadCurveToPoint:CGPointMake(width - borderOffset, height/2) controlPoint:CGPointMake(width - borderOffset , borderOffset) ]; //[fillPath addQuadCurveToPoint:CGPointMake(borderOffset, height-borderOffset) controlPoint:CGPointMake(width - borderOffset , height-borderOffset) ]; //[fillPath addLineToPoint:CGPointMake(borderOffset, borderOffset)]; //borderPath = [UIBezierPath bezierPath]; //[borderPath moveToPoint:CGPointMake(borderOffset, borderOffset)]; //[borderPath addQuadCurveToPoint:CGPointMake(width - borderOffset, height/2) controlPoint:CGPointMake(width - borderOffset , borderOffset) ]; //[borderPath addQuadCurveToPoint:CGPointMake(borderOffset, height-borderOffset) controlPoint:CGPointMake(width - borderOffset , height-borderOffset) ]; } else if (_buttonStyle == SonoButtonStyleRight) { fillPath.startNewSubPath(width - borderOffset, borderOffset); fillPath.quadraticTo(borderOffset, borderOffset, borderOffset, height/2); fillPath.quadraticTo(borderOffset, height-borderOffset, width - borderOffset, height-borderOffset); fillPath.lineTo(width - borderOffset, borderOffset); borderPath.startNewSubPath(width - borderOffset, borderOffset); borderPath.quadraticTo(borderOffset, borderOffset, borderOffset, height/2); borderPath.quadraticTo(borderOffset, height-borderOffset, width - borderOffset, height-borderOffset); //fillPath = [UIBezierPath bezierPath]; //[fillPath moveToPoint:CGPointMake(width - borderOffset, borderOffset)]; //[fillPath addQuadCurveToPoint:CGPointMake(borderOffset, height/2) controlPoint:CGPointMake(borderOffset, borderOffset) ]; //[fillPath addQuadCurveToPoint:CGPointMake(width - borderOffset, height - borderOffset) controlPoint:CGPointMake(borderOffset, height - borderOffset)]; //[fillPath addLineToPoint:CGPointMake(width - borderOffset, borderOffset)]; //borderPath = [UIBezierPath bezierPath]; //[borderPath moveToPoint:CGPointMake(width -borderOffset, borderOffset)]; //[borderPath addQuadCurveToPoint:CGPointMake(borderOffset, height/2) controlPoint:CGPointMake(borderOffset, borderOffset) ]; //[borderPath addQuadCurveToPoint:CGPointMake(width - borderOffset, height - borderOffset) controlPoint:CGPointMake(borderOffset, height - borderOffset)]; } else if (_buttonStyle == SonoButtonStyleUpperLeftCorner) { fillPath.startNewSubPath(borderOffset, borderOffset); fillPath.lineTo(width - borderOffset, borderOffset); fillPath.quadraticTo(width - borderOffset, height - borderOffset, borderOffset, height - borderOffset); fillPath.lineTo(borderOffset, borderOffset); borderPath.startNewSubPath(width - borderOffset, borderOffset); borderPath.quadraticTo(width - borderOffset, height - borderOffset, borderOffset, height - borderOffset); //fillPath = [UIBezierPath bezierPath]; //[fillPath moveToPoint:CGPointMake(borderOffset, borderOffset)]; //[fillPath addLineToPoint:CGPointMake(width-borderOffset, borderOffset)]; //[fillPath addQuadCurveToPoint:CGPointMake(borderOffset, height-borderOffset) controlPoint:CGPointMake(width-borderOffset, height-borderOffset) ]; //[fillPath addLineToPoint:CGPointMake(borderOffset, borderOffset)]; //borderPath = [UIBezierPath bezierPath]; //[borderPath moveToPoint:CGPointMake(width-borderOffset, borderOffset)]; //[borderPath addQuadCurveToPoint:CGPointMake(borderOffset, height-borderOffset) controlPoint:CGPointMake(width-borderOffset, height-borderOffset) ]; } else if (_buttonStyle == SonoButtonStyleUpperRightCorner) { fillPath.startNewSubPath(width - borderOffset, borderOffset); fillPath.lineTo(width - borderOffset, height - borderOffset); fillPath.quadraticTo(borderOffset, height - borderOffset, borderOffset, borderOffset); fillPath.lineTo(width - borderOffset, borderOffset); borderPath.startNewSubPath(width - borderOffset, height - borderOffset); borderPath.quadraticTo(borderOffset, height - borderOffset, borderOffset, borderOffset); //fillPath = [UIBezierPath bezierPath]; //[fillPath moveToPoint:CGPointMake(width - borderOffset, borderOffset)]; //[fillPath addLineToPoint:CGPointMake(width - borderOffset, height - borderOffset)]; //[fillPath addQuadCurveToPoint:CGPointMake(borderOffset, borderOffset) controlPoint:CGPointMake(borderOffset, height-borderOffset) ]; //[fillPath addLineToPoint:CGPointMake(width - borderOffset, borderOffset)]; //borderPath = [UIBezierPath bezierPath]; //[borderPath moveToPoint:CGPointMake(width - borderOffset, height - borderOffset)]; //[borderPath addQuadCurveToPoint:CGPointMake(borderOffset, borderOffset) controlPoint:CGPointMake(borderOffset, height-borderOffset) ]; } else if (_buttonStyle == SonoButtonStyleLowerLeftCorner) { fillPath.startNewSubPath(borderOffset, height - borderOffset); fillPath.lineTo(borderOffset, borderOffset); fillPath.quadraticTo(width-borderOffset, borderOffset, width-borderOffset, height-borderOffset); fillPath.lineTo(borderOffset, height-borderOffset); borderPath.startNewSubPath(borderOffset, borderOffset); borderPath.quadraticTo(width-borderOffset, borderOffset, width-borderOffset, height-borderOffset); //fillPath = [UIBezierPath bezierPath]; //[fillPath moveToPoint:CGPointMake(borderOffset, height-borderOffset)]; //[fillPath addLineToPoint:CGPointMake(borderOffset, borderOffset)]; //[fillPath addQuadCurveToPoint:CGPointMake(width-borderOffset, height-borderOffset) controlPoint:CGPointMake(width-borderOffset, borderOffset) ]; //[fillPath addLineToPoint:CGPointMake(borderOffset, height-borderOffset)]; //borderPath = [UIBezierPath bezierPath]; //[borderPath moveToPoint:CGPointMake(borderOffset, borderOffset)]; //[borderPath addQuadCurveToPoint:CGPointMake(width-borderOffset, height-borderOffset) controlPoint:CGPointMake(width-borderOffset, borderOffset) ]; } else if (_buttonStyle == SonoButtonStyleLowerRightCorner) { fillPath.startNewSubPath(width-borderOffset, height - borderOffset); fillPath.lineTo(borderOffset, height-borderOffset); fillPath.quadraticTo(borderOffset, borderOffset, width-borderOffset, borderOffset); fillPath.lineTo(width - borderOffset, height-borderOffset); borderPath.startNewSubPath(borderOffset, height - borderOffset); borderPath.quadraticTo(borderOffset, borderOffset, width-borderOffset, borderOffset); //fillPath = [UIBezierPath bezierPath]; //[fillPath moveToPoint:CGPointMake(width-borderOffset, height-borderOffset)]; //[fillPath addLineToPoint:CGPointMake(borderOffset, height-borderOffset)]; //[fillPath addQuadCurveToPoint:CGPointMake(width-borderOffset, borderOffset) controlPoint:CGPointMake(borderOffset, borderOffset) ]; //[fillPath addLineToPoint:CGPointMake(width-borderOffset, height-borderOffset)]; //borderPath = [UIBezierPath bezierPath]; //[borderPath moveToPoint:CGPointMake(borderOffset, height-borderOffset)]; //[borderPath addQuadCurveToPoint:CGPointMake(width-borderOffset, borderOffset) controlPoint:CGPointMake(borderOffset, borderOffset) ]; } else if (_buttonStyle == SonoButtonStyleLowerRightCornerRound) { float maxdim = jmax(width*2, height); // H /2 + W^2 / 8H (but double the width here) float radius = circleRadius > 0.0f ? circleRadius : height * 0.5 + (width*width*4.0)/(8.0f * height); float startAng = atan2(height - radius, maxdim/2 - width*2); float endAng = atan2(height - radius, width - maxdim/2) ; startAng += M_PI_2; endAng += M_PI_2; fillPath.startNewSubPath(borderOffset, height - borderOffset); fillPath.addCentredArc(maxdim/2, radius, radius, radius, 0.0f, startAng, endAng); fillPath.lineTo(width - borderOffset, height - borderOffset); fillPath.lineTo(borderOffset, height - borderOffset); borderPath.startNewSubPath(borderOffset, height - borderOffset); borderPath.addCentredArc(maxdim/2, radius, radius, radius, 0.0f, startAng, endAng); borderPath.lineTo(width - borderOffset, height - borderOffset); borderPath.lineTo(borderOffset, height - borderOffset); //fillPath = [UIBezierPath bezierPath]; //[fillPath moveToPoint:CGPointMake(borderOffset, height - borderOffset)]; //[fillPath addArcWithCenter:CGPointMake(maxdim/2, radius) radius:radius startAngle:startAng endAngle:endAng clockwise:YES]; //[fillPath addLineToPoint:CGPointMake(width - borderOffset, height - borderOffset)]; //[fillPath addLineToPoint:CGPointMake(borderOffset, height - borderOffset)]; //borderPath = [UIBezierPath bezierPath]; //[borderPath moveToPoint:CGPointMake(borderOffset, height -borderOffset)]; //[borderPath addArcWithCenter:CGPointMake(maxdim/2, radius) radius:radius startAngle:startAng endAngle:endAng clockwise:YES]; //[borderPath addLineToPoint:CGPointMake(width - borderOffset, height - borderOffset)]; //[borderPath addLineToPoint:CGPointMake(borderOffset, height - borderOffset)]; } else if (_buttonStyle == SonoButtonStyleLowerLeftCornerRound) { float maxdim = jmax(width*2, height); // H /2 + W^2 / 8H (but double the width here) float radius = circleRadius > 0.0f ? circleRadius : height * 0.5 + (width*width*4.0)/(8.0f * height); float startAng = atan2(height - radius, width - maxdim/2) ; float endAng = atan2(height - radius, width*2 - maxdim/2); startAng += M_PI_2; endAng += M_PI_2; fillPath.startNewSubPath(borderOffset, height - borderOffset); fillPath.lineTo(borderOffset, borderOffset); fillPath.addCentredArc(maxdim/2, radius, radius, radius, 0.0f, startAng, endAng); fillPath.lineTo(borderOffset, height - borderOffset); borderPath.startNewSubPath(borderOffset, height - borderOffset); borderPath.lineTo(borderOffset, borderOffset); borderPath.addCentredArc(maxdim/2, radius, radius, radius, 0.0f, startAng, endAng); borderPath.lineTo(borderOffset, height - borderOffset); //fillPath = [UIBezierPath bezierPath]; //[fillPath moveToPoint:CGPointMake(borderOffset, height - borderOffset)]; //[fillPath addLineToPoint:CGPointMake(borderOffset, borderOffset)]; //[fillPath addArcWithCenter:CGPointMake(maxdim/2 - width, radius) radius:radius startAngle:startAng endAngle:endAng clockwise:YES]; //[fillPath addLineToPoint:CGPointMake(borderOffset, height - borderOffset)]; //borderPath = [UIBezierPath bezierPath]; //[borderPath moveToPoint:CGPointMake(borderOffset, height -borderOffset)]; //[borderPath addLineToPoint:CGPointMake(borderOffset, borderOffset)]; //[borderPath addArcWithCenter:CGPointMake(maxdim/2 - width, radius) radius:radius startAngle:startAng endAngle:endAng clockwise:YES]; //[borderPath addLineToPoint:CGPointMake(borderOffset, height - borderOffset)]; } else if (_buttonStyle == SonoButtonStyleUpperRightCornerRound) { float maxdim = jmax(width*2, height); // H /2 + W^2 / 8H (but double the width here) float radius = circleRadius > 0.0f ? circleRadius : height * 0.5 + (width*width*4.0)/(8.0f * height); float startAng = atan2(radius - height, maxdim/2 - width*2); float endAng = atan2(radius - height , width - maxdim/2) ; startAng += M_PI_2; endAng += M_PI_2; DBG("URC Start ang " << radiansToDegrees(startAng) << " end " << radiansToDegrees(endAng) << " h: " << height << " rad: " << radius); fillPath.startNewSubPath(borderOffset, borderOffset); fillPath.addCentredArc(maxdim/2, height-radius, radius, radius, 0.0f, startAng, endAng); fillPath.lineTo(width - borderOffset, borderOffset); fillPath.lineTo(borderOffset, borderOffset); borderPath.startNewSubPath(borderOffset, borderOffset); borderPath.addCentredArc(maxdim/2, height-radius, radius, radius, 0.0f, startAng, endAng); borderPath.startNewSubPath(width - borderOffset, borderOffset); borderPath.lineTo(borderOffset, borderOffset); //fillPath = [UIBezierPath bezierPath]; //[fillPath moveToPoint:CGPointMake(borderOffset, borderOffset)]; //[fillPath addArcWithCenter:CGPointMake(maxdim/2, height -radius) radius:radius startAngle:startAng endAngle:endAng clockwise:NO]; //[fillPath addLineToPoint:CGPointMake(width - borderOffset, borderOffset)]; //[fillPath addLineToPoint:CGPointMake(borderOffset, borderOffset)]; //borderPath = [UIBezierPath bezierPath]; //[borderPath moveToPoint:CGPointMake(borderOffset, borderOffset)]; //[borderPath addArcWithCenter:CGPointMake(maxdim/2, height -radius) radius:radius startAngle:startAng endAngle:endAng clockwise:NO]; //[borderPath addLineToPoint:CGPointMake(width - borderOffset, borderOffset)]; //[borderPath moveToPoint:CGPointMake(width - borderOffset, borderOffset)]; //[borderPath addLineToPoint:CGPointMake(borderOffset, borderOffset)]; } else if (_buttonStyle == SonoButtonStyleUpperLeftCornerRound) { float maxdim = jmax(width*2, height); // H /2 + W^2 / 8H (but double the width here) float radius = circleRadius > 0.0f ? circleRadius : height * 0.5 + (width*width*4.0)/(8.0f * height); float startAng = atan2(radius - height, width - maxdim/2) ; float endAng = atan2(radius-height, width*2 - maxdim/2); startAng += M_PI_2; endAng += M_PI_2; DBG("URC Start ang " << radiansToDegrees(startAng) << " end " << radiansToDegrees(endAng) << " h: " << height << " rad: " << radius); fillPath.startNewSubPath(borderOffset, borderOffset); fillPath.lineTo(borderOffset, height - borderOffset); fillPath.addCentredArc(maxdim/2 - width, height-radius, radius, radius, 0.0f, startAng, endAng); fillPath.lineTo(borderOffset, borderOffset); borderPath.startNewSubPath(borderOffset, height - borderOffset); borderPath.lineTo(borderOffset, height - borderOffset); borderPath.addCentredArc(maxdim/2 - width, height-radius, radius, radius, 0.0f, startAng, endAng); borderPath.lineTo(borderOffset, borderOffset); //fillPath = [UIBezierPath bezierPath]; //[fillPath moveToPoint:CGPointMake(borderOffset, borderOffset)]; //[fillPath addLineToPoint:CGPointMake(borderOffset, height - borderOffset)]; ////[fillPath moveToPoint:CGPointMake(borderOffset, height - borderOffset)]; //[fillPath addArcWithCenter:CGPointMake(maxdim/2 - width, height -radius) radius:radius startAngle:startAng endAngle:endAng clockwise:NO]; //[fillPath addLineToPoint:CGPointMake(borderOffset, borderOffset)]; //borderPath = [UIBezierPath bezierPath]; ////[borderPath moveToPoint:CGPointMake(borderOffset, borderOffset)]; ////[borderPath addLineToPoint:CGPointMake(borderOffset, height - borderOffset)]; //[borderPath moveToPoint:CGPointMake(borderOffset, height - borderOffset)]; //[borderPath addArcWithCenter:CGPointMake(maxdim/2 - width, height -radius) radius:radius startAngle:startAng endAngle:endAng clockwise:NO]; //[borderPath addLineToPoint:CGPointMake(borderOffset, borderOffset)]; } else { auto bounds = getLocalBounds().toFloat().reduced(borderOffset); fillPath.addRoundedRectangle(bounds, cornerRadius); borderPath.addRoundedRectangle(bounds, cornerRadius); } }