31 namespace Util = MacOSX::Util;
35 const CGSize shadowOffset = CGSizeMake(10., 10.);
36 const CGFloat shadowBlur = 5.;
43 template<
class SRC,
class DST>
44 struct GradientFactory {
45 static CGGradientRef CreateGradient(CGColorSpaceRef colorSpace,
48 assert(colorSpace !=
nullptr &&
49 "GradientFactory::CreateGradient, parameter 'colorSpace' is null");
50 assert(extendedColor !=
nullptr &&
51 "GradientFactory::CreateGradient, parameter 'extendedColor' is null");
52 const SRC *compStart = extendedColor->
GetColors();
53 const SRC *compEnd = compStart + extendedColor->GetNumberOfSteps() * 4;
54 const std::vector<DST> convertedComponents(compStart, compEnd);
56 const SRC *posEnd = posStart + extendedColor->GetNumberOfSteps();
57 const std::vector<DST> convertedPositions(posStart, posEnd);
59 return CGGradientCreateWithColorComponents(colorSpace,
60 &convertedComponents[0],
61 &convertedPositions[0],
67 struct GradientFactory<DST, DST> {
68 static CGGradientRef CreateGradient(CGColorSpaceRef colorSpace,
71 assert(colorSpace !=
nullptr &&
72 "GradientFactory::CreateGradient, parameter 'colorSpace' is null");
73 assert(extendedColor !=
nullptr &&
74 "GradientFactory::CreateGradient, parameter 'extendedColor' is null");
75 const DST *comps = extendedColor->
GetColors();
77 return CGGradientCreateWithColorComponents(colorSpace, comps, pos,
82 struct GradientParameters {
98 : fStartPoint(), fEndPoint(), fStartRadius(0.), fEndRadius(0.)
102 GradientParameters(
const CGPoint &start,
const CGPoint &end)
103 : fStartPoint(start), fEndPoint(end), fStartRadius(0.), fEndRadius(0.)
108 GradientParameters(
const CGPoint &start,
const CGPoint &end,
109 CGFloat startRadius, CGFloat endRadius)
110 : fStartPoint(start), fEndPoint(end), fStartRadius(startRadius), fEndRadius(endRadius)
117 CGRect FindBoundingBox(
Int_t nPoints,
const TPoint *xy)
121 assert(nPoints > 2 &&
"FindBoundingBox, invalid number of points in a polygon");
122 assert(xy !=
nullptr &&
"FindBoundingBox, parameter 'xy' is null");
124 CGPoint bottomLeft = {};
125 bottomLeft.x = xy[0].
fX;
126 bottomLeft.y = xy[0].
fY;
128 CGPoint topRight = bottomLeft;
130 for (
Int_t i = 1; i < nPoints; ++i) {
131 bottomLeft.x =
std::min(bottomLeft.x, CGFloat(xy[i].fX));
132 bottomLeft.y =
std::min(bottomLeft.y, CGFloat(xy[i].fY));
134 topRight.x =
std::max(topRight.x, CGFloat(xy[i].fX));
135 topRight.y =
std::max(topRight.y, CGFloat(xy[i].fY));
138 return CGRectMake(bottomLeft.x, bottomLeft.y,
139 topRight.x - bottomLeft.x,
140 topRight.y - bottomLeft.y);
144 template<
class GradientType>
145 bool CalculateGradientStartEnd(
const GradientType *grad,
146 const CGSize &sizeOfDrawable,
148 GradientParameters ¶ms)
151 "CalculateGradientStartEnd, parameter 'grad' is null");
152 assert(sizeOfDrawable.width > 0. && sizeOfDrawable.height > 0. &&
153 "CalculateGradientStartEnd, invalid destination drawable size");
155 "CalculateGradientStartEnd, parameter 'n' is not a valid number of points");
156 assert(polygon !=
nullptr &&
157 "CalculateGradientStartEnd, parameter 'polygon' is null");
161 CGPoint start = CGPointMake(grad->GetStart().fX, grad->GetStart().fY);
162 CGPoint end = CGPointMake(grad->GetEnd().fX, grad->GetEnd().fY);
164 const CGRect &bbox = FindBoundingBox(n, polygon);
166 if (!bbox.size.width || !bbox.size.height)
172 start.x = bbox.size.width * start.x + bbox.origin.
x;
173 end.x = bbox.size.width * end.x + bbox.origin.
x;
175 start.y = bbox.size.height * start.y + bbox.origin.
y;
176 end.y = bbox.size.height * end.y + bbox.origin.
y;
178 start.x *= sizeOfDrawable.width;
179 start.y *= sizeOfDrawable.height;
180 end.x *= sizeOfDrawable.width;
181 end.y *= sizeOfDrawable.height;
184 params.fStartPoint = start;
185 params.fEndPoint = end;
192 const CGSize &sizeOfDrawable,
194 GradientParameters ¶ms)
196 assert(grad !=
nullptr &&
"CalculateGradientRadiuses, parameter 'grad' is null");
197 assert(sizeOfDrawable.width > 0. && sizeOfDrawable.height > 0. &&
198 "CalculateGradientRadiuses, invalid destination drawable size");
200 "CalculateGradientRadiuses, extended radial gradient expected");
201 assert(n > 2 &&
"CalculateGradientRadiuses, parameter 'n' is not a valid number of points");
202 assert(polygon !=
nullptr &&
203 "CalculateGradientRadiuses, parameter 'polygon' is null");
206 const CGRect &bbox = FindBoundingBox(n, polygon);
207 if (!bbox.size.width || !bbox.size.height)
210 CGFloat startRadius = grad->
GetR1();
211 CGFloat endRadius = grad->
GetR2();
214 const CGFloat scale =
std::max(bbox.size.width, bbox.size.height);
216 startRadius *= scale;
219 const CGFloat scale =
std::max(sizeOfDrawable.width, sizeOfDrawable.height);
221 startRadius *= scale;
225 params.fStartRadius = startRadius;
226 params.fEndRadius = endRadius;
232 bool CalculateSimpleRadialGradientParameters(
const TRadialGradient *grad,
233 const CGSize &sizeOfDrawable,
235 GradientParameters ¶ms)
238 "CalculateSimpleRadialGradientParameters, parameter 'grad' is null");
240 "CalculateSimpleRadialGradientParameters, invalid gradient type");
241 assert(sizeOfDrawable.width > 0. && sizeOfDrawable.height > 0. &&
242 "CCalculateSimpleRadialGradientParameters, invalid destination drawable size");
244 "CalculateSimpleRadialGradientParameters, parameter 'n' is not a valid number of points");
245 assert(polygon !=
nullptr &&
246 "CalculateSimpleRadialGradientParameters, parameter 'polygon' is null");
249 const CGRect &bbox = FindBoundingBox(n, polygon);
250 if (!bbox.size.width || !bbox.size.height)
258 radius *=
std::max(bbox.size.width, bbox.size.height);
259 center.x = bbox.size.width * center.x + bbox.origin.
x;
260 center.y = bbox.size.height * center.y + bbox.origin.
y;
262 radius *=
std::max(sizeOfDrawable.width, sizeOfDrawable.height);
263 center.x *= sizeOfDrawable.width;
264 center.y *= sizeOfDrawable.height;
267 params.fStartPoint = center;
268 params.fStartRadius = radius;
274 bool CalculateGradientParameters(
const TColorGradient *extendedColor,
275 const CGSize &sizeOfDrawable,
277 GradientParameters ¶ms)
279 assert(extendedColor !=
nullptr &&
280 "CalculateGradientParameters, parameter 'extendedColor' is null");
281 assert(sizeOfDrawable.width > 0. && sizeOfDrawable.height > 0. &&
282 "CalculateGradientParameters, invalid destination drawable size");
283 assert(n > 2 &&
"CalculateGradientParameters, parameter 'n' is not a valid number of points");
284 assert(polygon !=
nullptr &&
285 "CalculateGradientParameters, parameter 'polygon' is null");
287 if (
const TLinearGradient *
const gl = dynamic_cast<const TLinearGradient *>(extendedColor))
288 return CalculateGradientStartEnd(gl, sizeOfDrawable, n, polygon, params);
289 else if (
const TRadialGradient *
const gr = dynamic_cast<const TRadialGradient *>(extendedColor)) {
291 return CalculateSimpleRadialGradientParameters(
gr, sizeOfDrawable, n, polygon, params);
293 if (CalculateGradientStartEnd(
gr, sizeOfDrawable, n, polygon, params))
294 return CalculateGradientRadiuses(
gr, sizeOfDrawable, n, polygon, params);
299 assert(0 &&
"CalculateGradientParamters, unknown gradient type");
309 assert(ctx !=
nullptr &&
"SetFillColor, ctx parameter is null");
320 const CGFloat alpha = color->
GetAlpha();
323 color->
GetRGB(rgb[0], rgb[1], rgb[2]);
324 CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], alpha);
332 assert(data !=
nullptr &&
"DrawPattern, data parameter is null");
333 assert(ctx !=
nullptr &&
"DrawPattern, ctx parameter is null");
336 const unsigned stencilIndex = *
static_cast<unsigned *
>(data);
338 for (
int i = 30,
y = 0; i >= 0; i -= 2, ++
y) {
340 for (
int j = 0; j < 8; ++j, ++
x) {
341 if (
gStipples[stencilIndex][i] & (1 << j))
342 CGContextFillRect(ctx, CGRectMake(x,
y, 1, 1));
345 for (
int j = 0; j < 8; ++j, ++
x) {
346 if (
gStipples[stencilIndex][i + 1] & (1 << j))
347 CGContextFillRect(ctx, CGRectMake(x,
y, 1, 1));
355 assert(ctx !=
nullptr &&
"SetFillPattern, ctx parameter is null");
356 assert(patternIndex !=
nullptr &&
"SetFillPattern, patternIndex parameter is null");
369 if (!baseSpace.
Get())
373 if (!patternSpace.
Get())
376 CGContextSetFillColorSpace(ctx, patternSpace.
Get());
378 CGPatternCallbacks callbacks = {0, &
DrawPattern, 0};
380 CGRectMake(0, 0, 16, 16),
381 CGAffineTransformIdentity, 16, 16,
382 kCGPatternTilingConstantSpacing,
388 CGContextSetFillPattern(ctx, pattern.
Get(), rgba);
396 assert(ctx !=
nullptr &&
"SetFillAreaParameters, ctx parameter is null");
398 const unsigned fillStyle =
gVirtualX->GetFillStyle() / 1000;
401 if (fillStyle == 2 || (fillStyle != 1 && fillStyle != 3)) {
403 ::Error(
"SetFillAreaParameters",
"Line color for index %d was not found",
int(
gVirtualX->GetLineColor()));
406 }
else if (fillStyle == 1) {
409 ::Error(
"SetFillAreaParameters",
"Fill color for index %d was not found",
int(
gVirtualX->GetFillColor()));
413 assert(patternIndex !=
nullptr &&
"SetFillAreaParameters, pattern index in null");
415 *patternIndex =
gVirtualX->GetFillStyle() % 1000;
417 if (*patternIndex > 25)
421 ::Error(
"SetFillAreaParameters",
"SetFillPattern failed");
440 CGContextStrokeRect(ctx, CGRectMake(x1, y1, x2 - x1, y2 - y1));
442 CGContextFillRect(ctx, CGRectMake(x1, y1, x2 - x1, y2 - y1));
452 assert(ctx !=
nullptr &&
"DrawFillArea, ctx parameter is null");
453 assert(xy !=
nullptr &&
"DrawFillArea, xy parameter is null");
455 CGContextBeginPath(ctx);
457 CGContextMoveToPoint(ctx, xy[0].fX, xy[0].fY);
458 for (
Int_t i = 1; i <
n; ++i)
459 CGContextAddLineToPoint(ctx, xy[i].fX, xy[i].fY);
461 CGContextClosePath(ctx);
463 const unsigned fillStyle =
gVirtualX->GetFillStyle() / 1000;
466 if (fillStyle == 2 || (fillStyle != 1 && fillStyle != 3)) {
467 CGContextStrokePath(ctx);
468 }
else if (fillStyle == 1) {
470 CGContextSetShadow(ctx, shadowOffset, shadowBlur);
472 CGContextFillPath(ctx);
475 CGContextSetShadow(ctx, shadowOffset, shadowBlur);
477 CGContextFillPath(ctx);
487 assert(ctx !=
nullptr &&
"DrawPolygonWithGradientFill, ctx parameter is null");
488 assert(nPoints != 0 &&
"DrawPolygonWithGradientFill, nPoints parameter is 0");
489 assert(xy !=
nullptr &&
"DrawPolygonWithGradientFill, xy parameter is null");
490 assert(extendedColor !=
nullptr &&
491 "DrawPolygonWithGradientFill, extendedColor parameter is null");
493 if (!sizeOfDrawable.width || !sizeOfDrawable.height)
496 const CFScopeGuard<CGMutablePathRef> path(CGPathCreateMutable());
498 ::Error(
"DrawPolygonWithGradientFill",
"CGPathCreateMutable failed");
504 const CFScopeGuard<CGColorSpaceRef> baseSpace(CGColorSpaceCreateDeviceRGB());
505 if (!baseSpace.Get()) {
506 ::Error(
"DrawPolygonWithGradientFill",
"CGColorSpaceCreateDeviceRGB failed");
510 typedef GradientFactory<Double_t, CGFloat> Factory;
511 const CFScopeGuard<CGGradientRef> gradient(Factory::CreateGradient(baseSpace.Get(), extendedColor));
512 if (!gradient.Get()) {
513 ::Error(
"DrawPolygonWithGradientFill",
"CGGradientCreateWithColorComponents failed");
518 CGPathMoveToPoint(path.Get(),
nullptr, xy[0].
fX, xy[0].
fY);
519 for (
Int_t i = 1; i < nPoints; ++i)
520 CGPathAddLineToPoint(path.Get(),
nullptr, xy[i].
fX, xy[i].
fY);
522 CGPathCloseSubpath(path.Get());
529 CGContextSetRGBFillColor(ctx, 1., 1., 1., 0.5);
530 CGContextBeginPath(ctx);
531 CGContextAddPath(ctx, path.Get());
532 CGContextSetShadow(ctx, shadowOffset, shadowBlur);
533 CGContextFillPath(ctx);
536 CGContextBeginPath(ctx);
537 CGContextAddPath(ctx, path.Get());
540 GradientParameters params;
541 if (!CalculateGradientParameters(extendedColor, sizeOfDrawable, nPoints, xy, params))
545 if (gr && (params.fStartRadius || params.fEndRadius)) {
547 CGContextDrawRadialGradient(ctx, gradient.Get(), params.fStartPoint, 0.,
548 params.fStartPoint, params.fStartRadius,
549 kCGGradientDrawsAfterEndLocation |
550 kCGGradientDrawsBeforeStartLocation);
552 CGContextDrawRadialGradient(ctx, gradient.Get(), params.fStartPoint, params.fStartRadius,
553 params.fEndPoint, params.fEndRadius,
554 kCGGradientDrawsAfterEndLocation |
555 kCGGradientDrawsBeforeStartLocation);
558 CGContextDrawLinearGradient(ctx, gradient.Get(),
559 params.fStartPoint, params.fEndPoint,
560 kCGGradientDrawsAfterEndLocation |
561 kCGGradientDrawsBeforeStartLocation);
static Vc_ALWAYS_INLINE int_v min(const int_v &x, const int_v &y)
Bool_t SetFillAreaParameters(CGContextRef ctx, unsigned *patternIndex)
Namespace for new ROOT classes and functions.
ECoordinateMode GetCoordinateMode() const
Get coordinate mode.
void swap(ROOT::THist< DIMENSIONS, PRECISION > &a, ROOT::THist< DIMENSIONS, PRECISION > &b) noexcept
Swap two histograms.
const Point & GetCenter() const
Get center.
Define a radial color gradient.
bool SetFillPattern(CGContextRef ctx, const unsigned *patternIndex)
Double_t GetR2() const
Get R2.
static const double x2[5]
void DrawPattern(void *data, CGContextRef ctx)
Double_t GetRadius() const
Get radius.
void DrawFillArea(CGContextRef ctx, Int_t n, TPoint *xy, Bool_t drawShadow)
SizeType_t GetNumberOfSteps() const
Get number of steps.
virtual void GetRGB(Float_t &r, Float_t &g, Float_t &b) const
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.
EGradientType GetGradientType() const
Get gradient type.
const Double_t * GetColors() const
Get colors.
static const double x1[5]
The color creation and management class.
static Vc_ALWAYS_INLINE int_v max(const int_v &x, const int_v &y)
const Double_t * GetColorPositions() const
Get color positions.
void DrawBox(CGContextRef ctx, Int_t x1, Int_t y1, Int_t x2, Int_t y2, bool hollow)
TColorGradient extends basic TColor.
void Error(ErrorHandler_t func, int code, const char *va_(fmt),...)
Write error message and call a handler, if required.