sciter/
graphics.rs

1/*! Sciter's platform independent graphics interface.
2
3Used in custom behaviors / event handlers to draw on element's surface in native code.
4Essentially this mimics [`Graphics`](https://sciter.com/docs/content/sciter/Graphics.htm)
5scripting object as close as possible.
6
7*/
8use capi::scgraphics::{HTEXT, HIMG, HPATH};
9use capi::scgraphics::{SC_ANGLE, SC_COLOR, SC_COLOR_STOP, SC_DIM, SC_POS};
10use capi::sctypes::{BOOL, LPCBYTE, LPVOID, POINT, SIZE, UINT};
11use std::ptr::{null_mut, null};
12use value::{FromValue, Value};
13use dom::Element;
14use _GAPI;
15
16pub use capi::scgraphics::{HGFX, GRAPHIN_RESULT};
17pub use capi::scgraphics::{DRAW_PATH, LINE_CAP, LINE_JOIN};
18
19/// Supported image encodings for [`Image.save()`](struct.Image.html#method.save).
20#[derive(Clone, Copy)]
21#[derive(Debug, PartialEq)]
22pub enum SaveImageEncoding {
23  /// Raw bitmap in a `[a,b,g,r, a,b,g,r, ...]` form.
24  Raw,
25  /// Portable Network Graphics format.
26  Png,
27  /// JPEG with the specified quality level (in range of `10..100`).
28  Jpeg(u8),
29  /// WebP with the specified quality level (in range of `0..100`, where `0` means a lossless compression).
30  Webp(u8),
31}
32
33macro_rules! ok_or {
34  ($rv:expr, $ok:ident) => {
35    if $ok == GRAPHIN_RESULT::OK {
36      Ok($rv)
37    } else {
38      Err($ok)
39    }
40  };
41}
42
43/// A specialized `Result` type for graphics operations.
44pub type Result<T> = ::std::result::Result<T, GRAPHIN_RESULT>;
45
46/// Color type in the `RGBA` form.
47pub type Color = SC_COLOR;
48
49/// Position on a surface in `(x, y)` form.
50pub type Pos = (SC_POS, SC_POS);
51
52/// Size in `(width, height)` form.
53pub type Size = (SC_DIM, SC_DIM);
54
55/// Angle type (in radians).
56pub type Angle = SC_ANGLE;
57
58/// Dimension type.
59pub type Dim = SC_DIM;
60
61/// Construct a color value (in `RGBA` form) from the `red`, `green` and `blue` components.
62pub fn rgb(red: u8, green: u8, blue: u8) -> Color {
63  (_GAPI.RGBA)(u32::from(red), u32::from(green), u32::from(blue), 255)
64}
65
66/// Construct a color value (in `RGBA` form) from the `red`, `green`, `blue` and `opacity` components.
67pub fn rgba((r, g, b): (u8, u8, u8), opacity: u8) -> Color {
68	let color = rgb(r, g, b);
69  u32::from(opacity) | color << 24
70}
71
72
73///////////////////////////////////////////////////////////////////////////////
74// Text
75/// Metrics of a text layout object.
76#[derive(Debug, Default)]
77pub struct TextMetrics {
78	/// Minimum width, is a width of the widest word (non-breakable sequence) in the text.
79	pub min_width: Dim,
80	/// Maximum width, is the width of the text without wrapping.
81	///
82	/// If the text contains new line sequences then function returns width of widest string.
83	pub max_width: Dim,
84	/// Computed height of the Text object and box height.
85	pub height: Dim,
86	pub ascent: Dim,
87	pub descent: Dim,
88	/// Mumber of lines in text layout.
89	///
90	/// To get meaningful values you should set width of the text layout object
91	/// (with [`Text.set_box`](struct.Text.html#method.set_box), for example).
92	pub lines: u32,
93}
94
95/// Text layout object.
96pub struct Text(HTEXT);
97
98/// Destroy pointed text object.
99impl Drop for Text {
100	fn drop(&mut self) {
101		(_GAPI.textRelease)(self.0);
102	}
103}
104
105/// Copies text object.
106///
107/// All allocated objects are reference counted so copying is just a matter of increasing reference counts.
108impl Clone for Text {
109  fn clone(&self) -> Self {
110    let dst = Text(self.0);
111    (_GAPI.textAddRef)(dst.0);
112    dst
113  }
114}
115
116/// Get a `Text` object contained in the `Value`.
117impl FromValue for Text {
118  fn from_value(v: &Value) -> Option<Text> {
119    let mut h = null_mut();
120    let ok = (_GAPI.vUnWrapText)(v.as_cptr(), &mut h);
121    if ok == GRAPHIN_RESULT::OK {
122      (_GAPI.textAddRef)(h);
123      Some(Text(h))
124    } else {
125      None
126    }
127  }
128}
129
130/// Store the `Text` object as a `Value`.
131impl From<Text> for Value {
132  fn from(i: Text) -> Value {
133    let mut v = Value::new();
134    let ok = (_GAPI.vWrapText)(i.0, v.as_ptr());
135    assert!(ok == GRAPHIN_RESULT::OK);
136    v
137  }
138}
139
140impl Text {
141	/// Create a text layout object on top of a host element.
142	pub fn create(e: &Element, text: &str) -> Result<Text> {
143		let (t, tn) = s2wn!(text);
144		let mut h = null_mut();
145		let ok = (_GAPI.textCreateForElement)(&mut h, t.as_ptr(), tn, e.as_ptr(), null());
146		ok_or!(Text(h), ok)
147	}
148
149	/// Create a text layout object on top of a host element with the specified `class` attribute.
150	pub fn with_class(e: &Element, text: &str, class: &str) -> Result<Text> {
151		let (t, tn) = s2wn!(text);
152		let (c, _cn) = s2wn!(class);
153		let mut h = null_mut();
154		let ok = (_GAPI.textCreateForElement)(&mut h, t.as_ptr(), tn, e.as_ptr(), c.as_ptr() );
155		ok_or!(Text(h), ok)
156	}
157
158	/// Create a text layout object on top of a host element with the specified `style` attribute.
159	pub fn with_style(e: &Element, text: &str, styles: &str) -> Result<Text> {
160		let (t, tn) = s2wn!(text);
161		let (s, sn) = s2wn!(styles);
162		let mut h = null_mut();
163		let ok = (_GAPI.textCreateForElementAndStyle)(&mut h, t.as_ptr(), tn, e.as_ptr(), s.as_ptr(), sn);
164		ok_or!(Text(h), ok)
165	}
166
167	/// Sets the box `width` and `height` of the text object.
168	pub fn set_box(&mut self, size: Size) -> Result<()> {
169		let ok = (_GAPI.textSetBox)(self.0, size.0, size.1);
170		ok_or!((), ok)
171	}
172
173	/// Returns metrics of the text layout object.
174	pub fn get_metrics(&self) -> Result<TextMetrics> {
175		let mut tm = TextMetrics::default();
176		let ok = (_GAPI.textGetMetrics)(self.0,
177				&mut tm.min_width, &mut tm.max_width,
178				&mut tm.height,
179				&mut tm.ascent, &mut tm.descent,
180				&mut tm.lines,
181			);
182		ok_or!(tm, ok)
183	}
184}
185
186///////////////////////////////////////////////////////////////////////////////
187// Image
188
189/// Graphics image object.
190pub struct Image(HIMG);
191
192/// Destroy pointed image object.
193impl Drop for Image {
194  fn drop(&mut self) {
195    (_GAPI.imageRelease)(self.0);
196  }
197}
198
199/// Copies image object.
200///
201/// All allocated objects are reference counted so copying is just a matter of increasing reference counts.
202impl Clone for Image {
203  fn clone(&self) -> Self {
204    let dst = Image(self.0);
205    (_GAPI.imageAddRef)(dst.0);
206    dst
207  }
208}
209
210/// Get an `Image` object contained in the `Value`.
211impl FromValue for Image {
212  fn from_value(v: &Value) -> Option<Image> {
213    let mut h = null_mut();
214    let ok = (_GAPI.vUnWrapImage)(v.as_cptr(), &mut h);
215    if ok == GRAPHIN_RESULT::OK {
216    	(_GAPI.imageAddRef)(h);
217      Some(Image(h))
218    } else {
219      None
220    }
221  }
222}
223
224/// Store the `Image` object as a `Value`.
225impl From<Image> for Value {
226  fn from(i: Image) -> Value {
227    let mut v = Value::new();
228    let ok = (_GAPI.vWrapImage)(i.0, v.as_ptr());
229    assert!(ok == GRAPHIN_RESULT::OK);
230    v
231  }
232}
233
234impl Image {
235  /// Create a new blank image.
236  pub fn create((width, height): (u32, u32), with_alpha: bool) -> Result<Image> {
237    let mut h = null_mut();
238    let ok = (_GAPI.imageCreate)(&mut h, width, height, with_alpha as BOOL);
239    ok_or!(Image(h), ok)
240  }
241
242  /// Create a new blank image.
243  #[deprecated(note="Use `Image::create` instead.")]
244  pub fn new((width, height): (u32, u32), with_alpha: bool) -> Result<Image> {
245  	Self::create((width, height), with_alpha)
246  }
247
248  /// Create image from `BGRA` data. Size of the pixmap is `width * height * 4` bytes.
249  pub fn with_data((width, height): (u32, u32), with_alpha: bool, pixmap: &[u8]) -> Result<Image> {
250    let mut h = null_mut();
251    let ok = (_GAPI.imageCreateFromPixmap)(&mut h, width, height, with_alpha as BOOL, pixmap.as_ptr());
252    ok_or!(Image(h), ok)
253  }
254
255  /// Load image from memory.
256  ///
257  /// Supported formats are: GIF, JPEG, PNG, WebP. On Windows also are BMP, ICO, TIFF and WMP.
258  pub fn load(image_data: &[u8]) -> Result<Image> {
259    let mut h = null_mut();
260    let ok = (_GAPI.imageLoad)(image_data.as_ptr(), image_data.len() as UINT, &mut h);
261    ok_or!(Image(h), ok)
262  }
263
264  /// Save content of the image as a byte vector.
265  pub fn save(&self, encoding: SaveImageEncoding) -> Result<Vec<u8>> {
266    extern "system" fn on_save(prm: LPVOID, data: LPCBYTE, data_length: UINT) {
267      assert!(!prm.is_null());
268      assert!(!data.is_null());
269      unsafe {
270        let param = prm as *mut Vec<u8>;
271        let dst = &mut *param;
272        let src = ::std::slice::from_raw_parts(data, data_length as usize);
273        dst.extend_from_slice(src);
274      }
275    }
276    use capi::scgraphics::IMAGE_ENCODING::*;
277    let (enc, q) = match encoding {
278      SaveImageEncoding::Raw => (RAW, 0),
279      SaveImageEncoding::Png => (PNG, 0),
280      SaveImageEncoding::Jpeg(q) => (JPG, q),
281      SaveImageEncoding::Webp(q) => (WEBP, q),
282    };
283    let mut data = Vec::new();
284    let ok = (_GAPI.imageSave)(self.0, on_save, &mut data as *mut _ as LPVOID, enc, u32::from(q));
285    ok_or!(data, ok)
286  }
287
288  /// Render on bitmap image using methods of the [`Graphics`](struct.Graphics.html) object.
289  ///
290  /// The image must be created using [`Image::new()`](struct.Image.html#method.new) or
291  /// [`Image::with_data()`](struct.Image.html#method.with_data) methods
292  /// or loaded from a [BMP](https://en.wikipedia.org/wiki/BMP_file_format) file.
293  ///
294  /// `PaintFn` painter type must be the following:
295  ///
296  /// ```rust
297  /// use sciter::graphics::{Graphics, Result};
298  ///
299  /// fn paint(gfx: &mut Graphics, (width, height): (f32, f32)) -> Result<()>
300  /// # { Ok(()) }
301  /// ```
302  ///
303  /// Note that errors inside painter are promoted back to the caller of the `paint()`.
304  ///
305  /// # Example:
306  ///
307  /// ```rust
308  /// # use sciter::graphics::Image;
309  /// let mut image = Image::new((100, 100), false).unwrap();
310  /// image.paint(|gfx, size| {
311  ///   gfx.rectangle((5.0, 5.0), (size.0 - 5.0, size.1 - 5.0))?;
312  ///   Ok(())
313  /// }).unwrap();
314  /// ```
315  pub fn paint<PaintFn>(&mut self, painter: PaintFn) -> Result<()>
316  where
317    PaintFn: Fn(&mut Graphics, (f32, f32)) -> Result<()>,
318  {
319    #[repr(C)]
320    struct Payload<PaintFn> {
321      painter: PaintFn,
322      result: Result<()>,
323    }
324    extern "system" fn on_paint<PaintFn: Fn(&mut Graphics, (f32, f32)) -> Result<()>>(prm: LPVOID, hgfx: HGFX, width: UINT, height: UINT) {
325      let param = prm as *mut Payload<PaintFn>;
326      assert!(!param.is_null());
327      assert!(!hgfx.is_null());
328    	let payload = unsafe { &mut *param };
329      let ok = if !hgfx.is_null() {
330      	let mut gfx = Graphics::from(hgfx);
331      	(payload.painter)(&mut gfx, (width as f32, height as f32))
332      } else {
333      	Err(GRAPHIN_RESULT::BAD_PARAM)
334      };
335      payload.result = ok;
336    }
337    let payload = Payload {
338      painter: painter,
339      result: Ok(()),
340    };
341    let param = Box::new(payload);
342    let param = Box::into_raw(param);
343    let ok = (_GAPI.imagePaint)(self.0, on_paint::<PaintFn>, param as LPVOID);
344    let ok = ok_or!((), ok);
345    let param = unsafe { Box::from_raw(param) };
346    ok.and(param.result)
347  }
348
349  /// Get width and height of the image (in pixels).
350  pub fn dimensions(&self) -> Result<(u32, u32)> {
351    let mut alpha = 0;
352    let mut w = 0;
353    let mut h = 0;
354    let ok = (_GAPI.imageGetInfo)(self.0, &mut w, &mut h, &mut alpha);
355    ok_or!((w, h), ok)
356  }
357
358  /// Clear image by filling it with the black color.
359  pub fn clear(&mut self) -> Result<()> {
360    let ok = (_GAPI.imageClear)(self.0, Graphics::NO_COLOR);
361    ok_or!((), ok)
362  }
363
364  /// Clear image by filling it with the specified `color`.
365  pub fn clear_with(&mut self, color: Color) -> Result<()> {
366    let ok = (_GAPI.imageClear)(self.0, color);
367    ok_or!((), ok)
368  }
369}
370
371///////////////////////////////////////////////////////////////////////////////
372// Path
373
374/// Graphics path object.
375pub struct Path(HPATH);
376
377/// Destroy pointed path object.
378impl Drop for Path {
379  fn drop(&mut self) {
380    (_GAPI.pathRelease)(self.0);
381  }
382}
383
384/// Copies path object.
385///
386/// All allocated objects are reference counted so copying is just a matter of increasing reference counts.
387impl Clone for Path {
388  fn clone(&self) -> Self {
389    let dst = Path(self.0);
390    (_GAPI.pathAddRef)(dst.0);
391    dst
392  }
393}
394
395/// Get a `Path` object contained in the `Value`.
396impl FromValue for Path {
397  fn from_value(v: &Value) -> Option<Path> {
398    let mut h = null_mut();
399    let ok = (_GAPI.vUnWrapPath)(v.as_cptr(), &mut h);
400    if ok == GRAPHIN_RESULT::OK {
401    	(_GAPI.pathAddRef)(h);
402      Some(Path(h))
403    } else {
404      None
405    }
406  }
407}
408
409/// Store the `Path` object as a `Value`.
410impl From<Path> for Value {
411  fn from(i: Path) -> Value {
412    let mut v = Value::new();
413    let ok = (_GAPI.vWrapPath)(i.0, v.as_ptr());
414    assert!(ok == GRAPHIN_RESULT::OK);
415    v
416  }
417}
418
419impl Path {
420  /// Create a new empty path.
421  pub fn create() -> Result<Path> {
422    let mut h = null_mut();
423    let ok = (_GAPI.pathCreate)(&mut h);
424    ok_or!(Path(h), ok)
425  }
426
427  /// Create a new empty path.
428  #[deprecated(note="Use `Path::create()` instead.")]
429  pub fn new() -> Result<Path> {
430  	Self::create()
431  }
432
433  /// Close the current path/figure.
434  pub fn close(&mut self) -> Result<()> {
435    let ok = (_GAPI.pathClosePath)(self.0);
436    ok_or!((), ok)
437  }
438
439  /// Move the current drawing path position to `x,y`.
440  ///
441  /// If `is_relative` is `true` then the specified coordinates are interpreted as deltas from the current path position.
442  pub fn move_to(&mut self, point: Pos, is_relative: bool) -> Result<&mut Path> {
443    let ok = (_GAPI.pathMoveTo)(self.0, point.0, point.1, is_relative as BOOL);
444    ok_or!(self, ok)
445  }
446
447  /// Draw a line and move the current drawing path position to `x,y`.
448  ///
449  /// If `is_relative` is `true` then the specified coordinates are interpreted as deltas from the current path position.
450  pub fn line_to(&mut self, point: Pos, is_relative: bool) -> Result<&mut Path> {
451    let ok = (_GAPI.pathLineTo)(self.0, point.0, point.1, is_relative as BOOL);
452    ok_or!(self, ok)
453  }
454
455  /// Draw an arc.
456  pub fn arc_to(&mut self, xy: Pos, angle: Angle, rxy: Pos, is_large: bool, is_clockwise: bool, is_relative: bool) -> Result<&mut Path> {
457    let ok = (_GAPI.pathArcTo)(
458      self.0,
459      xy.0,
460      xy.1,
461      angle,
462      rxy.0,
463      rxy.1,
464      is_large as BOOL,
465      is_clockwise as BOOL,
466      is_relative as BOOL,
467    );
468    ok_or!(self, ok)
469  }
470
471  /// Draw a quadratic Bézier curve.
472  ///
473  /// If `is_relative` is `true` then the specified coordinates are interpreted as deltas from the current path position.
474  pub fn quadratic_curve_to(&mut self, control: Pos, end: Pos, is_relative: bool) -> Result<&mut Path> {
475    let ok = (_GAPI.pathQuadraticCurveTo)(self.0, control.0, control.1, end.0, end.1, is_relative as BOOL);
476    ok_or!(self, ok)
477  }
478
479  /// Draw a cubic Bézier curve.
480  ///
481  /// If `is_relative` is `true` then the specified coordinates are interpreted as deltas from the current path position.
482  pub fn bezier_curve_to(&mut self, control1: Pos, control2: Pos, end: Pos, is_relative: bool) -> Result<&mut Path> {
483    let ok = (_GAPI.pathBezierCurveTo)(
484      self.0,
485      control1.0,
486      control1.1,
487      control2.0,
488      control2.1,
489      end.0,
490      end.1,
491      is_relative as BOOL,
492    );
493    ok_or!(self, ok)
494  }
495}
496
497///////////////////////////////////////////////////////////////////////////////
498// Graphics
499
500/// A graphics state guard.
501///
502/// Used to automatically restore a previous saved graphics attributes state.
503pub struct State<'a>(&'a mut Graphics);
504
505/// Restore graphics state.
506impl<'a> Drop for State<'a> {
507	fn drop(&mut self) {
508		self.0.pop_state().ok();
509	}
510}
511
512/// Dereference to `Graphics`.
513impl<'a> ::std::ops::Deref for State<'a> {
514	type Target = Graphics;
515	fn deref(&self) -> &Graphics {
516		self.0
517	}
518}
519
520/// Dereference to `Graphics`.
521impl<'a> ::std::ops::DerefMut for State<'a> {
522	fn deref_mut(&mut self) -> &mut Graphics {
523		self.0
524	}
525}
526
527/// Graphics object. Represents graphic surface of the element.
528pub struct Graphics(HGFX);
529
530/// Destroy pointed graphics object.
531impl Drop for Graphics {
532  fn drop(&mut self) {
533    (_GAPI.gRelease)(self.0);
534  }
535}
536
537/// Copies graphics object.
538///
539/// All allocated objects are reference counted so copying is just a matter of increasing reference counts.
540impl Clone for Graphics {
541  fn clone(&self) -> Self {
542    let dst = Graphics(self.0);
543    (_GAPI.gAddRef)(dst.0);
544    dst
545  }
546}
547
548/// Get an `Graphics` object contained in the `Value`.
549impl FromValue for Graphics {
550  fn from_value(v: &Value) -> Option<Graphics> {
551    let mut h = null_mut();
552    let ok = (_GAPI.vUnWrapGfx)(v.as_cptr(), &mut h);
553    if ok == GRAPHIN_RESULT::OK {
554    	(_GAPI.gAddRef)(h);
555      Some(Graphics(h))
556    } else {
557      None
558    }
559  }
560}
561
562/// Store the `Graphics` object as a `Value`.
563impl From<Graphics> for Value {
564  fn from(i: Graphics) -> Value {
565    let mut v = Value::new();
566    let ok = (_GAPI.vWrapGfx)(i.0, v.as_ptr());
567    assert!(ok == GRAPHIN_RESULT::OK);
568    v
569  }
570}
571
572/// Construct Graphics object from `HGFX` handle.
573impl From<HGFX> for Graphics {
574	fn from(hgfx: HGFX) -> Graphics {
575		assert!(!hgfx.is_null());
576  	(_GAPI.gAddRef)(hgfx);
577		Graphics(hgfx)
578	}
579}
580
581/// Save/restore graphics state.
582impl Graphics {
583  /// Save the current graphics attributes on top of the internal state stack.
584  ///
585  /// It will be restored automatically.
586  ///
587  /// # Example:
588  ///
589  /// ```rust
590  /// use sciter::graphics::{Image, rgb};
591  ///
592  /// let mut image = Image::new((100, 100), false).unwrap();
593  /// image.paint(|gfx, size| {
594  ///   let mut gfx = gfx.save_state()?;
595  ///   gfx
596  ///     .line_width(6.0)?
597  ///     .line_color(rgb(0xD4, 0, 0))?
598  ///     .fill_color(rgb(0xD4, 0, 0))?
599  ///     .line((-30., 0.), (83., 0.))?
600  ///     ;
601  ///   Ok(())
602  /// }).unwrap();
603	pub fn save_state(&mut self) -> Result<State> {
604		self.push_state().map(|gfx| State(gfx))
605	}
606
607  /// Manually save the current graphics attributes on top of the internal state stack.
608  fn push_state(&mut self) -> Result<&mut Self> {
609    let ok = (_GAPI.gStateSave)(self.0);
610    ok_or!(self, ok)
611  }
612
613  /// Manually restore graphics attributes from top of the internal state stack.
614  fn pop_state(&mut self) -> Result<&mut Self> {
615    let ok = (_GAPI.gStateRestore)(self.0);
616    ok_or!(self, ok)
617	}
618
619	/// Flush all pending graphic operations.
620	pub fn flush(&mut self) -> Result<&mut Self> {
621		let ok = (_GAPI.gFlush)(self.0);
622		ok_or!(self, ok)
623	}
624}
625
626/// Primitives drawing operations.
627///
628/// All operations use the current fill and stroke brushes.
629impl Graphics {
630  /// Draw a line from the `start` to the `end`.
631  pub fn line(&mut self, start: Pos, end: Pos) -> Result<&mut Self> {
632    let ok = (_GAPI.gLine)(self.0, start.0, start.1, end.0, end.1);
633    ok_or!(self, ok)
634  }
635
636  /// Draw a rectangle.
637  pub fn rectangle(&mut self, left_top: Pos, right_bottom: Pos) -> Result<&mut Self> {
638    let ok = (_GAPI.gRectangle)(self.0, left_top.0, left_top.1, right_bottom.0, right_bottom.1);
639    ok_or!(self, ok)
640  }
641
642  /// Draw a rounded rectangle with the same corners.
643  pub fn round_rect(&mut self, left_top: Pos, right_bottom: Pos, radius: Dim) -> Result<&mut Self> {
644    let rad: [Dim; 8] = [radius; 8usize];
645    let ok = (_GAPI.gRoundedRectangle)(self.0, left_top.0, left_top.1, right_bottom.0, right_bottom.1, rad.as_ptr());
646    ok_or!(self, ok)
647  }
648
649  /// Draw a rounded rectangle with different corners.
650  pub fn round_rect4(&mut self, left_top: Pos, right_bottom: Pos, radius: (Dim, Dim, Dim, Dim)) -> Result<&mut Self> {
651    let r = radius;
652    let rad: [Dim; 8] = [r.0, r.0, r.1, r.1, r.2, r.2, r.3, r.3];
653    let ok = (_GAPI.gRoundedRectangle)(self.0, left_top.0, left_top.1, right_bottom.0, right_bottom.1, rad.as_ptr());
654    ok_or!(self, ok)
655  }
656
657  /// Draw an ellipse.
658  pub fn ellipse(&mut self, xy: Pos, radii: Pos) -> Result<&mut Self> {
659    let ok = (_GAPI.gEllipse)(self.0, xy.0, xy.1, radii.0, radii.1);
660    ok_or!(self, ok)
661  }
662
663  /// Draw a circle.
664  pub fn circle(&mut self, xy: Pos, radius: Dim) -> Result<&mut Self> {
665    let ok = (_GAPI.gEllipse)(self.0, xy.0, xy.1, radius, radius);
666    ok_or!(self, ok)
667  }
668
669  /// Draw a closed arc.
670  pub fn arc(&mut self, xy: Pos, rxy: Pos, start: Angle, sweep: Angle) -> Result<&mut Self> {
671    let ok = (_GAPI.gArc)(self.0, xy.0, xy.1, rxy.0, rxy.1, start, sweep);
672    ok_or!(self, ok)
673  }
674
675  /// Draw a star.
676  pub fn star(&mut self, xy: Pos, r1: Dim, r2: Dim, start: Angle, rays: usize) -> Result<&mut Self> {
677    let ok = (_GAPI.gStar)(self.0, xy.0, xy.1, r1, r2, start, rays as UINT);
678    ok_or!(self, ok)
679  }
680
681  /// Draw a closed polygon.
682  pub fn polygon(&mut self, points: &[Pos]) -> Result<&mut Self> {
683    // A compile time assert (credits to https://github.com/nvzqz/static-assertions-rs)
684    type PosArray = [Pos; 2];
685    type FloatArray = [SC_POS; 4];
686    let _ = ::std::mem::transmute::<FloatArray, PosArray>;
687
688    let ok = (_GAPI.gPolygon)(self.0, points.as_ptr() as *const SC_POS, points.len() as UINT);
689    ok_or!(self, ok)
690  }
691
692  /// Draw a polyline.
693  pub fn polyline(&mut self, points: &[Pos]) -> Result<&mut Self> {
694    // A compile time assert (credits to https://github.com/nvzqz/static-assertions-rs)
695    type PosArray = [Pos; 2];
696    type FloatArray = [SC_POS; 4];
697    let _ = ::std::mem::transmute::<FloatArray, PosArray>;
698
699    let ok = (_GAPI.gPolyline)(self.0, points.as_ptr() as *const SC_POS, points.len() as UINT);
700    ok_or!(self, ok)
701  }
702}
703
704/// Drawing attributes.
705impl Graphics {
706	const NO_COLOR: Color = 0;
707
708  /// Set the color for solid fills for subsequent drawings.
709  pub fn fill_color(&mut self, color: Color) -> Result<&mut Self> {
710    let ok = (_GAPI.gFillColor)(self.0, color);
711    ok_or!(self, ok)
712  }
713
714  /// Set the even/odd rule of solid fills for subsequent drawings.
715  ///
716  /// `false` means "fill non zero".
717  pub fn fill_mode(&mut self, is_even: bool) -> Result<&mut Self> {
718    let ok = (_GAPI.gFillMode)(self.0, is_even as BOOL);
719    ok_or!(self, ok)
720  }
721
722  /// Disables fills for subsequent drawing operations.
723  pub fn no_fill(&mut self) -> Result<&mut Self> {
724    self.fill_color(Self::NO_COLOR)
725  }
726
727  /// Set the line color for subsequent drawings.
728  pub fn line_color(&mut self, color: Color) -> Result<&mut Self> {
729    let ok = (_GAPI.gLineColor)(self.0, color);
730    ok_or!(self, ok)
731  }
732
733  /// Set the line width for subsequent drawings.
734  pub fn line_width(&mut self, width: Dim) -> Result<&mut Self> {
735    let ok = (_GAPI.gLineWidth)(self.0, width);
736    ok_or!(self, ok)
737  }
738
739  /// Set the line cap mode (stroke dash ending style) for subsequent drawings.
740  ///
741  /// It determines how the end points of every line are drawn.
742  /// There are three possible values for this property and those are: `BUTT`, `ROUND` and `SQUARE`.
743  /// By default this property is set to `BUTT`.
744  pub fn line_cap(&mut self, style: LINE_CAP) -> Result<&mut Self> {
745    let ok = (_GAPI.gLineCap)(self.0, style);
746    ok_or!(self, ok)
747  }
748
749  /// Set the line join mode for subsequent drawings.
750  ///
751  /// It determines how two connecting segments (of lines, arcs or curves)
752  /// with non-zero lengths in a shape are joined together
753  /// (degenerate segments with zero lengths, whose specified endpoints and control points
754  /// are exactly at the same position, are skipped).
755  pub fn line_join(&mut self, style: LINE_JOIN) -> Result<&mut Self> {
756    let ok = (_GAPI.gLineJoin)(self.0, style);
757    ok_or!(self, ok)
758  }
759
760  /// Disable outline drawing.
761  pub fn no_line(&mut self) -> Result<&mut Self> {
762    self.line_width(0.0)
763  }
764
765  /// Setup parameters of a linear gradient of lines.
766  pub fn line_linear_gradient(&mut self, start: Pos, end: Pos, c1: Color, c2: Color) -> Result<&mut Self> {
767    let stops = [(c1, 0.0), (c2, 1.0)];
768    self.line_linear_gradients(start, end, &stops)
769  }
770
771  /// Setup parameters of a linear gradient of lines using multiple colors and color stop positions `(0.0 ... 1.0)`.
772  pub fn line_linear_gradients(&mut self, start: Pos, end: Pos, colors: &[(Color, Dim)]) -> Result<&mut Self> {
773    let _ = ::std::mem::transmute::<SC_COLOR_STOP, (Color, Dim)>;
774    let ok = (_GAPI.gLineGradientLinear)(
775      self.0,
776      start.0,
777      start.1,
778      end.0,
779      end.1,
780      colors.as_ptr() as *const SC_COLOR_STOP,
781      colors.len() as UINT,
782    );
783    ok_or!(self, ok)
784  }
785
786  /// Setup parameters of linear gradient fills.
787  pub fn fill_linear_gradient(&mut self, c1: Color, c2: Color, start: Pos, end: Pos) -> Result<&mut Self> {
788    let stops = [(c1, 0.0), (c2, 1.0)];
789    self.fill_linear_gradients(&stops, start, end)
790  }
791
792  /// Setup parameters of linear gradient fills using multiple colors and color stop positions `(0.0 ... 1.0)`.
793  pub fn fill_linear_gradients(&mut self, colors: &[(Color, Dim)], start: Pos, end: Pos) -> Result<&mut Self> {
794    let _ = ::std::mem::transmute::<SC_COLOR_STOP, (Color, Dim)>;
795    let ok = (_GAPI.gFillGradientLinear)(
796      self.0,
797      start.0,
798      start.1,
799      end.0,
800      end.1,
801      colors.as_ptr() as *const SC_COLOR_STOP,
802      colors.len() as UINT,
803    );
804    ok_or!(self, ok)
805  }
806
807  /// Setup parameters of a radial gradient of lines.
808  pub fn line_radial_gradient(&mut self, point: Pos, radii: (Dim, Dim), c1: Color, c2: Color) -> Result<&mut Self> {
809    let stops = [(c1, 0.0), (c2, 1.0)];
810    self.line_radial_gradients(point, radii, &stops)
811  }
812
813  /// Setup parameters of a radial gradient of lines using multiple colors and color stop positions `(0.0 ... 1.0)`.
814  pub fn line_radial_gradients(&mut self, point: Pos, radii: (Dim, Dim), colors: &[(Color, Dim)]) -> Result<&mut Self> {
815    let _ = ::std::mem::transmute::<SC_COLOR_STOP, (Color, Dim)>;
816    let ok = (_GAPI.gLineGradientRadial)(
817      self.0,
818      point.0,
819      point.1,
820      radii.0,
821      radii.1,
822      colors.as_ptr() as *const SC_COLOR_STOP,
823      colors.len() as UINT,
824    );
825    ok_or!(self, ok)
826  }
827
828  /// Setup parameters of radial gradient of fills.
829  pub fn fill_radial_gradient(&mut self, c1: Color, c2: Color, point: Pos, radii: (Dim, Dim)) -> Result<&mut Self> {
830    let stops = [(c1, 0.0), (c2, 1.0)];
831    self.fill_radial_gradients(&stops, point, radii)
832  }
833
834  /// Setup parameters of radial gradient of fills using multiple colors and color stop positions `(0.0 ... 1.0)`.
835  pub fn fill_radial_gradients(&mut self, colors: &[(Color, Dim)], point: Pos, radii: (Dim, Dim)) -> Result<&mut Self> {
836    let _ = ::std::mem::transmute::<SC_COLOR_STOP, (Color, Dim)>;
837    let ok = (_GAPI.gFillGradientRadial)(
838      self.0,
839      point.0,
840      point.1,
841      radii.0,
842      radii.1,
843      colors.as_ptr() as *const SC_COLOR_STOP,
844      colors.len() as UINT,
845    );
846    ok_or!(self, ok)
847  }
848}
849
850/// Affine transformations.
851impl Graphics {
852  /// Rotate coordinate system on `radians` angle.
853  pub fn rotate(&mut self, radians: Angle) -> Result<&mut Self> {
854    let ok = (_GAPI.gRotate)(self.0, radians, None, None);
855    ok_or!(self, ok)
856  }
857
858  /// Rotate coordinate system on `radians` angle around the `center`.
859  pub fn rotate_around(&mut self, radians: Angle, center: Pos) -> Result<&mut Self> {
860    let ok = (_GAPI.gRotate)(self.0, radians, Some(&center.0), Some(&center.1));
861    ok_or!(self, ok)
862  }
863
864  /// Move origin of coordinate system to the `(to_x, to_y)` point.
865  pub fn translate(&mut self, to_xy: Pos) -> Result<&mut Self> {
866    let ok = (_GAPI.gTranslate)(self.0, to_xy.0, to_xy.1);
867    ok_or!(self, ok)
868  }
869
870  /// Scale coordinate system.
871  ///
872  /// `(sc_x, sc_y)` are the scale factors in the horizontal and vertical directions respectively.
873  ///
874  /// Both parameters must be positive numbers.
875  /// Values smaller than `1.0` reduce the unit size and values larger than `1.0` increase the unit size.
876  pub fn scale(&mut self, sc_xy: Pos) -> Result<&mut Self> {
877    let ok = (_GAPI.gScale)(self.0, sc_xy.0, sc_xy.1);
878    ok_or!(self, ok)
879  }
880
881  /// Setup a skewing (shearing) transformation.
882  pub fn skew(&mut self, sh_xy: Pos) -> Result<&mut Self> {
883    let ok = (_GAPI.gSkew)(self.0, sh_xy.0, sh_xy.1);
884    ok_or!(self, ok)
885  }
886
887  /// Multiply the current transformation with the matrix described by the arguments.
888  ///
889  /// It allows to scale, rotate, move and skew the context
890  /// as described by:
891  ///
892  /// ```text
893  ///    scale_x  skew_y   move_x
894  /// [  skew_x   scale_y  move_y  ]
895  ///    0        0        1
896  /// ```
897  ///
898  /// where
899  ///
900  /// * `scale_x`, `scale_y`: horizontal and vertical scaling,
901  /// * `skew_x`, `skew_y`:   horizontal and vertical shearing (skewing),
902  /// * `move_x`, `move_y`:   horizontal and vertical moving.
903  ///
904  pub fn transform(&mut self, scale_by: Pos, skew_by: Pos, move_to: Pos) -> Result<&mut Self> {
905    // m11, m12, m21, m22, dx, dy
906    // scx, shx, shy, scy, dx, dy
907    let ok = (_GAPI.gTransform)(self.0, scale_by.0, skew_by.0, skew_by.1, scale_by.0, move_to.0, move_to.1);
908    ok_or!(self, ok)
909  }
910
911  /// Multiply the current transformation with the matrix described by the arguments.
912  ///
913  /// It allows to scale, rotate, move and skew the context
914  /// as described by:
915  ///
916  /// ```text
917  ///    m11   m21  dx
918  /// [  m12   m22  dy  ]
919  ///    0     0    1
920  /// ```
921  ///
922  /// * `m11` (`scale_x`): horizontal scaling
923  /// * `m12` (`skew_x`):  horizontal skewing
924  /// * `m21` (`skew_y`):  vertical skewing
925  /// * `m22` (`scale_y`): vertical scaling
926  /// * `dx`  (`move_x`):  horizontal moving
927  /// * `dy`  (`move_y`):  vertical moving
928  ///
929  pub fn transform_matrix(&mut self, m11: Dim, m12: Dim, m21: Dim, m22: Dim, dx: Dim, dy: Dim) -> Result<&mut Self> {
930    self.transform((m11, m22), (m12, m21), (dx, dy))
931  }
932}
933
934/// Coordinate space.
935impl Graphics {
936  /// Translate coordinates.
937  ///
938  /// Translates coordinates from a coordinate system defined by `rotate()`, `scale()`, `translate()` and/or `skew()`
939  /// to the screen coordinate system.
940  pub fn world_to_screen(&self, mut xy: Pos) -> Result<Pos> {
941    let ok = (_GAPI.gWorldToScreen)(self.0, &mut xy.0, &mut xy.1);
942    ok_or!(xy, ok)
943  }
944
945  /// Translate coordinates.
946  ///
947  /// Translates coordinates from a coordinate system defined by `rotate()`, `scale()`, `translate()` and/or `skew()`
948  /// to the screen coordinate system.
949  pub fn world_to_screen1(&self, mut length: Dim) -> Result<Dim> {
950    let mut dummy = 0.0;
951    let ok = (_GAPI.gWorldToScreen)(self.0, &mut length, &mut dummy);
952    ok_or!(length, ok)
953  }
954
955  /// Translate coordinates.
956  ///
957  /// Translates coordinates from screen coordinate system to the one defined by `rotate()`, `scale()`, `translate()` and/or `skew()`.
958  pub fn screen_to_world(&self, mut xy: Pos) -> Result<Pos> {
959    let ok = (_GAPI.gScreenToWorld)(self.0, &mut xy.0, &mut xy.1);
960    ok_or!(xy, ok)
961  }
962
963  /// Translate coordinates.
964  ///
965  /// Translates coordinates from screen coordinate system to the one defined by `rotate()`, `scale()`, `translate()` and/or `skew()`.
966  pub fn screen_to_world1(&self, mut length: Dim) -> Result<Dim> {
967    let mut dummy = 0.0;
968    let ok = (_GAPI.gScreenToWorld)(self.0, &mut length, &mut dummy);
969    ok_or!(length, ok)
970  }
971}
972
973/// Clipping.
974impl Graphics {
975  /// Push a clip layer defined by the specified rectangle bounds.
976  pub fn push_clip_box(&mut self, left_top: Pos, right_bottom: Pos, opacity: Option<f32>) -> Result<&mut Self> {
977    let ok = (_GAPI.gPushClipBox)(
978      self.0,
979      left_top.0,
980      left_top.1,
981      right_bottom.0,
982      right_bottom.1,
983      opacity.unwrap_or(1.0),
984    );
985    ok_or!(self, ok)
986  }
987
988  /// Push a clip layer defined by the specified `path` bounds.
989  pub fn push_clip_path(&mut self, path: &Path, opacity: Option<f32>) -> Result<&mut Self> {
990    let ok = (_GAPI.gPushClipPath)(self.0, path.0, opacity.unwrap_or(1.0));
991    ok_or!(self, ok)
992  }
993
994  /// Pop a clip layer set by previous `push_clip_box()` or `push_clip_path()` calls.
995  pub fn pop_clip(&mut self) -> Result<&mut Self> {
996    let ok = (_GAPI.gPopClip)(self.0);
997    ok_or!(self, ok)
998  }
999}
1000
1001/// Image and path rendering.
1002impl Graphics {
1003	/// Renders a text layout object at the position `(x,y)`.
1004	///
1005	/// `point_of`: number in the range `1..9`,
1006	/// defines what part of text layout corresponds to point `(x,y)`.
1007	/// For meaning of numbers see the numeric pad on keyboard.
1008	///
1009	pub fn draw_text(&mut self, text: &Text, pos: Pos, point_of: u32) -> Result<&mut Self> {
1010		let ok = (_GAPI.gDrawText)(self.0, text.0, pos.0, pos.1, point_of);
1011		ok_or!(self, ok)
1012	}
1013
1014  /// Draw the path object using current fill and stroke brushes.
1015  pub fn draw_path(&mut self, path: &Path, mode: DRAW_PATH) -> Result<&mut Self> {
1016    let ok = (_GAPI.gDrawPath)(self.0, path.0, mode);
1017    ok_or!(self, ok)
1018  }
1019
1020  /// Draw the whole image onto the graphics surface.
1021  ///
1022  /// With the current transformation applied (scale, rotation).
1023  ///
1024  /// Performance: expensive.
1025  pub fn draw_image(&mut self, image: &Image, pos: Pos) -> Result<&mut Self> {
1026    let ok = (_GAPI.gDrawImage)(self.0, image.0, pos.0, pos.1, None, None, None, None, None, None, None);
1027    ok_or!(self, ok)
1028  }
1029
1030  /// Draw a part of the image onto the graphics surface.
1031  ///
1032  /// With the current transformation applied (scale, rotation).
1033  ///
1034  /// Performance: expensive.
1035  pub fn draw_image_part(&mut self, image: &Image, dst_pos: Pos, dst_size: Size, src_pos: POINT, src_size: SIZE) -> Result<&mut Self> {
1036    let ix = src_pos.x as UINT;
1037    let iy = src_pos.y as UINT;
1038    let iw = src_size.cx as UINT;
1039    let ih = src_size.cy as UINT;
1040    let ok = (_GAPI.gDrawImage)(
1041      self.0,
1042      image.0,
1043      dst_pos.0,
1044      dst_pos.1,
1045      Some(&dst_size.0),
1046      Some(&dst_size.1),
1047      Some(&ix),
1048      Some(&iy),
1049      Some(&iw),
1050      Some(&ih),
1051      None,
1052    );
1053    ok_or!(self, ok)
1054  }
1055
1056  /// Blend the image with the graphics surface.
1057  ///
1058  /// No affine transformations.
1059  ///
1060  /// Performance: less expensive.
1061  pub fn blend_image(&mut self, image: &Image, dst_pos: Pos, opacity: f32) -> Result<&mut Self> {
1062    let ok = (_GAPI.gDrawImage)(
1063      self.0,
1064      image.0,
1065      dst_pos.0,
1066      dst_pos.1,
1067      None,
1068      None,
1069      None,
1070      None,
1071      None,
1072      None,
1073      Some(&opacity),
1074    );
1075    ok_or!(self, ok)
1076  }
1077
1078  /// Blend a part of the image with the graphics surface.
1079  ///
1080  /// No affine transformations.
1081  ///
1082  /// Performance: less expensive.
1083  pub fn blend_image_part(&mut self, image: &Image, dst_pos: Pos, opacity: f32, src_pos: POINT, src_size: SIZE) -> Result<&mut Self> {
1084    let ix = src_pos.x as UINT;
1085    let iy = src_pos.y as UINT;
1086    let iw = src_size.cx as UINT;
1087    let ih = src_size.cy as UINT;
1088    let ok = (_GAPI.gDrawImage)(
1089      self.0,
1090      image.0,
1091      dst_pos.0,
1092      dst_pos.1,
1093      None,
1094      None,
1095      Some(&ix),
1096      Some(&iy),
1097      Some(&iw),
1098      Some(&ih),
1099      Some(&opacity),
1100    );
1101    ok_or!(self, ok)
1102  }
1103}