1/*
2 * gdiplusbrush.h
3 *
4 * GDI+ brush classes
5 *
6 * This file is part of the w32api package.
7 *
8 * Contributors:
9 *   Created by Markus Koenig <markus@stber-koenig.de>
10 *
11 * THIS SOFTWARE IS NOT COPYRIGHTED
12 *
13 * This source code is offered for use in the public domain. You may
14 * use, modify or distribute it freely.
15 *
16 * This code is distributed in the hope that it will be useful but
17 * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
18 * DISCLAIMED. This includes but is not limited to warranties of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 */
22
23#ifndef __GDIPLUS_BRUSH_H
24#define __GDIPLUS_BRUSH_H
25#if __GNUC__ >=3
26#pragma GCC system_header
27#endif
28
29#ifndef __cplusplus
30#error "A C++ compiler is required to include gdiplusbrush.h."
31#endif
32
33class Brush: public GdiplusBase
34{
35	friend class HatchBrush;
36	friend class LinearGradientBrush;
37	friend class PathGradientBrush;
38	friend class SolidBrush;
39	friend class TextureBrush;
40	friend class Graphics;
41	friend class Pen;
42
43public:
44	virtual ~Brush()
45	{
46		DllExports::GdipDeleteBrush(nativeBrush);
47	}
48	virtual Brush* Clone() const  // each subclass must implement this
49	{
50		lastStatus = NotImplemented;
51		return NULL;
52	}
53
54	Status GetLastStatus() const
55	{
56		Status result = lastStatus;
57		lastStatus = Ok;
58		return result;
59	}
60	BrushType GetType() const
61	{
62		BrushType result = BrushTypeSolidColor;
63		updateStatus(DllExports::GdipGetBrushType(nativeBrush, &result));
64		return result;
65	}
66
67private:
68	Brush(): nativeBrush(NULL), lastStatus(Ok) {}
69	Brush(GpBrush *brush, Status status):
70		nativeBrush(brush), lastStatus(status) {}
71	Brush(const Brush& brush);
72	Brush& operator=(const Brush&);
73
74	Status updateStatus(Status newStatus) const
75	{
76		if (newStatus != Ok) lastStatus = newStatus;
77		return newStatus;
78	}
79
80	GpBrush *nativeBrush;
81	mutable Status lastStatus;
82};
83
84class HatchBrush: public Brush
85{
86public:
87	HatchBrush(HatchStyle hatchStyle,
88			const Color& foreColor,
89			const Color& backColor = Color())
90	{
91		GpHatch *nativeHatch = NULL;
92		lastStatus = DllExports::GdipCreateHatchBrush(hatchStyle,
93				foreColor.GetValue(), backColor.GetValue(),
94				&nativeHatch);
95		nativeBrush = nativeHatch;
96	}
97	virtual HatchBrush* Clone() const
98	{
99		GpBrush *cloneBrush = NULL;
100		Status status = updateStatus(DllExports::GdipCloneBrush(
101				nativeBrush, &cloneBrush));
102		if (status == Ok) {
103			HatchBrush *result =
104				new HatchBrush(cloneBrush, lastStatus);
105			if (!result) {
106				DllExports::GdipDeleteBrush(cloneBrush);
107				updateStatus(OutOfMemory);
108			}
109			return result;
110		} else {
111			return NULL;
112		}
113	}
114
115	Status GetBackgroundColor(Color *color) const
116	{
117		return updateStatus(DllExports::GdipGetHatchBackgroundColor(
118				(GpHatch*) nativeBrush,
119				color ? &color->Value : NULL));
120	}
121	Status GetForegroundColor(Color *color) const
122	{
123		return updateStatus(DllExports::GdipGetHatchForegroundColor(
124				(GpHatch*) nativeBrush,
125				color ? &color->Value : NULL));
126	}
127	HatchStyle GetHatchStyle() const
128	{
129		HatchStyle result;
130		updateStatus(DllExports::GdipGetHatchStyle(
131				(GpHatch*) nativeBrush, &result));
132		return result;
133	}
134
135private:
136	HatchBrush(GpBrush *brush, Status status): Brush(brush, status) {}
137	HatchBrush(const HatchBrush& brush);
138	HatchBrush& operator=(const HatchBrush&);
139};
140
141class LinearGradientBrush: public Brush
142{
143public:
144	LinearGradientBrush(const PointF& point1, const PointF& point2,
145			const Color& color1, const Color& color2)
146	{
147		GpLineGradient *nativeLineGradient = NULL;
148		lastStatus = DllExports::GdipCreateLineBrush(
149				&point1, &point2,
150				color1.GetValue(), color2.GetValue(),
151				WrapModeTile, &nativeLineGradient);
152		nativeBrush = nativeLineGradient;
153	}
154	LinearGradientBrush(const Point& point1, const Point& point2,
155			const Color& color1, const Color& color2)
156	{
157		GpLineGradient *nativeLineGradient = NULL;
158		lastStatus = DllExports::GdipCreateLineBrushI(
159				&point1, &point2,
160				color1.GetValue(), color2.GetValue(),
161				WrapModeTile, &nativeLineGradient);
162		nativeBrush = nativeLineGradient;
163	}
164	LinearGradientBrush(const RectF& rect, const Color& color1,
165			const Color& color2, LinearGradientMode mode)
166	{
167		GpLineGradient *nativeLineGradient = NULL;
168		lastStatus = DllExports::GdipCreateLineBrushFromRect(
169				&rect, color1.GetValue(), color2.GetValue(),
170				mode, WrapModeTile, &nativeLineGradient);
171		nativeBrush = nativeLineGradient;
172	}
173	LinearGradientBrush(const Rect& rect, const Color& color1,
174			const Color& color2, LinearGradientMode mode)
175	{
176		GpLineGradient *nativeLineGradient = NULL;
177		lastStatus = DllExports::GdipCreateLineBrushFromRectI(
178				&rect, color1.GetValue(), color2.GetValue(),
179				mode, WrapModeTile, &nativeLineGradient);
180		nativeBrush = nativeLineGradient;
181	}
182	LinearGradientBrush(const RectF& rect, const Color& color1,
183			const Color& color2, REAL angle,
184			BOOL isAngleScalable = FALSE)
185	{
186		GpLineGradient *nativeLineGradient = NULL;
187		lastStatus = DllExports::GdipCreateLineBrushFromRectWithAngle(
188				&rect, color1.GetValue(), color2.GetValue(),
189				angle, isAngleScalable, WrapModeTile,
190				&nativeLineGradient);
191		nativeBrush = nativeLineGradient;
192	}
193	LinearGradientBrush(const Rect& rect, const Color& color1,
194			const Color& color2, REAL angle,
195			BOOL isAngleScalable = FALSE)
196	{
197		GpLineGradient *nativeLineGradient = NULL;
198		lastStatus = DllExports::GdipCreateLineBrushFromRectWithAngleI(
199				&rect, color1.GetValue(), color2.GetValue(),
200				angle, isAngleScalable, WrapModeTile,
201				&nativeLineGradient);
202		nativeBrush = nativeLineGradient;
203	}
204	virtual LinearGradientBrush* Clone() const
205	{
206		GpBrush *cloneBrush = NULL;
207		Status status = updateStatus(DllExports::GdipCloneBrush(
208				nativeBrush, &cloneBrush));
209		if (status == Ok) {
210			LinearGradientBrush *result =
211				new LinearGradientBrush(cloneBrush, lastStatus);
212			if (!result) {
213				DllExports::GdipDeleteBrush(cloneBrush);
214				updateStatus(OutOfMemory);
215			}
216			return result;
217		} else {
218			return NULL;
219		}
220	}
221
222	Status GetBlend(REAL *blendFactors, REAL *blendPositions,
223			INT count) const
224	{
225		return updateStatus(DllExports::GdipGetLineBlend(
226				(GpLineGradient*) nativeBrush,
227				blendFactors, blendPositions, count));
228	}
229	INT GetBlendCount() const
230	{
231		INT result = 0;
232		updateStatus(DllExports::GdipGetLineBlendCount(
233				(GpLineGradient*) nativeBrush, &result));
234		return result;
235	}
236	BOOL GetGammaCorrection() const
237	{
238		BOOL result = FALSE;
239		updateStatus(DllExports::GdipGetLineGammaCorrection(
240				(GpLineGradient*) nativeBrush, &result));
241		return result;
242	}
243	INT GetInterpolationColorCount() const
244	{
245		INT result = 0;
246		updateStatus(DllExports::GdipGetLinePresetBlendCount(
247				(GpLineGradient*) nativeBrush, &result));
248		return result;
249	}
250	Status GetInterpolationColors(Color *presetColors,
251			REAL *blendPositions, INT count) const
252	{
253		if (!presetColors || count <= 0)
254			return lastStatus = InvalidParameter;
255
256		ARGB *presetArgb =
257			(ARGB*) DllExports::GdipAlloc(count * sizeof(ARGB));
258		if (!presetArgb)
259			return lastStatus = OutOfMemory;
260
261		Status status = updateStatus(DllExports::GdipGetLinePresetBlend(
262				(GpLineGradient*) nativeBrush, presetArgb,
263				blendPositions, count));
264		for (INT i = 0; i < count; ++i) {
265			presetColors[i].SetValue(presetArgb[i]);
266		}
267		DllExports::GdipFree((void*) presetArgb);
268		return status;
269	}
270	Status GetLinearColors(Color *colors) const
271	{
272		if (!colors) return lastStatus = InvalidParameter;
273
274		ARGB colorsArgb[2];
275		Status status = updateStatus(DllExports::GdipGetLineColors(
276				(GpLineGradient*) nativeBrush, colorsArgb));
277		colors[0].SetValue(colorsArgb[0]);
278		colors[1].SetValue(colorsArgb[1]);
279		return status;
280	}
281	Status GetRectangle(RectF *rect) const
282	{
283		return updateStatus(DllExports::GdipGetLineRect(
284				(GpLineGradient*) nativeBrush, rect));
285	}
286	Status GetRectangle(Rect *rect) const
287	{
288		return updateStatus(DllExports::GdipGetLineRectI(
289				(GpLineGradient*) nativeBrush, rect));
290	}
291	Status GetTransform(Matrix *matrix) const
292	{
293		return updateStatus(DllExports::GdipGetLineTransform(
294				(GpLineGradient*) nativeBrush,
295				matrix ? matrix->nativeMatrix : NULL));
296	}
297	WrapMode GetWrapMode() const
298	{
299		WrapMode wrapMode = WrapModeTile;
300		updateStatus(DllExports::GdipGetLineWrapMode(
301				(GpLineGradient*) nativeBrush, &wrapMode));
302		return wrapMode;
303	}
304	Status MultiplyTransform(const Matrix *matrix,
305			MatrixOrder order = MatrixOrderPrepend)
306	{
307		return updateStatus(DllExports::GdipMultiplyLineTransform(
308				(GpLineGradient*) nativeBrush,
309				matrix ? matrix->nativeMatrix : NULL, order));
310	}
311	Status ResetTransform()
312	{
313		return updateStatus(DllExports::GdipResetLineTransform(
314				(GpLineGradient*) nativeBrush));
315	}
316	Status RotateTranform(REAL angle, MatrixOrder order = MatrixOrderPrepend)
317	{
318		return updateStatus(DllExports::GdipRotateLineTransform(
319				(GpLineGradient*) nativeBrush, angle, order));
320	}
321	Status ScaleTransform(REAL sx, REAL sy,
322			MatrixOrder order = MatrixOrderPrepend)
323	{
324		return updateStatus(DllExports::GdipScaleLineTransform(
325				(GpLineGradient*) nativeBrush, sx, sy, order));
326	}
327	Status SetBlend(const REAL *blendFactors,
328			const REAL *blendPositions, INT count)
329	{
330		return updateStatus(DllExports::GdipSetLineBlend(
331				(GpLineGradient*) nativeBrush,
332				blendFactors, blendPositions, count));
333	}
334	Status SetBlendBellShape(REAL focus, REAL scale = 1.0f)
335	{
336		return updateStatus(DllExports::GdipSetLineSigmaBlend(
337				(GpLineGradient*) nativeBrush,
338				focus, scale));
339	}
340	Status SetBlendTriangularShape(REAL focus, REAL scale = 1.0f)
341	{
342		return updateStatus(DllExports::GdipSetLineLinearBlend(
343				(GpLineGradient*) nativeBrush,
344				focus, scale));
345	}
346	Status SetGammaCorrection(BOOL useGammaCorrection)
347	{
348		return updateStatus(DllExports::GdipSetLineGammaCorrection(
349				(GpLineGradient*) nativeBrush,
350				useGammaCorrection));
351	}
352	Status SetInterpolationColors(const Color *presetColors,
353			const REAL *blendPositions, INT count)
354	{
355		if (!presetColors || count < 0)
356			return lastStatus = InvalidParameter;
357
358		ARGB *presetArgb =
359			(ARGB*) DllExports::GdipAlloc(count * sizeof(ARGB));
360		if (!presetArgb)
361			return lastStatus = OutOfMemory;
362		for (INT i = 0; i < count; ++i) {
363			presetArgb[i] = presetColors[i].GetValue();
364		}
365
366		Status status = updateStatus(DllExports::GdipSetLinePresetBlend(
367				(GpLineGradient*) nativeBrush,
368				presetArgb, blendPositions, count));
369		DllExports::GdipFree((void*) presetArgb);
370		return status;
371	}
372	Status SetLinearColors(const Color& color1, const Color& color2)
373	{
374		return updateStatus(DllExports::GdipSetLineColors(
375				(GpLineGradient*) nativeBrush,
376				color1.GetValue(), color2.GetValue()));
377	}
378	Status SetTransform(const Matrix *matrix)
379	{
380		return updateStatus(DllExports::GdipSetLineTransform(
381				(GpLineGradient*) nativeBrush,
382				matrix ? matrix->nativeMatrix : NULL));
383	}
384	Status SetWrapMode(WrapMode wrapMode)
385	{
386		return updateStatus(DllExports::GdipSetLineWrapMode(
387				(GpLineGradient*) nativeBrush, wrapMode));
388	}
389	Status TranslateTransform(REAL dx, REAL dy,
390			MatrixOrder order = MatrixOrderPrepend)
391	{
392		return updateStatus(DllExports::GdipTranslateLineTransform(
393				(GpLineGradient*) nativeBrush, dx, dy, order));
394	}
395
396private:
397	LinearGradientBrush(GpBrush *brush, Status status): Brush(brush, status) {}
398	LinearGradientBrush(const LinearGradientBrush& brush);
399	LinearGradientBrush& operator=(const LinearGradientBrush&);
400};
401
402class SolidBrush: public Brush
403{
404public:
405	SolidBrush(const Color& color)
406	{
407		GpSolidFill *nativeSolidFill = NULL;
408		lastStatus = DllExports::GdipCreateSolidFill(
409				color.GetValue(), &nativeSolidFill);
410		nativeBrush = nativeSolidFill;
411	}
412	virtual SolidBrush* Clone() const
413	{
414		GpBrush *cloneBrush = NULL;
415		Status status = updateStatus(DllExports::GdipCloneBrush(
416				nativeBrush, &cloneBrush));
417		if (status == Ok) {
418			SolidBrush *result =
419				new SolidBrush(cloneBrush, lastStatus);
420			if (!result) {
421				DllExports::GdipDeleteBrush(cloneBrush);
422				updateStatus(OutOfMemory);
423			}
424			return result;
425		} else {
426			return NULL;
427		}
428	}
429
430	Status GetColor(Color *color) const
431	{
432		return updateStatus(DllExports::GdipGetSolidFillColor(
433				(GpSolidFill*) nativeBrush,
434				color ? &color->Value : NULL));
435	}
436	Status SetColor(const Color& color)
437	{
438		return updateStatus(DllExports::GdipSetSolidFillColor(
439				(GpSolidFill*) nativeBrush, color.GetValue()));
440	}
441
442private:
443	SolidBrush(GpBrush *brush, Status status): Brush(brush, status) {}
444	SolidBrush(const SolidBrush&);
445	SolidBrush& operator=(const SolidBrush&);
446};
447
448class TextureBrush: public Brush
449{
450public:
451	TextureBrush(Image *image, WrapMode wrapMode = WrapModeTile)
452	{
453		GpTexture *nativeTexture = NULL;
454		lastStatus = DllExports::GdipCreateTexture(
455				image ? image->nativeImage : NULL,
456				wrapMode, &nativeTexture);
457		nativeBrush = nativeTexture;
458	}
459	TextureBrush(Image *image, WrapMode wrapMode,
460			REAL dstX, REAL dstY, REAL dstWidth, REAL dstHeight)
461	{
462		GpTexture *nativeTexture = NULL;
463		lastStatus = DllExports::GdipCreateTexture2(
464				image ? image->nativeImage : NULL,
465				wrapMode, dstX, dstY, dstWidth, dstHeight,
466				&nativeTexture);
467		nativeBrush = nativeTexture;
468	}
469	TextureBrush(Image *image, WrapMode wrapMode,
470			INT dstX, INT dstY, INT dstWidth, INT dstHeight)
471	{
472		GpTexture *nativeTexture = NULL;
473		lastStatus = DllExports::GdipCreateTexture2I(
474				image ? image->nativeImage : NULL,
475				wrapMode, dstX, dstY, dstWidth, dstHeight,
476				&nativeTexture);
477		nativeBrush = nativeTexture;
478	}
479	TextureBrush(Image *image, WrapMode wrapMode, const RectF& dstRect)
480	{
481		GpTexture *nativeTexture = NULL;
482		lastStatus = DllExports::GdipCreateTexture2(
483				image ? image->nativeImage : NULL, wrapMode,
484				dstRect.X, dstRect.Y,
485				dstRect.Width, dstRect.Height, &nativeTexture);
486		nativeBrush = nativeTexture;
487	}
488	TextureBrush(Image *image, WrapMode wrapMode, const Rect& dstRect)
489	{
490		GpTexture *nativeTexture = NULL;
491		lastStatus = DllExports::GdipCreateTexture2I(
492				image ? image->nativeImage : NULL, wrapMode,
493				dstRect.X, dstRect.Y,
494				dstRect.Width, dstRect.Height, &nativeTexture);
495		nativeBrush = nativeTexture;
496	}
497	TextureBrush(Image *image, const RectF& dstRect,
498			ImageAttributes *imageAttributes = NULL)
499	{
500		GpTexture *nativeTexture = NULL;
501		lastStatus = DllExports::GdipCreateTextureIA(
502				image ? image->nativeImage : NULL,
503				imageAttributes ? imageAttributes->nativeImageAttributes : NULL,
504				dstRect.X, dstRect.Y,
505				dstRect.Width, dstRect.Height, &nativeTexture);
506		nativeBrush = nativeTexture;
507	}
508	TextureBrush(Image *image, const Rect& dstRect,
509			ImageAttributes *imageAttributes = NULL)
510	{
511		GpTexture *nativeTexture = NULL;
512		lastStatus = DllExports::GdipCreateTextureIAI(
513				image ? image->nativeImage : NULL,
514				imageAttributes ? imageAttributes->nativeImageAttributes : NULL,
515				dstRect.X, dstRect.Y,
516				dstRect.Width, dstRect.Height, &nativeTexture);
517		nativeBrush = nativeTexture;
518	}
519	virtual TextureBrush* Clone() const
520	{
521		GpBrush *cloneBrush = NULL;
522		Status status = updateStatus(DllExports::GdipCloneBrush(
523				nativeBrush, &cloneBrush));
524		if (status == Ok) {
525			TextureBrush *result =
526				new TextureBrush(cloneBrush, lastStatus);
527			if (!result) {
528				DllExports::GdipDeleteBrush(cloneBrush);
529				updateStatus(OutOfMemory);
530			}
531			return result;
532		} else {
533			return NULL;
534		}
535	}
536
537	//TODO: implement TextureBrush::GetImage()
538	//Image *GetImage() const
539	//{
540	//	// where is the Image allocated (static,member,new,other)?
541	//	// GdipGetTextureImage just returns a GpImage*
542	//	updateStatus(NotImplemented);
543	//	return NULL;
544	//}
545	Status GetTransfrom(Matrix *matrix) const
546	{
547		return updateStatus(DllExports::GdipGetTextureTransform(
548				(GpTexture*) nativeBrush,
549				matrix ? matrix->nativeMatrix : NULL));
550	}
551	WrapMode GetWrapMode() const
552	{
553		WrapMode result = WrapModeTile;
554		updateStatus(DllExports::GdipGetTextureWrapMode(
555				(GpTexture*) nativeBrush, &result));
556		return result;
557	}
558	Status MultiplyTransform(const Matrix *matrix,
559			MatrixOrder order = MatrixOrderPrepend)
560	{
561		return updateStatus(DllExports::GdipMultiplyTextureTransform(
562				(GpTexture*) nativeBrush,
563				matrix ? matrix->nativeMatrix : NULL, order));
564	}
565	Status ResetTransform()
566	{
567		return updateStatus(DllExports::GdipResetTextureTransform(
568				(GpTexture*) nativeBrush));
569	}
570	Status RotateTransform(REAL angle,
571			MatrixOrder order = MatrixOrderPrepend)
572	{
573		return updateStatus(DllExports::GdipRotateTextureTransform(
574				(GpTexture*) nativeBrush, angle, order));
575	}
576	Status ScaleTransform(REAL sx, REAL sy,
577			MatrixOrder order = MatrixOrderPrepend)
578	{
579		return updateStatus(DllExports::GdipScaleTextureTransform(
580				(GpTexture*) nativeBrush, sx, sy, order));
581	}
582	Status SetTransform(const Matrix *matrix)
583	{
584		return updateStatus(DllExports::GdipSetTextureTransform(
585				(GpTexture*) nativeBrush,
586				matrix ? matrix->nativeMatrix : NULL));
587	}
588	Status SetWrapMode(WrapMode wrapMode)
589	{
590		return updateStatus(DllExports::GdipSetTextureWrapMode(
591				(GpTexture*) nativeBrush, wrapMode));
592	}
593	Status TranslateTransform(REAL dx, REAL dy,
594			MatrixOrder order = MatrixOrderPrepend)
595	{
596		return updateStatus(DllExports::GdipTranslateTextureTransform(
597				(GpTexture*) nativeBrush, dx, dy, order));
598	}
599
600private:
601	TextureBrush(GpBrush *brush, Status status): Brush(brush, status) {}
602	TextureBrush(const TextureBrush&);
603	TextureBrush& operator=(const TextureBrush&);
604};
605
606#endif /* __GDIPLUS_BRUSH_H */
607