cairo/
patterns.rs

1// Copyright 2013-2015, The Gtk-rs Project Developers.
2// See the COPYRIGHT file at the top-level directory of this distribution.
3// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
4
5use enums::MeshCorner;
6use enums::{Extend, Filter, PatternType, Status};
7use ffi;
8use ffi::{cairo_pattern_t, cairo_surface_t};
9use libc::{c_double, c_int, c_uint};
10use std::convert::TryFrom;
11use std::fmt;
12use std::ops::Deref;
13use std::ptr;
14use {Matrix, Path, Surface};
15
16// See http://cairographics.org/manual/bindings-patterns.html for more info
17#[derive(Debug)]
18pub struct Pattern {
19    pointer: *mut cairo_pattern_t,
20}
21
22impl fmt::Display for Pattern {
23    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24        write!(f, "Pattern")
25    }
26}
27
28impl Pattern {
29    user_data_methods! {
30        ffi::cairo_pattern_get_user_data,
31        ffi::cairo_pattern_set_user_data,
32    }
33
34    pub fn to_raw_none(&self) -> *mut cairo_pattern_t {
35        self.pointer
36    }
37
38    pub unsafe fn from_raw_none(pointer: *mut cairo_pattern_t) -> Pattern {
39        ffi::cairo_pattern_reference(pointer);
40        Self::from_raw_full(pointer)
41    }
42
43    pub unsafe fn from_raw_full(pointer: *mut cairo_pattern_t) -> Pattern {
44        Pattern { pointer }
45    }
46
47    pub fn get_type(&self) -> PatternType {
48        unsafe { ffi::cairo_pattern_get_type(self.pointer).into() }
49    }
50
51    pub fn ensure_status(&self) {
52        self.status().ensure_valid();
53    }
54
55    pub fn status(&self) -> Status {
56        unsafe { Status::from(ffi::cairo_pattern_status(self.pointer)) }
57    }
58
59    pub fn get_reference_count(&self) -> isize {
60        unsafe { ffi::cairo_pattern_get_reference_count(self.pointer) as isize }
61    }
62
63    pub fn set_extend(&self, extend: Extend) {
64        unsafe { ffi::cairo_pattern_set_extend(self.pointer, extend.into()) }
65    }
66
67    pub fn get_extend(&self) -> Extend {
68        unsafe { Extend::from(ffi::cairo_pattern_get_extend(self.pointer)) }
69    }
70
71    pub fn set_filter(&self, filter: Filter) {
72        unsafe { ffi::cairo_pattern_set_filter(self.pointer, filter.into()) }
73    }
74
75    pub fn get_filter(&self) -> Filter {
76        unsafe { Filter::from(ffi::cairo_pattern_get_filter(self.pointer)) }
77    }
78
79    pub fn set_matrix(&self, matrix: Matrix) {
80        unsafe { ffi::cairo_pattern_set_matrix(self.pointer, matrix.ptr()) }
81    }
82
83    pub fn get_matrix(&self) -> Matrix {
84        let mut matrix = Matrix::null();
85        unsafe {
86            ffi::cairo_pattern_get_matrix(self.pointer, matrix.mut_ptr());
87        }
88        matrix
89    }
90}
91
92impl Clone for Pattern {
93    fn clone(&self) -> Self {
94        Pattern {
95            pointer: unsafe { ffi::cairo_pattern_reference(self.pointer) },
96        }
97    }
98}
99
100impl Drop for Pattern {
101    fn drop(&mut self) {
102        unsafe { ffi::cairo_pattern_destroy(self.pointer) }
103    }
104}
105
106macro_rules! convert {
107    ($source: ident => $dest: ident = $( $variant: ident )|+ $( ($intermediate: ident) )*) => {
108        impl TryFrom<$source> for $dest {
109            type Error = $source;
110
111            fn try_from(pattern: $source) -> Result<Self, $source> {
112                if $( pattern.get_type() == PatternType::$variant )||+ {
113                    $(
114                        let pattern = $intermediate(pattern);
115                    )*
116                    Ok($dest(pattern))
117                }
118                else {
119                    Err(pattern)
120                }
121            }
122        }
123    };
124}
125
126macro_rules! pattern_type(
127    //Signals without arguments
128    ($pattern_type:ident $( = $variant: ident)*) => (
129
130        #[derive(Debug, Clone)]
131        pub struct $pattern_type(Pattern);
132
133        impl Deref for $pattern_type {
134            type Target = Pattern;
135
136            fn deref(&self) -> &Pattern {
137                &self.0
138            }
139        }
140
141        impl fmt::Display for $pattern_type {
142            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143                write!(f, stringify!($pattern_type))
144            }
145        }
146
147        $(
148            convert!(Pattern => $pattern_type = $variant);
149        )*
150    );
151);
152
153pattern_type!(SolidPattern = Solid);
154
155impl SolidPattern {
156    pub fn from_rgb(red: f64, green: f64, blue: f64) -> SolidPattern {
157        unsafe {
158            SolidPattern(Pattern::from_raw_full(ffi::cairo_pattern_create_rgb(
159                red, green, blue,
160            )))
161        }
162    }
163
164    pub fn from_rgba(red: f64, green: f64, blue: f64, alpha: f64) -> SolidPattern {
165        unsafe {
166            SolidPattern(Pattern::from_raw_full(ffi::cairo_pattern_create_rgba(
167                red, green, blue, alpha,
168            )))
169        }
170    }
171
172    pub fn get_rgba(&self) -> (f64, f64, f64, f64) {
173        unsafe {
174            let mut red = 0.0;
175            let mut green = 0.0;
176            let mut blue = 0.0;
177            let mut alpha = 0.0;
178
179            Status::from(ffi::cairo_pattern_get_rgba(
180                self.pointer,
181                &mut red,
182                &mut green,
183                &mut blue,
184                &mut alpha,
185            ))
186            .ensure_valid();
187
188            (red, green, blue, alpha)
189        }
190    }
191}
192
193pattern_type!(Gradient);
194convert!(Pattern => Gradient = LinearGradient | RadialGradient);
195
196impl Gradient {
197    pub fn add_color_stop_rgb(&self, offset: f64, red: f64, green: f64, blue: f64) {
198        unsafe { ffi::cairo_pattern_add_color_stop_rgb(self.pointer, offset, red, green, blue) }
199    }
200
201    pub fn add_color_stop_rgba(&self, offset: f64, red: f64, green: f64, blue: f64, alpha: f64) {
202        unsafe {
203            ffi::cairo_pattern_add_color_stop_rgba(self.pointer, offset, red, green, blue, alpha)
204        }
205    }
206
207    pub fn get_color_stop_count(&self) -> isize {
208        unsafe {
209            let mut count = 0;
210            let result = ffi::cairo_pattern_get_color_stop_count(self.pointer, &mut count);
211
212            Status::from(result).ensure_valid(); // Not sure if these are needed
213            count as isize
214        }
215    }
216
217    pub fn get_color_stop_rgba(&self, index: isize) -> (f64, f64, f64, f64, f64) {
218        unsafe {
219            let mut offset = 0.0;
220            let mut red = 0.0;
221            let mut green = 0.0;
222            let mut blue = 0.0;
223            let mut alpha = 0.0;
224
225            Status::from(ffi::cairo_pattern_get_color_stop_rgba(
226                self.pointer,
227                index as c_int,
228                &mut offset,
229                &mut red,
230                &mut green,
231                &mut blue,
232                &mut alpha,
233            ))
234            .ensure_valid();
235            (offset, red, green, blue, alpha)
236        }
237    }
238}
239
240macro_rules! gradient_type {
241    ($gradient_type: ident) => {
242        #[derive(Debug, Clone)]
243        pub struct $gradient_type(Gradient);
244
245        impl Deref for $gradient_type {
246            type Target = Gradient;
247
248            fn deref(&self) -> &Gradient {
249                &self.0
250            }
251        }
252
253        impl fmt::Display for $gradient_type {
254            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
255                write!(f, stringify!($gradient_type))
256            }
257        }
258
259        convert!(Pattern => $gradient_type = $gradient_type (Gradient));
260        convert!(Gradient => $gradient_type = $gradient_type);
261    }
262}
263
264gradient_type!(LinearGradient);
265
266impl LinearGradient {
267    pub fn new(x0: f64, y0: f64, x1: f64, y1: f64) -> LinearGradient {
268        unsafe {
269            LinearGradient(Gradient(Pattern::from_raw_full(
270                ffi::cairo_pattern_create_linear(x0, y0, x1, y1),
271            )))
272        }
273    }
274
275    pub fn get_linear_points(&self) -> (f64, f64, f64, f64) {
276        unsafe {
277            let mut x0 = 0.0;
278            let mut y0 = 0.0;
279            let mut x1 = 0.0;
280            let mut y1 = 0.0;
281
282            Status::from(ffi::cairo_pattern_get_linear_points(
283                self.pointer,
284                &mut x0,
285                &mut y0,
286                &mut x1,
287                &mut y1,
288            ))
289            .ensure_valid();
290            (x0, y0, x1, y1)
291        }
292    }
293}
294
295gradient_type!(RadialGradient);
296
297impl RadialGradient {
298    pub fn new(x0: f64, y0: f64, r0: f64, x1: f64, y1: f64, r1: f64) -> RadialGradient {
299        unsafe {
300            RadialGradient(Gradient(Pattern::from_raw_full(
301                ffi::cairo_pattern_create_radial(x0, y0, r0, x1, y1, r1),
302            )))
303        }
304    }
305
306    pub fn get_radial_circles(&self) -> (f64, f64, f64, f64, f64, f64) {
307        unsafe {
308            let mut x0 = 0.0;
309            let mut y0 = 0.0;
310            let mut r0 = 0.0;
311            let mut x1 = 0.0;
312            let mut y1 = 0.0;
313            let mut r1 = 0.0;
314
315            Status::from(ffi::cairo_pattern_get_radial_circles(
316                self.pointer,
317                &mut x0,
318                &mut y0,
319                &mut r0,
320                &mut x1,
321                &mut y1,
322                &mut r1,
323            ))
324            .ensure_valid();
325            (x0, y0, r0, x1, y1, r1)
326        }
327    }
328}
329
330pattern_type!(SurfacePattern = Surface);
331
332impl SurfacePattern {
333    pub fn create(surface: &Surface) -> SurfacePattern {
334        unsafe {
335            SurfacePattern(Pattern::from_raw_full(
336                ffi::cairo_pattern_create_for_surface(surface.to_raw_none()),
337            ))
338        }
339    }
340
341    pub fn get_surface(&self) -> Surface {
342        unsafe {
343            let mut surface_ptr: *mut cairo_surface_t = ptr::null_mut();
344            Status::from(ffi::cairo_pattern_get_surface(
345                self.pointer,
346                &mut surface_ptr,
347            ))
348            .ensure_valid();
349            Surface::from_raw_none(surface_ptr)
350        }
351    }
352}
353
354pattern_type!(Mesh = Mesh);
355
356impl Mesh {
357    pub fn new() -> Mesh {
358        unsafe { Mesh(Pattern::from_raw_full(ffi::cairo_pattern_create_mesh())) }
359    }
360
361    pub fn begin_patch(&self) {
362        unsafe { ffi::cairo_mesh_pattern_begin_patch(self.pointer) }
363        self.ensure_status();
364    }
365
366    pub fn end_patch(&self) {
367        unsafe { ffi::cairo_mesh_pattern_end_patch(self.pointer) }
368        self.ensure_status();
369    }
370
371    pub fn move_to(&self, x: f64, y: f64) {
372        unsafe { ffi::cairo_mesh_pattern_move_to(self.pointer, x, y) }
373        self.ensure_status();
374    }
375
376    pub fn line_to(&self, x: f64, y: f64) {
377        unsafe { ffi::cairo_mesh_pattern_line_to(self.pointer, x, y) }
378        self.ensure_status();
379    }
380
381    pub fn curve_to(&self, x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64) {
382        unsafe { ffi::cairo_mesh_pattern_curve_to(self.pointer, x1, y1, x2, y2, x3, y3) }
383        self.ensure_status();
384    }
385
386    pub fn set_control_point(&self, corner: MeshCorner, x: f64, y: f64) {
387        unsafe { ffi::cairo_mesh_pattern_set_control_point(self.pointer, corner.into(), x, y) }
388        self.ensure_status();
389    }
390
391    pub fn get_control_point(&self, patch_num: usize, corner: MeshCorner) -> (f64, f64) {
392        let mut x: c_double = 0.0;
393        let mut y: c_double = 0.0;
394
395        let status = unsafe {
396            ffi::cairo_mesh_pattern_get_control_point(
397                self.pointer,
398                patch_num as c_uint,
399                corner.into(),
400                &mut x,
401                &mut y,
402            )
403        };
404        Status::from(status).ensure_valid();
405        (x, y)
406    }
407
408    pub fn set_corner_color_rgb(&self, corner: MeshCorner, red: f64, green: f64, blue: f64) {
409        unsafe {
410            ffi::cairo_mesh_pattern_set_corner_color_rgb(
411                self.pointer,
412                corner.into(),
413                red,
414                green,
415                blue,
416            )
417        }
418        self.ensure_status();
419    }
420
421    pub fn set_corner_color_rgba(
422        &self,
423        corner: MeshCorner,
424        red: f64,
425        green: f64,
426        blue: f64,
427        alpha: f64,
428    ) {
429        unsafe {
430            ffi::cairo_mesh_pattern_set_corner_color_rgba(
431                self.pointer,
432                corner.into(),
433                red,
434                green,
435                blue,
436                alpha,
437            )
438        }
439        self.ensure_status();
440    }
441
442    pub fn get_corner_color_rgba(
443        &self,
444        patch_num: usize,
445        corner: MeshCorner,
446    ) -> (f64, f64, f64, f64) {
447        let mut red: c_double = 0.0;
448        let mut green: c_double = 0.0;
449        let mut blue: c_double = 0.0;
450        let mut alpha: c_double = 0.0;
451
452        let status = unsafe {
453            ffi::cairo_mesh_pattern_get_corner_color_rgba(
454                self.pointer,
455                patch_num as c_uint,
456                corner.into(),
457                &mut red,
458                &mut green,
459                &mut blue,
460                &mut alpha,
461            )
462        };
463        Status::from(status).ensure_valid();
464        (red, green, blue, alpha)
465    }
466
467    pub fn get_patch_count(&self) -> usize {
468        let mut count: c_uint = 0;
469        unsafe {
470            Status::from(ffi::cairo_mesh_pattern_get_patch_count(
471                self.pointer,
472                &mut count,
473            ))
474            .ensure_valid();
475        }
476        count as usize
477    }
478
479    pub fn get_path(&self, patch_num: usize) -> Path {
480        let path: Path = unsafe {
481            Path::from_raw_full(ffi::cairo_mesh_pattern_get_path(
482                self.pointer,
483                patch_num as c_uint,
484            ))
485        };
486        path.ensure_status();
487        path
488    }
489}
490
491#[test]
492fn try_from() {
493    let linear = LinearGradient::new(0., 0., 1., 1.);
494    let gradient = Gradient::clone(&linear);
495    let pattern = Pattern::clone(&linear);
496    assert!(Gradient::try_from(pattern.clone()).is_ok());
497    assert!(LinearGradient::try_from(gradient).is_ok());
498    assert!(LinearGradient::try_from(pattern).is_ok());
499}