in src/Avalonia.Controls.ColorPicker/ColorSpectrum/ColorSpectrum.cs [797:980]
private void UpdateEllipse()
{
if (_selectionEllipsePanel == null)
{
return;
}
// If we don't have an image size yet, we shouldn't be showing the ellipse.
if (_imageWidthFromLastBitmapCreation == 0 ||
_imageHeightFromLastBitmapCreation == 0)
{
_selectionEllipsePanel.IsVisible = false;
return;
}
else
{
_selectionEllipsePanel.IsVisible = true;
}
double xPosition;
double yPosition;
Hsv hsvColor = new Hsv(HsvColor);
hsvColor.H = MathUtilities.Clamp(hsvColor.H, (double)_minHueFromLastBitmapCreation, (double)_maxHueFromLastBitmapCreation);
hsvColor.S = MathUtilities.Clamp(hsvColor.S, _minSaturationFromLastBitmapCreation / 100.0, _maxSaturationFromLastBitmapCreation / 100.0);
hsvColor.V = MathUtilities.Clamp(hsvColor.V, _minValueFromLastBitmapCreation / 100.0, _maxValueFromLastBitmapCreation / 100.0);
if (_shapeFromLastBitmapCreation == ColorSpectrumShape.Box)
{
double xPercent = 0;
double yPercent = 0;
double hPercent = (hsvColor.H - _minHueFromLastBitmapCreation) / (_maxHueFromLastBitmapCreation - _minHueFromLastBitmapCreation);
double sPercent = (hsvColor.S * 100.0 - _minSaturationFromLastBitmapCreation) / (_maxSaturationFromLastBitmapCreation - _minSaturationFromLastBitmapCreation);
double vPercent = (hsvColor.V * 100.0 - _minValueFromLastBitmapCreation) / (_maxValueFromLastBitmapCreation - _minValueFromLastBitmapCreation);
// In the case where saturation was an axis in the spectrum with hue, or value is an axis, full stop,
// we inverted the direction of that axis in order to put more hue on the outside of the ring,
// so we need to do similarly here when positioning the ellipse.
if (_componentsFromLastBitmapCreation == ColorSpectrumComponents.HueSaturation ||
_componentsFromLastBitmapCreation == ColorSpectrumComponents.SaturationHue)
{
sPercent = 1 - sPercent;
}
else
{
vPercent = 1 - vPercent;
}
switch (_componentsFromLastBitmapCreation)
{
case ColorSpectrumComponents.HueValue:
xPercent = hPercent;
yPercent = vPercent;
break;
case ColorSpectrumComponents.HueSaturation:
xPercent = hPercent;
yPercent = sPercent;
break;
case ColorSpectrumComponents.ValueHue:
xPercent = vPercent;
yPercent = hPercent;
break;
case ColorSpectrumComponents.ValueSaturation:
xPercent = vPercent;
yPercent = sPercent;
break;
case ColorSpectrumComponents.SaturationHue:
xPercent = sPercent;
yPercent = hPercent;
break;
case ColorSpectrumComponents.SaturationValue:
xPercent = sPercent;
yPercent = vPercent;
break;
}
xPosition = _imageWidthFromLastBitmapCreation * xPercent;
yPosition = _imageHeightFromLastBitmapCreation * yPercent;
}
else
{
double thetaValue = 0;
double rValue = 0;
double hThetaValue =
_maxHueFromLastBitmapCreation != _minHueFromLastBitmapCreation ?
360 * (hsvColor.H - _minHueFromLastBitmapCreation) / (_maxHueFromLastBitmapCreation - _minHueFromLastBitmapCreation) :
0;
double sThetaValue =
_maxSaturationFromLastBitmapCreation != _minSaturationFromLastBitmapCreation ?
360 * (hsvColor.S * 100.0 - _minSaturationFromLastBitmapCreation) / (_maxSaturationFromLastBitmapCreation - _minSaturationFromLastBitmapCreation) :
0;
double vThetaValue =
_maxValueFromLastBitmapCreation != _minValueFromLastBitmapCreation ?
360 * (hsvColor.V * 100.0 - _minValueFromLastBitmapCreation) / (_maxValueFromLastBitmapCreation - _minValueFromLastBitmapCreation) :
0;
double hRValue = _maxHueFromLastBitmapCreation != _minHueFromLastBitmapCreation ?
(hsvColor.H - _minHueFromLastBitmapCreation) / (_maxHueFromLastBitmapCreation - _minHueFromLastBitmapCreation) - 1 :
0;
double sRValue = _maxSaturationFromLastBitmapCreation != _minSaturationFromLastBitmapCreation ?
(hsvColor.S * 100.0 - _minSaturationFromLastBitmapCreation) / (_maxSaturationFromLastBitmapCreation - _minSaturationFromLastBitmapCreation) - 1 :
0;
double vRValue = _maxValueFromLastBitmapCreation != _minValueFromLastBitmapCreation ?
(hsvColor.V * 100.0 - _minValueFromLastBitmapCreation) / (_maxValueFromLastBitmapCreation - _minValueFromLastBitmapCreation) - 1 :
0;
// In the case where saturation was an axis in the spectrum with hue, or value is an axis, full stop,
// we inverted the direction of that axis in order to put more hue on the outside of the ring,
// so we need to do similarly here when positioning the ellipse.
if (_componentsFromLastBitmapCreation == ColorSpectrumComponents.HueSaturation ||
_componentsFromLastBitmapCreation == ColorSpectrumComponents.SaturationHue)
{
sThetaValue = 360 - sThetaValue;
sRValue = -sRValue - 1;
}
else
{
vThetaValue = 360 - vThetaValue;
vRValue = -vRValue - 1;
}
switch (_componentsFromLastBitmapCreation)
{
case ColorSpectrumComponents.HueValue:
thetaValue = hThetaValue;
rValue = vRValue;
break;
case ColorSpectrumComponents.HueSaturation:
thetaValue = hThetaValue;
rValue = sRValue;
break;
case ColorSpectrumComponents.ValueHue:
thetaValue = vThetaValue;
rValue = hRValue;
break;
case ColorSpectrumComponents.ValueSaturation:
thetaValue = vThetaValue;
rValue = sRValue;
break;
case ColorSpectrumComponents.SaturationHue:
thetaValue = sThetaValue;
rValue = hRValue;
break;
case ColorSpectrumComponents.SaturationValue:
thetaValue = sThetaValue;
rValue = vRValue;
break;
}
double radius = Math.Min(_imageWidthFromLastBitmapCreation, _imageHeightFromLastBitmapCreation) / 2;
xPosition = (Math.Cos((thetaValue * Math.PI / 180.0) + Math.PI) * radius * rValue) + radius;
yPosition = (Math.Sin((thetaValue * Math.PI / 180.0) + Math.PI) * radius * rValue) + radius;
}
// Remember the bitmap size follows physical device pixels
// Warning: LayoutHelper.GetLayoutScale() doesn't work unless the control is visible
// This will not be true in all cases if the color is updated from another control or code-behind
var scale = LayoutHelper.GetLayoutScale(this);
Canvas.SetLeft(_selectionEllipsePanel, (xPosition / scale) - (_selectionEllipsePanel.Width / 2));
Canvas.SetTop(_selectionEllipsePanel, (yPosition / scale) - (_selectionEllipsePanel.Height / 2));
// We only want to bother with the color name tool tip if we can provide color names.
if (IsFocused &&
_selectionEllipsePanel != null &&
ColorHelper.ToDisplayNameExists)
{
ToolTip.SetIsOpen(_selectionEllipsePanel, true);
}
UpdatePseudoClasses();
}