Mercurial > projects > dynamin
annotate dynamin/painting/graphics.d @ 16:dcaa95190f4b
Add roundedRectangle() method to Graphics.
author | Jordan Miner <jminer7@gmail.com> |
---|---|
date | Sat, 18 Jul 2009 21:28:47 -0500 |
parents | aa4efef0f0b1 |
children | 73060bc3f004 |
rev | line source |
---|---|
0 | 1 // Written in the D programming language |
2 // www.digitalmars.com/d/ | |
3 | |
4 /* | |
5 * The contents of this file are subject to the Mozilla Public License Version | |
6 * 1.1 (the "License"); you may not use this file except in compliance with | |
7 * the License. You may obtain a copy of the License at | |
8 * http://www.mozilla.org/MPL/ | |
9 * | |
10 * Software distributed under the License is distributed on an "AS IS" basis, | |
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |
12 * for the specific language governing rights and limitations under the | |
13 * License. | |
14 * | |
15 * The Original Code is the Dynamin library. | |
16 * | |
17 * The Initial Developer of the Original Code is Jordan Miner. | |
18 * Portions created by the Initial Developer are Copyright (C) 2006-2009 | |
19 * the Initial Developer. All Rights Reserved. | |
20 * | |
21 * Contributor(s): | |
22 * Jordan Miner <jminer7@gmail.com> | |
23 * | |
24 */ | |
25 | |
26 module dynamin.painting.graphics; | |
27 | |
28 import dynamin.c.cairo; | |
29 import dynamin.core.string; | |
30 import dynamin.core.math; | |
31 import dynamin.core.file; | |
32 import dynamin.painting.coordinates; | |
33 import dynamin.painting.color; | |
34 import tango.io.Stdout; | |
35 | |
36 /// | |
37 class Font { | |
38 private: | |
39 string _family; | |
40 int _style = 0; | |
41 int _size; | |
42 public: | |
43 this(string family_ = "", int size = 10, bool b = false, bool i = false, bool u = false) { | |
44 this.family = family_; | |
45 this.size = size; | |
46 bold = b; | |
47 italic = i; | |
48 underline = u; | |
49 } | |
50 /** | |
51 * Gets or sets the family name of this font. Common font family names on | |
52 * Windows are "Arial", "Times New Roman", and "Tahoma". | |
53 */ | |
54 string family() { return _family; } | |
55 /// ditto | |
56 void family(string str) { _family = str; } | |
57 /// | |
58 int style() { return _style; } | |
59 /// ditto | |
60 void style(int s) { _style = s; } | |
61 /// Gets or sets whether this font is bold. | |
62 bool bold() { return cast(bool)(_style & 1); } | |
63 /// ditto | |
64 void bold(bool b) { b ? (_style |= 1) : (_style &= ~1); } | |
65 /// Gets or sets whether this font is italic. | |
66 bool italic() { return cast(bool)(_style & 2); } | |
67 /// ditto | |
68 void italic(bool b) { b ? (_style |= 2) : (_style &= ~2); } | |
69 /// Gets or sets whether this font is underline. | |
70 bool underline() { return cast(bool)(_style & 4); } | |
71 /// ditto | |
72 void underline(bool b) { b ? (_style |= 4) : (_style &= ~4); } | |
73 /// Gets or sets whether this font is strikethrough. | |
74 bool strikethrough() { return cast(bool)(_style & 8); } | |
75 /// ditto | |
76 void strikethrough(bool b) { b ? (_style |= 8) : (_style &= ~8); } | |
77 /** | |
78 * Gets or sets the size of this font in user space units, not in points. | |
79 * This size is the ascent plus the descent, not including the leading. | |
80 */ | |
81 int size() { return _size; } | |
82 /// ditto | |
83 void size(int s) { _size = s; } | |
84 } | |
85 | |
86 /// | |
87 struct FontExtents { | |
88 /// | |
89 real ascent; | |
90 /// | |
91 real descent; | |
92 /// | |
93 real leading() { return height - ascent - descent; } | |
94 /// | |
95 real height; | |
96 /// | |
97 real maxAdvance; | |
98 } | |
99 | |
100 //import lodepng = dynamin.lodepng.decode; | |
101 /// An RGBA 32-bit-per-pixel image. | |
102 class Image { | |
103 Color* _data; | |
104 uint _width, _height; | |
105 Color* data() { return _data; } | |
106 uint width() { return _width; } | |
107 uint height() { return _height; } | |
108 protected this() { | |
109 } | |
110 Color* opIndex(int x, int y) { | |
111 return _data + x+y*_width; | |
112 } | |
113 static Image load(string file) { | |
114 static if(false) { | |
115 auto img = new Image; | |
116 lodepng.PngInfo info; | |
117 img._data = cast(Color*)lodepng.decode32(readFileBytes(file), info); | |
118 img._width = info.image.width; | |
119 img._height = info.image.height; | |
120 | |
121 ubyte r; | |
122 for(uint i = 0; i < img.width * img.height; ++i) { | |
123 // lodepng returns data as ABGR instead of the ARGB that cairo, | |
124 // Windows, and I think X use. | |
125 r = img.data[i].R; | |
126 img.data[i].R = img.data[i].B; | |
127 img.data[i].B = r; | |
128 // cairo, Windows, and I think X use pre-multiplied alpha | |
129 img.data[i].R = img.data[i].R * img.data[i].A / 255; | |
130 img.data[i].G = img.data[i].G * img.data[i].A / 255; | |
131 img.data[i].B = img.data[i].B * img.data[i].A / 255; | |
132 } | |
133 | |
134 return img; | |
135 } else { return null; } | |
136 } | |
137 } | |
138 | |
139 /// | |
140 enum GraphicsOperator { | |
141 Clear, /// | |
142 | |
143 Source, /// | |
144 Over, /// | |
145 In, /// | |
146 Out, /// | |
147 Atop, /// | |
148 | |
149 Dest, /// | |
150 DestOver, /// | |
151 DestIn, /// | |
152 DestOut, /// | |
153 DestAtop, /// | |
154 | |
155 Xor, /// | |
156 Add, /// | |
157 Saturate /// | |
158 } | |
159 | |
160 /// | |
161 enum GraphicsFillRule { | |
162 /// | |
163 Winding, | |
164 EvenOdd /// | |
165 } | |
166 /** | |
167 * Example: | |
168 * ----- | |
169 * graphics.source = Color.Gold; | |
170 * graphics.rectangle(40, 10, 100, 120); | |
171 * graphics.fill(); | |
172 * graphics.source = Color.Black; | |
173 * | |
174 * graphics.lineWidth = 20; | |
175 * | |
176 * // GraphicsLineCap.Butt is default | |
177 * graphics.moveTo(40, 30); | |
178 * graphics.lineTo(140, 30); | |
179 * graphics.stroke(); | |
180 * | |
181 * graphics.lineCap = GraphicsLineCap.Round; | |
182 * graphics.moveTo(40, 70); | |
183 * graphics.lineTo(140, 70); | |
184 * graphics.stroke(); | |
185 * | |
186 * graphics.lineCap = GraphicsLineCap.Square; | |
187 * graphics.moveTo(40, 110); | |
188 * graphics.lineTo(140, 110); | |
189 * graphics.stroke(); | |
190 * ----- | |
191 * $(IMAGE ../web/example_line_cap.png) | |
192 */ | |
193 enum GraphicsLineCap { | |
194 /** | |
195 * Uses no ending. The line ends exactly at the end point. | |
196 */ | |
197 Butt, | |
198 /** | |
199 * Uses a rounded ending with the center of the circle at the end point. | |
200 * Therefore, the cap extends past the end point for half the line width. | |
201 */ | |
202 Round, | |
203 /** | |
204 * Uses a square ending with the center of the square at the end point. | |
205 * Therefore, the cap extends past the end point for half the line width. | |
206 */ | |
207 Square | |
208 } | |
209 | |
210 // cairo_copy_clip_rectangles --> Rectangle[] ClipRectangles() | |
211 // cairo_get_dash --> Dashes() | |
212 // cairo_get_color_stop_rgba --> ColorStops() | |
213 /** | |
214 * A Graphics object uses its source to draw on its target. Its target is set | |
215 * when it is created, but its source can be changed whenever desired. For | |
216 * example, for a painting event, the target of a Graphics is the control | |
217 * being painted. In other cases it could be an image. Its source is usually a | |
218 * color, but could be a gradient, an image, or some other pattern. | |
219 * | |
220 * If the documentation here is not sufficient, cairo might have | |
221 * better documentation at $(LINK http://www.cairographics.org/manual/). | |
222 */ | |
223 class Graphics { | |
224 private: | |
225 cairo_t* cr; | |
226 public: | |
227 this(cairo_t* cr) { | |
228 this.cr = cr; | |
229 cairo_reference(cr); | |
230 checkStatus(); | |
231 } | |
232 ~this() { | |
233 cairo_destroy(cr); | |
234 } | |
235 /** | |
236 * Returns: a pointer to the cairo context (cairo_t*) that backs this object | |
237 */ | |
238 cairo_t* handle() { return cr; } | |
239 void checkStatus() { | |
240 cairo_status_t status = cairo_status(cr); | |
241 if(status == CAIRO_STATUS_SUCCESS) | |
242 return; | |
243 | |
244 Stdout("Cairo error: ")(cairo_status_to_string(status)).newline; | |
245 assert(0); | |
246 } | |
247 /// | |
248 void moveTo(real x, real y) { | |
249 cairo_move_to(cr, x, y); | |
250 } | |
251 /// ditto | |
252 void moveTo(Point pt) { | |
253 moveTo(pt.x, pt.y); | |
254 } | |
255 /// | |
256 void lineTo(real x, real y) { | |
257 cairo_line_to(cr, x, y); | |
258 } | |
259 /// ditto | |
260 void lineTo(Point pt) { | |
261 lineTo(pt.x, pt.y); | |
262 } | |
263 /// | |
264 void curveTo(Point pt1, Point pt2, Point pt3) { | |
265 curveTo(pt1.x, pt1.y, pt2.x, pt2.y, pt3.x, pt3.y); | |
266 } | |
267 /// ditto | |
268 void curveTo(real x1, real y1, real x2, real y2, real x3, real y3) { | |
269 cairo_curve_to(cr, x1, y1, x2, y2, x3, y3); | |
270 } | |
271 /// | |
272 void relMoveTo(real x, real y) { | |
273 cairo_rel_move_to(cr, x, y); | |
274 } | |
275 /// ditto | |
276 void relMoveTo(Point pt) { | |
277 relMoveTo(pt.x, pt.y); | |
278 } | |
279 /// | |
280 void relLineTo(real x, real y) { | |
281 cairo_rel_line_to(cr, x, y); | |
282 } | |
283 /// ditto | |
284 void relLineTo(Point pt) { | |
285 relLineTo(pt.x, pt.y); | |
286 } | |
287 /// | |
288 void relCurveTo(Point pt1, Point pt2, Point pt3) { | |
289 relCurveTo(pt1.x, pt1.y, pt2.x, pt2.y, pt3.x, pt3.y); | |
290 } | |
291 /// ditto | |
292 void relCurveTo(real x1, real y1, real x2, real y2, real x3, real y3) { | |
293 cairo_rel_curve_to(cr, x1, y1, x2, y2, x3, y3); | |
294 } | |
295 /** | |
296 * Adds an arc to the current path. A line is added connecting the | |
297 * current point to the beginning of the arc. | |
298 * Example: | |
299 * ----- | |
300 * graphics.moveTo(5, 5); | |
301 * graphics.arc(50.5, 80.5, 40, 40, -0.2, PI/2); | |
302 * graphics.stroke(); | |
303 * ----- | |
304 * $(IMAGE ../web/example_arc.png) | |
305 */ | |
306 void arc(Point ptc, real radius, real angle1, real angle2) { | |
307 arc(ptc.x, ptc.y, radius, angle1, angle2); | |
308 } | |
309 /// ditto | |
310 void arc(real xc, real yc, real radius, real angle1, real angle2) { | |
311 cairo_arc(cr, xc, yc, radius, angle1, angle2); | |
312 } | |
313 /// ditto | |
314 void arc(real xc, real yc, real xradius, real yradius, real angle1, real angle2) { | |
315 cairo_save(cr); | |
316 cairo_translate(cr, xc, yc); | |
317 cairo_scale(cr, xradius, yradius); | |
318 cairo_arc(cr, 0, 0, 1, angle1, angle2); | |
319 cairo_restore(cr); | |
320 } | |
321 /** | |
322 * Adds an ellipse as a closed sub-path--a line will not connect it | |
323 * to the current point. | |
324 * Example: | |
325 * ----- | |
326 * graphics.ellipse(70.5, 50.5, 60, 25); | |
327 * graphics.stroke(); | |
328 * ----- | |
329 * $(IMAGE ../web/example_ellipse.png) | |
330 */ | |
331 void ellipse(real xc, real yc, real radius) { | |
332 cairo_new_sub_path(cr); | |
333 cairo_arc(cr, xc, yc, radius, 0, Pi * 2); | |
334 cairo_close_path(cr); | |
335 } | |
336 /// ditto | |
337 void ellipse(real xc, real yc, real xradius, real yradius) { | |
338 cairo_new_sub_path(cr); | |
339 arc(xc, yc, xradius, yradius, 0, Pi * 2); | |
340 cairo_close_path(cr); | |
341 } | |
342 /** | |
343 * Adds a rectangle as a sub-path--a line will not connect it | |
344 * to the current point. | |
345 * Example: | |
346 * ----- | |
347 * graphics.rectangle(5.5, 5.5, 70, 20); | |
348 * graphics.stroke(); | |
349 * ----- | |
350 * $(IMAGE ../web/example_rectangle.png) | |
351 */ | |
352 void rectangle(Rect rect) { | |
353 rectangle(rect.x, rect.y, rect.width, rect.height); | |
354 } | |
355 /// ditto | |
356 void rectangle(real x, real y, real width, real height) { | |
357 cairo_rectangle(cr, x, y, width, height); | |
358 } | |
16
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
359 /** |
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
360 * Adds a rectangle with rounded corners as a sub-path--a line will |
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
361 * not connect it to the current point. |
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
362 */ |
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
363 void roundedRectangle(Rect rect, real radius) { |
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
364 roundedRectangle(rect.x, rect.y, rect.width, rect.height, radius); |
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
365 } |
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
366 /// ditto |
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
367 void roundedRectangle(real x, real y, real width, real height, real radius) { |
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
368 alias radius r; |
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
369 cairo_new_sub_path(cr); |
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
370 arc(x+r, y+r, r, Pi, 3*Pi/2); |
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
371 arc(x+width-r, y+r, r, 3*Pi/2, 0); |
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
372 arc(x+width-r, y+height-r, r, 0, Pi/2); |
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
373 arc(x+r, y+height-r, r, Pi/2, Pi); |
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
374 closePath(); |
dcaa95190f4b
Add roundedRectangle() method to Graphics.
Jordan Miner <jminer7@gmail.com>
parents:
0
diff
changeset
|
375 } |
0 | 376 /// |
377 void closePath() { | |
378 cairo_close_path(cr); | |
379 } | |
380 /** | |
381 * Draws the outline of the current path. | |
382 * Example: | |
383 * ----- | |
384 * graphics.moveTo(12.5, 14.5); | |
385 * graphics.lineTo(123.5, 22.5); | |
386 * graphics.lineTo(139.5, 108.5); | |
387 * graphics.lineTo(49.5, 86.5); | |
388 * graphics.closePath(); | |
389 * graphics.stroke(); | |
390 * ----- | |
391 * $(IMAGE ../web/example_stroke.png) | |
392 */ | |
393 void stroke() { | |
394 cairo_stroke(cr); | |
395 } | |
396 /** | |
397 * Draws the inside of the current path. | |
398 * Example: | |
399 * ----- | |
400 * graphics.MoveTo(12.5, 14.5); | |
401 * graphics.LineTo(123.5, 22.5); | |
402 * graphics.LineTo(139.5, 108.5); | |
403 * graphics.LineTo(49.5, 86.5); | |
404 * graphics.ClosePath(); | |
405 * graphics.Fill(); | |
406 * ----- | |
407 * $(IMAGE ../web/example_fill.png) | |
408 */ | |
409 void fill() { | |
410 cairo_fill(cr); | |
411 } | |
412 /** | |
413 * Paints the current source everywhere within the current clip region. | |
414 * Examples: | |
415 * ----- | |
416 * graphics.source = Color(255, 128, 0); | |
417 * graphics.paint(); | |
418 * ----- | |
419 * $(IMAGE ../web/example_paint.png) | |
420 */ | |
421 void paint() { | |
422 cairo_paint(cr); | |
423 } | |
424 /** | |
425 * Gets or sets the line _width used for stroking. | |
426 * Example: | |
427 * ----- | |
428 * graphics.ellipse(40.5, 30.5, 30, 20); | |
429 * graphics.lineWidth = 1; | |
430 * graphics.stroke(); | |
431 * graphics.ellipse(40.5, 80.5, 30, 20); | |
432 * graphics.lineWidth = 5; | |
433 * graphics.stroke(); | |
434 * ----- | |
435 * $(IMAGE ../web/example_line_width.png) | |
436 */ | |
437 real lineWidth() { | |
438 return cairo_get_line_width(cr); | |
439 } | |
440 /// ditto | |
441 void lineWidth(real width) { | |
442 cairo_set_line_width(cr, width); | |
443 } | |
444 /** | |
445 * Gets or sets the line cap used for stroking. | |
446 * | |
447 * The line cap is only examined when the stroke is performed, not before. | |
448 * Therefore, drawing two lines, each with a different line cap, would | |
449 * require calling stroke twice. | |
450 */ | |
451 GraphicsLineCap lineCap() { | |
452 return cast(GraphicsLineCap)cairo_get_line_cap(cr); | |
453 } | |
454 /// ditto | |
455 void lineCap(GraphicsLineCap cap) { | |
456 cairo_set_line_cap(cr, cap); | |
457 } | |
458 /** | |
459 * Sets the font size to the specified size in user space units, not | |
460 * in points. | |
461 */ | |
462 void fontSize(real size) { | |
463 assert(size != 0); | |
464 cairo_set_font_size(cr, size); | |
465 } | |
466 /** | |
467 * Set the font used to draw text. | |
468 */ | |
469 void font(Font f) { | |
470 assert(f.size != 0); | |
471 cairo_set_font_size(cr, f.size); | |
472 cairo_select_font_face(cr, toCharPtr(f.family), f.italic, f.bold); | |
473 } | |
474 // TODO: if text is all ascii, do fast path with no uniscribe | |
475 void drawText(string text, real x, real y) { | |
476 auto extents = getFontExtents; | |
477 cairo_font_extents_t fextents; | |
478 cairo_font_extents(cr, &fextents); | |
479 cairo_move_to(cr, x, y + fextents.ascent); | |
480 cairo_show_text(cr, toCharPtr(text)); // 99% of time spent in show_text | |
481 checkStatus(); | |
482 } | |
483 /// | |
484 Size getTextExtents(string text) { | |
485 cairo_text_extents_t textents; | |
486 cairo_text_extents(cr, toCharPtr(text), &textents); | |
487 cairo_font_extents_t fextents; | |
488 cairo_font_extents(cr, &fextents); | |
489 return Size(textents.x_advance, fextents.height); | |
490 } | |
491 /// | |
492 FontExtents getFontExtents() { // TODO: make property? | |
493 cairo_font_extents_t fextents; | |
494 cairo_font_extents(cr, &fextents); | |
495 FontExtents extents; | |
496 extents.ascent = fextents.ascent; | |
497 extents.descent = fextents.descent; | |
498 extents.height = fextents.height; | |
499 extents.maxAdvance = fextents.max_x_advance; | |
500 return extents; | |
501 } | |
502 /// | |
503 Rect getClipExtents() { // TODO: make property? | |
504 double x, y, width, height; | |
505 cairo_clip_extents(cr, &x, &y, &width, &height); | |
506 return Rect(x, y, width, height); | |
507 } | |
508 /// | |
509 void save() { | |
510 cairo_save(cr); | |
511 } | |
512 /// | |
513 void restore() { | |
514 cairo_restore(cr); | |
515 checkStatus(); | |
516 } | |
517 /// | |
518 void clip() { | |
519 cairo_clip(cr); | |
520 } | |
521 /// | |
522 void translate(Point pt) { | |
523 translate(pt.x, pt.y); | |
524 } | |
525 /// ditto | |
526 void translate(real x, real y) { | |
527 cairo_translate(cr, x, y); | |
528 } | |
529 /// | |
530 void scale(real x, real y) { | |
531 cairo_scale(cr, x, y); | |
532 } | |
533 /// | |
534 void rotate(real angle) { | |
535 cairo_rotate(cr, angle); | |
536 } | |
537 /// | |
538 GraphicsOperator operator() { | |
539 return cast(GraphicsOperator)cairo_get_operator(cr); | |
540 } | |
541 /// | |
542 void operator(GraphicsOperator op) { | |
543 cairo_set_operator(cr, cast(cairo_operator_t)op); | |
544 } | |
545 /** | |
546 * Sets the dash pattern to be used when lines are drawn. | |
547 */ | |
548 void setDash(real[] dashes, real offset) { | |
549 auto cdashes = new double[dashes.length]; | |
550 foreach(int i, real r; dashes) | |
551 cdashes[i] = r; | |
552 cairo_set_dash(cr, cdashes.ptr, cdashes.length, offset); | |
553 } | |
554 /** | |
555 * Gets or sets the fill rule the current fill rule. | |
556 * The default is GraphicsFillRule.Winding. | |
557 */ | |
558 GraphicsFillRule fillRule() { | |
559 return cast(GraphicsFillRule)cairo_get_fill_rule(cr); | |
560 } | |
561 /// ditto | |
562 void fillRule(GraphicsFillRule rule) { | |
563 cairo_set_fill_rule(cr, cast(cairo_fill_rule_t)rule); | |
564 } | |
565 /** | |
566 * The temporary surface created will be the same size as the current clip. To speed up using this function, call Clip() to the area you will be drawing in. | |
567 */ | |
568 void pushGroup() { | |
569 cairo_push_group(cr); | |
570 } | |
571 //popGroup() { // TODO: returning a pattern | |
572 // cairo_pop_group(cr); | |
573 //} | |
574 /** | |
575 * Terminates the redirection begun by a call to PushGroup() or | |
576 * PushGroupWithContent() and installs the resulting pattern as the | |
577 * source pattern. | |
578 */ | |
579 void popGroupToSource() { | |
580 cairo_pop_group_to_source(cr); | |
581 checkStatus(); | |
582 } | |
583 // TODO: figure out the best way to set the source and get the source | |
584 void source(Color c) { | |
585 cairo_set_source_rgba(cr, c.R/255.0, c.G/255.0, c.B/255.0, c.A/255.0); | |
586 } | |
587 //void source(Pattern s) {} | |
588 //void setSource(Surface s, real x = 0, real y = 0) {} | |
589 // TODO: remove this function and have users do: | |
590 // g.setSource(img, x, y); | |
591 // g.paint(); | |
592 // ??? | |
593 // paintSource(Image, real, real) ? | |
594 /// Draws the specified image unscaled. | |
595 void drawImage(Image image, real x, real y) { | |
596 auto surface= cairo_image_surface_create_for_data(cast(char*)image.data, | |
597 CAIRO_FORMAT_ARGB32, image.width, image.height, image.width*4); | |
598 save(); | |
599 cairo_set_source_surface(cr, surface, x, y); | |
600 cairo_paint(cr); | |
601 restore(); | |
602 cairo_surface_destroy(surface); | |
603 } | |
604 // Draws the specified image scaled to the specified width and height. | |
605 //void drawImage(Image image, real x, real y, real width, real height); | |
606 } |