28 namespace Util = MacOSX::Util;
32 const CGSize shadowOffset = CGSizeMake(10., 10.);
33 const CGFloat shadowBlur = 5.;
40 template<
class SRC,
class DST>
41 struct GradientFactory {
42 static CGGradientRef CreateGradient(CGColorSpaceRef colorSpace,
45 assert(colorSpace !=
nullptr &&
46 "GradientFactory::CreateGradient, parameter 'colorSpace' is null");
47 assert(extendedColor !=
nullptr &&
48 "GradientFactory::CreateGradient, parameter 'extendedColor' is null");
49 const SRC *compStart = extendedColor->
GetColors();
51 const std::vector<DST> convertedComponents(compStart, compEnd);
54 const std::vector<DST> convertedPositions(posStart, posEnd);
56 return CGGradientCreateWithColorComponents(colorSpace,
57 &convertedComponents[0],
58 &convertedPositions[0],
64 struct GradientFactory<DST, DST> {
65 static CGGradientRef CreateGradient(CGColorSpaceRef colorSpace,
68 assert(colorSpace !=
nullptr &&
69 "GradientFactory::CreateGradient, parameter 'colorSpace' is null");
70 assert(extendedColor !=
nullptr &&
71 "GradientFactory::CreateGradient, parameter 'extendedColor' is null");
72 const DST *comps = extendedColor->
GetColors();
74 return CGGradientCreateWithColorComponents(colorSpace, comps, pos,
79 struct GradientParameters {
95 : fStartPoint(), fEndPoint(), fStartRadius(0.), fEndRadius(0.)
99 GradientParameters(
const CGPoint &start,
const CGPoint &end)
105 GradientParameters(
const CGPoint &start,
const CGPoint &end,
106 CGFloat startRadius, CGFloat endRadius)
118 assert(nPoints > 2 &&
"FindBoundingBox, invalid number of points in a polygon");
119 assert(xy !=
nullptr &&
"FindBoundingBox, parameter 'xy' is null");
121 CGPoint bottomLeft = {};
122 bottomLeft.x = xy[0].
fX;
123 bottomLeft.y = xy[0].
fY;
125 CGPoint topRight = bottomLeft;
127 for (
Int_t i = 1; i < nPoints; ++i) {
128 bottomLeft.x = std::min(bottomLeft.x, CGFloat(xy[i].fX));
129 bottomLeft.y = std::min(bottomLeft.y, CGFloat(xy[i].fY));
131 topRight.x = std::max(topRight.x, CGFloat(xy[i].fX));
132 topRight.y = std::max(topRight.y, CGFloat(xy[i].fY));
135 return CGRectMake(bottomLeft.x, bottomLeft.y,
136 topRight.x - bottomLeft.x,
137 topRight.y - bottomLeft.y);
141 template<
class GradientType>
142 bool CalculateGradientStartEnd(
const GradientType *grad,
143 const CGSize &sizeOfDrawable,
145 GradientParameters ¶ms)
147 assert(grad !=
nullptr &&
148 "CalculateGradientStartEnd, parameter 'grad' is null");
149 assert(sizeOfDrawable.width > 0. && sizeOfDrawable.height > 0. &&
150 "CalculateGradientStartEnd, invalid destination drawable size");
152 "CalculateGradientStartEnd, parameter 'n' is not a valid number of points");
153 assert(polygon !=
nullptr &&
154 "CalculateGradientStartEnd, parameter 'polygon' is null");
158 CGPoint start = CGPointMake(grad->GetStart().fX, grad->GetStart().fY);
159 CGPoint end = CGPointMake(grad->GetEnd().fX, grad->GetEnd().fY);
161 const CGRect &bbox = FindBoundingBox(n, polygon);
163 if (!bbox.size.width || !bbox.size.height)
169 start.x = bbox.size.width * start.x + bbox.origin.x;
170 end.x = bbox.size.width * end.x + bbox.origin.x;
172 start.y = bbox.size.height * start.y + bbox.origin.y;
173 end.y = bbox.size.height * end.y + bbox.origin.y;
175 start.x *= sizeOfDrawable.width;
176 start.y *= sizeOfDrawable.height;
177 end.x *= sizeOfDrawable.width;
178 end.y *= sizeOfDrawable.height;
181 params.fStartPoint = start;
182 params.fEndPoint = end;
189 const CGSize &sizeOfDrawable,
191 GradientParameters ¶ms)
193 assert(grad !=
nullptr &&
"CalculateGradientRadiuses, parameter 'grad' is null");
194 assert(sizeOfDrawable.width > 0. && sizeOfDrawable.height > 0. &&
195 "CalculateGradientRadiuses, invalid destination drawable size");
197 "CalculateGradientRadiuses, extended radial gradient expected");
198 assert(n > 2 &&
"CalculateGradientRadiuses, parameter 'n' is not a valid number of points");
199 assert(polygon !=
nullptr &&
200 "CalculateGradientRadiuses, parameter 'polygon' is null");
203 const CGRect &bbox = FindBoundingBox(n, polygon);
204 if (!bbox.size.width || !bbox.size.height)
207 CGFloat startRadius = grad->
GetR1();
208 CGFloat endRadius = grad->
GetR2();
211 const CGFloat scale = std::max(bbox.size.width, bbox.size.height);
213 startRadius *= scale;
216 const CGFloat scale = std::max(sizeOfDrawable.width, sizeOfDrawable.height);
218 startRadius *= scale;
222 params.fStartRadius = startRadius;
223 params.fEndRadius = endRadius;
229 bool CalculateSimpleRadialGradientParameters(
const TRadialGradient *grad,
230 const CGSize &sizeOfDrawable,
232 GradientParameters ¶ms)
234 assert(grad !=
nullptr &&
235 "CalculateSimpleRadialGradientParameters, parameter 'grad' is null");
237 "CalculateSimpleRadialGradientParameters, invalid gradient type");
238 assert(sizeOfDrawable.width > 0. && sizeOfDrawable.height > 0. &&
239 "CCalculateSimpleRadialGradientParameters, invalid destination drawable size");
241 "CalculateSimpleRadialGradientParameters, parameter 'n' is not a valid number of points");
242 assert(polygon !=
nullptr &&
243 "CalculateSimpleRadialGradientParameters, parameter 'polygon' is null");
246 const CGRect &bbox = FindBoundingBox(n, polygon);
247 if (!bbox.size.width || !bbox.size.height)
255 radius *= std::max(bbox.size.width, bbox.size.height);
256 center.x = bbox.size.width * center.x + bbox.origin.x;
257 center.y = bbox.size.height * center.y + bbox.origin.y;
259 radius *= std::max(sizeOfDrawable.width, sizeOfDrawable.height);
260 center.x *= sizeOfDrawable.width;
261 center.y *= sizeOfDrawable.height;
264 params.fStartPoint = center;
265 params.fStartRadius = radius;
271 bool CalculateGradientParameters(
const TColorGradient *extendedColor,
272 const CGSize &sizeOfDrawable,
274 GradientParameters ¶ms)
276 assert(extendedColor !=
nullptr &&
277 "CalculateGradientParameters, parameter 'extendedColor' is null");
278 assert(sizeOfDrawable.width > 0. && sizeOfDrawable.height > 0. &&
279 "CalculateGradientParameters, invalid destination drawable size");
280 assert(n > 2 &&
"CalculateGradientParameters, parameter 'n' is not a valid number of points");
281 assert(polygon !=
nullptr &&
282 "CalculateGradientParameters, parameter 'polygon' is null");
284 if (
const TLinearGradient *
const gl = dynamic_cast<const TLinearGradient *>(extendedColor))
285 return CalculateGradientStartEnd(gl, sizeOfDrawable, n, polygon, params);
286 else if (
const TRadialGradient *
const gr = dynamic_cast<const TRadialGradient *>(extendedColor)) {
288 return CalculateSimpleRadialGradientParameters(
gr, sizeOfDrawable, n, polygon, params);
290 if (CalculateGradientStartEnd(
gr, sizeOfDrawable, n, polygon, params))
291 return CalculateGradientRadiuses(
gr, sizeOfDrawable, n, polygon, params);
296 assert(0 &&
"CalculateGradientParamters, unknown gradient type");
306 assert(ctx !=
nullptr &&
"SetFillColor, ctx parameter is null");
317 const CGFloat alpha = color->
GetAlpha();
320 color->
GetRGB(rgb[0], rgb[1], rgb[2]);
321 CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha);
329 assert(data !=
nullptr &&
"DrawPattern, data parameter is null");
330 assert(ctx !=
nullptr &&
"DrawPattern, ctx parameter is null");
333 const unsigned stencilIndex = *
static_cast<unsigned *
>(
data);
335 for (
int i = 30,
y = 0; i >= 0; i -= 2, ++
y) {
337 for (
int j = 0; j < 8; ++j, ++
x) {
338 if (
gStipples[stencilIndex][i] & (1 << j))
339 CGContextFillRect(ctx, CGRectMake(x,
y, 1, 1));
342 for (
int j = 0; j < 8; ++j, ++
x) {
343 if (
gStipples[stencilIndex][i + 1] & (1 << j))
344 CGContextFillRect(ctx, CGRectMake(x,
y, 1, 1));
352 assert(ctx !=
nullptr &&
"SetFillPattern, ctx parameter is null");
353 assert(patternIndex !=
nullptr &&
"SetFillPattern, patternIndex parameter is null");
366 if (!baseSpace.
Get())
370 if (!patternSpace.
Get())
373 CGContextSetFillColorSpace(ctx, patternSpace.
Get());
375 CGPatternCallbacks callbacks = {0, &
DrawPattern, 0};
377 CGRectMake(0, 0, 16, 16),
378 CGAffineTransformIdentity, 16, 16,
379 kCGPatternTilingConstantSpacing,
385 CGContextSetFillPattern(ctx, pattern.
Get(), rgba);
393 assert(ctx !=
nullptr &&
"SetFillAreaParameters, ctx parameter is null");
395 const unsigned fillStyle =
gVirtualX->GetFillStyle() / 1000;
398 if (fillStyle == 2 || (fillStyle != 1 && fillStyle != 3)) {
400 ::Error(
"SetFillAreaParameters",
"Line color for index %d was not found",
int(
gVirtualX->GetLineColor()));
403 }
else if (fillStyle == 1) {
406 ::Error(
"SetFillAreaParameters",
"Fill color for index %d was not found",
int(
gVirtualX->GetFillColor()));
410 assert(patternIndex !=
nullptr &&
"SetFillAreaParameters, pattern index in null");
412 *patternIndex =
gVirtualX->GetFillStyle() % 1000;
414 if (*patternIndex > 25)
418 ::Error(
"SetFillAreaParameters",
"SetFillPattern failed");
437 CGContextStrokeRect(ctx, CGRectMake(x1, y1, x2 - x1, y2 - y1));
439 CGContextFillRect(ctx, CGRectMake(x1, y1, x2 - x1, y2 - y1));
449 assert(ctx !=
nullptr &&
"DrawFillArea, ctx parameter is null");
450 assert(xy !=
nullptr &&
"DrawFillArea, xy parameter is null");
452 CGContextBeginPath(ctx);
454 CGContextMoveToPoint(ctx, xy[0].fX, xy[0].fY);
455 for (
Int_t i = 1; i <
n; ++i)
456 CGContextAddLineToPoint(ctx, xy[i].fX, xy[i].fY);
458 CGContextClosePath(ctx);
460 const unsigned fillStyle =
gVirtualX->GetFillStyle() / 1000;
463 if (fillStyle == 2 || (fillStyle != 1 && fillStyle != 3)) {
464 CGContextStrokePath(ctx);
465 }
else if (fillStyle == 1) {
467 CGContextSetShadow(ctx, shadowOffset, shadowBlur);
469 CGContextFillPath(ctx);
472 CGContextSetShadow(ctx, shadowOffset, shadowBlur);
474 CGContextFillPath(ctx);
484 assert(ctx !=
nullptr &&
"DrawPolygonWithGradientFill, ctx parameter is null");
485 assert(nPoints != 0 &&
"DrawPolygonWithGradientFill, nPoints parameter is 0");
486 assert(xy !=
nullptr &&
"DrawPolygonWithGradientFill, xy parameter is null");
487 assert(extendedColor !=
nullptr &&
488 "DrawPolygonWithGradientFill, extendedColor parameter is null");
490 if (!sizeOfDrawable.width || !sizeOfDrawable.height)
493 const CFScopeGuard<CGMutablePathRef> path(CGPathCreateMutable());
495 ::Error(
"DrawPolygonWithGradientFill",
"CGPathCreateMutable failed");
500 const CFScopeGuard<CGColorSpaceRef> baseSpace(CGColorSpaceCreateDeviceRGB());
501 if (!baseSpace.Get()) {
502 ::Error(
"DrawPolygonWithGradientFill",
"CGColorSpaceCreateDeviceRGB failed");
506 typedef GradientFactory<Double_t, CGFloat> Factory;
507 const CFScopeGuard<CGGradientRef> gradient(Factory::CreateGradient(baseSpace.Get(), extendedColor));
508 if (!gradient.Get()) {
509 ::Error(
"DrawPolygonWithGradientFill",
"CGGradientCreateWithColorComponents failed");
514 CGPathMoveToPoint(path.Get(),
nullptr, xy[0].
fX, xy[0].
fY);
515 for (
Int_t i = 1; i < nPoints; ++i)
516 CGPathAddLineToPoint(path.Get(),
nullptr, xy[i].
fX, xy[i].
fY);
518 CGPathCloseSubpath(path.Get());
525 CGContextSetRGBFillColor(ctx, 1., 1., 1., 0.5);
526 CGContextBeginPath(ctx);
527 CGContextAddPath(ctx, path.Get());
528 CGContextSetShadow(ctx, shadowOffset, shadowBlur);
529 CGContextFillPath(ctx);
532 CGContextBeginPath(ctx);
533 CGContextAddPath(ctx, path.Get());
536 GradientParameters params;
537 if (!CalculateGradientParameters(extendedColor, sizeOfDrawable, nPoints, xy, params))
541 if (gr && (params.fStartRadius || params.fEndRadius)) {
543 CGContextDrawRadialGradient(ctx, gradient.Get(), params.fStartPoint, 0.,
544 params.fStartPoint, params.fStartRadius,
545 kCGGradientDrawsAfterEndLocation |
546 kCGGradientDrawsBeforeStartLocation);
548 CGContextDrawRadialGradient(ctx, gradient.Get(), params.fStartPoint, params.fStartRadius,
549 params.fEndPoint, params.fEndRadius,
550 kCGGradientDrawsAfterEndLocation |
551 kCGGradientDrawsBeforeStartLocation);
554 CGContextDrawLinearGradient(ctx, gradient.Get(),
555 params.fStartPoint, params.fEndPoint,
556 kCGGradientDrawsAfterEndLocation |
557 kCGGradientDrawsBeforeStartLocation);
Double_t GetRadius() const
Get radius.
Bool_t SetFillAreaParameters(CGContextRef ctx, unsigned *patternIndex)
Namespace for new ROOT classes and functions.
const Point & GetCenter() const
Get center.
const Double_t * GetColorPositions() const
Get color positions.
void swap(TDirectoryEntry &e1, TDirectoryEntry &e2) noexcept
ECoordinateMode GetCoordinateMode() const
Get coordinate mode.
Bool_t SetFillColor(CGContextRef ctx, Color_t colorIndex)
SizeType_t GetNumberOfSteps() const
Get number of steps.
Define a radial color gradient.
virtual void GetRGB(Float_t &r, Float_t &g, Float_t &b) const
bool SetFillPattern(CGContextRef ctx, const unsigned *patternIndex)
static const double x2[5]
Double_t GetR2() const
Get R2.
void DrawPattern(void *data, CGContextRef ctx)
void DrawFillArea(CGContextRef ctx, Int_t n, TPoint *xy, Bool_t drawShadow)
Bool_t SetLineColor(CGContextRef ctx, Color_t colorIndex)
void DrawPolygonWithGradientFill(CGContextRef ctx, const TColorGradient *extendedColor, const CGSize &sizeOfDrawable, Int_t nPoints, const TPoint *xy, Bool_t drawShadow)
const unsigned char gStipples[26][32]
Define a linear color gradient.
static const double x1[5]
The color creation and management class.
EGradientType GetGradientType() const
Get gradient type.
void DrawBox(CGContextRef ctx, Int_t x1, Int_t y1, Int_t x2, Int_t y2, bool hollow)
const Double_t * GetColors() const
Get colors.
TColorGradient extends basic TColor.
void Error(ErrorHandler_t func, int code, const char *va_(fmt),...)
Write error message and call a handler, if required.