fltk/draw/
routines.rs

1use super::types::Coord;
2use crate::enums::{Align, Color, ColorDepth, Cursor, Font, FrameType, Shortcut};
3use crate::image::RgbImage;
4use crate::prelude::*;
5use crate::surface::ImageSurface;
6use crate::utils::FlString;
7use fltk_sys::draw::*;
8use std::ffi::{CStr, CString};
9use std::mem;
10use std::os::raw;
11
12bitflags::bitflags! {
13    /// Defines the line styles supported by fltk
14    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
15    pub struct LineStyle: i32 {
16        /// Solid line
17        const Solid = 0;
18        /// Dash
19        const Dash = 1;
20        /// Dot
21        const Dot = 2;
22        /// Dash dot
23        const DashDot = 3;
24        /// Dash dot dot
25        const DashDotDot = 4;
26        /// Cap flat
27        const CapFlat = 0x100;
28        /// Cap round
29        const CapRound = 0x200;
30        /// Cap square
31        const CapSquare = 0x300;
32        /// Join miter
33        const JoinMiter = 0x1000;
34        /// Join round
35        const JoinRound = 0x2000;
36        /// Join bevel
37        const JoinBevel = 0x3000;
38    }
39}
40
41/// Opaque type around `Fl_Region`
42pub struct Region(pub(crate) *mut raw::c_void);
43
44/// Opaque type around `Fl_Offscreen`
45#[derive(Debug)]
46pub struct Offscreen {
47    inner: *mut raw::c_void,
48}
49
50#[cfg(not(feature = "single-threaded"))]
51unsafe impl Sync for Offscreen {}
52#[cfg(not(feature = "single-threaded"))]
53unsafe impl Send for Offscreen {}
54
55impl PartialEq for Offscreen {
56    fn eq(&self, other: &Self) -> bool {
57        self.inner == other.inner
58    }
59}
60
61impl Eq for Offscreen {}
62
63impl Offscreen {
64    /// Creates a new offscreen type
65    pub fn new(w: i32, h: i32) -> Option<Offscreen> {
66        unsafe {
67            let x = Fl_create_offscreen(w, h);
68            if x.is_null() {
69                None
70            } else {
71                Some(Offscreen { inner: x })
72            }
73        }
74    }
75
76    /// Creates an uninitialized offscreen type
77    /// # Safety
78    /// Leaves the offscreen in an uninitialized state
79    pub unsafe fn uninit() -> Offscreen {
80        Offscreen {
81            inner: std::ptr::null_mut(),
82        }
83    }
84
85    /// Begins drawing in the offscreen
86    pub fn begin(&self) {
87        assert!(!self.inner.is_null());
88        unsafe { Fl_begin_offscreen(self.inner) }
89    }
90
91    /// Ends drawing in the offscreen
92    pub fn end(&self) {
93        assert!(!self.inner.is_null());
94        unsafe { Fl_end_offscreen() }
95    }
96
97    /// Copies the offscreen
98    pub fn copy(&self, x: i32, y: i32, w: i32, h: i32, src_x: i32, src_y: i32) {
99        assert!(!self.inner.is_null());
100        unsafe { Fl_copy_offscreen(x, y, w, h, self.inner, src_x, src_y) }
101    }
102
103    /// Rescales the offscreen
104    pub fn rescale(&mut self) {
105        assert!(!self.inner.is_null());
106        unsafe { Fl_rescale_offscreen(&mut self.inner) }
107    }
108
109    /// Checks the validity of the offscreen
110    pub fn is_valid(&self) -> bool {
111        !self.inner.is_null()
112    }
113
114    /// Performs a shallow copy of the offscreen
115    /// # Safety
116    /// This can lead to multiple mutable references to the same offscreen
117    pub unsafe fn shallow_copy(&self) -> Offscreen {
118        assert!(!self.inner.is_null());
119        Offscreen { inner: self.inner }
120    }
121}
122
123impl Drop for Offscreen {
124    fn drop(&mut self) {
125        unsafe { Fl_delete_offscreen(self.inner) }
126    }
127}
128
129/// Shows a color map
130pub fn show_colormap(old_color: Color) -> Color {
131    unsafe { mem::transmute(Fl_show_colormap(old_color.bits())) }
132}
133
134/// Sets the color using rgb values
135pub fn set_color_rgb(r: u8, g: u8, b: u8) {
136    unsafe { Fl_set_color_rgb(r, g, b) }
137}
138
139/// Gets the last used color
140pub fn get_color() -> Color {
141    unsafe { mem::transmute(Fl_get_color()) }
142}
143
144/// Draws a line
145pub fn draw_line(x1: i32, y1: i32, x2: i32, y2: i32) {
146    unsafe {
147        Fl_line(x1, y1, x2, y2);
148    }
149}
150
151/// Draws a line from (x,y) to (x1,y1) and another from (x1,y1) to (x2,y2)
152pub fn draw_line2(pos1: Coord<i32>, pos2: Coord<i32>, pos3: Coord<i32>) {
153    unsafe { Fl_line2(pos1.0, pos1.1, pos2.0, pos2.1, pos3.0, pos3.1) }
154}
155
156/// Draws a point
157pub fn draw_point(x: i32, y: i32) {
158    unsafe { Fl_point(x, y) }
159}
160
161/// Draws a point
162pub fn draw_point2(pos: Coord<i32>) {
163    unsafe { Fl_point(pos.0, pos.1) }
164}
165
166/// Draws a rectangle
167pub fn draw_rect(x: i32, y: i32, w: i32, h: i32) {
168    unsafe { Fl_rect(x, y, w, h) }
169}
170
171/// Draws a rectangle with border color
172pub fn draw_rect_with_color(x: i32, y: i32, w: i32, h: i32, color: Color) {
173    unsafe { Fl_rect_with_color(x, y, w, h, color.bits()) }
174}
175
176/// Draws a non-filled 3-sided polygon
177pub fn draw_loop(x1: i32, y1: i32, x2: i32, y2: i32, x3: i32, y3: i32) {
178    unsafe {
179        Fl_loop(x1, y1, x2, y2, x3, y3);
180    }
181}
182
183/// Draws a non-filled 3-sided polygon
184pub fn draw_loop2(pos1: Coord<i32>, pos2: Coord<i32>, pos3: Coord<i32>) {
185    unsafe { Fl_loop(pos1.0, pos1.1, pos2.0, pos2.1, pos3.0, pos3.1) }
186}
187
188/// Draws a non-filled 4-sided polygon
189pub fn draw_loop3(pos1: Coord<i32>, pos2: Coord<i32>, pos3: Coord<i32>, pos4: Coord<i32>) {
190    unsafe {
191        Fl_loop2(
192            pos1.0, pos1.1, pos2.0, pos2.1, pos3.0, pos3.1, pos4.0, pos4.1,
193        )
194    }
195}
196
197/// Draws a filled rectangle
198pub fn draw_rect_fill(x: i32, y: i32, w: i32, h: i32, color: Color) {
199    unsafe { Fl_rectf_with_color(x, y, w, h, color.bits()) }
200}
201
202/// Draws a focus rectangle
203pub fn draw_focus_rect(x: i32, y: i32, w: i32, h: i32) {
204    unsafe { Fl_focus_rect(x, y, w, h) }
205}
206
207/// Sets the drawing color
208pub fn set_draw_hex_color(color: u32) {
209    unsafe {
210        crate::app::open_display();
211    }
212    let (r, g, b) = crate::utils::hex2rgb(color);
213    unsafe { Fl_set_color_rgb(r, g, b) }
214}
215
216/// Sets the drawing color
217pub fn set_draw_rgb_color(r: u8, g: u8, b: u8) {
218    unsafe {
219        crate::app::open_display();
220    }
221    unsafe { Fl_set_color_rgb(r, g, b) }
222}
223
224/// Sets the drawing color
225pub fn set_draw_color(color: Color) {
226    unsafe {
227        crate::app::open_display();
228    }
229    unsafe { Fl_set_color_int(color.bits()) }
230}
231
232/// Draws a circle
233pub fn draw_circle(x: f64, y: f64, r: f64) {
234    unsafe {
235        Fl_circle(x, y, r);
236    }
237}
238
239/// Draws an arc
240pub fn draw_arc(x: i32, y: i32, width: i32, height: i32, a: f64, b: f64) {
241    unsafe {
242        Fl_arc(x, y, width, height, a, b);
243    }
244}
245
246/// Draws an arc
247pub fn draw_arc2(x: f64, y: f64, r: f64, start: f64, end: f64) {
248    unsafe { Fl_arc2(x, y, r, start, end) }
249}
250
251/// Draws a filled pie
252pub fn draw_pie(x: i32, y: i32, width: i32, height: i32, a: f64, b: f64) {
253    unsafe {
254        Fl_pie(x, y, width, height, a, b);
255    }
256}
257
258/// Sets the line style
259///
260/// # Warning
261/// You are required to change this back to
262/// [`set_line_style(LineStyle::Solid, 0)`](crate::draw::set_line_style)
263/// after finishing
264pub fn set_line_style(style: LineStyle, width: i32) {
265    unsafe {
266        crate::app::open_display();
267        Fl_line_style(
268            style.bits(),
269            width,
270            std::ptr::null_mut() as *mut std::os::raw::c_char,
271        );
272    }
273}
274
275/// Limits drawing to a region
276pub fn push_clip(x: i32, y: i32, w: i32, h: i32) {
277    unsafe {
278        Fl_push_clip(x, y, w, h);
279    }
280}
281
282/// Puts the drawing back
283pub fn pop_clip() {
284    unsafe {
285        Fl_pop_clip();
286    }
287}
288
289/// Sets the clip region
290pub fn set_clip_region(r: Region) {
291    assert!(!r.0.is_null());
292    unsafe { Fl_set_clip_region(r.0) }
293}
294
295/// Gets the clip region
296pub fn clip_region() -> Region {
297    unsafe {
298        let ptr = Fl_clip_region();
299        assert!(!ptr.is_null());
300        Region(ptr)
301    }
302}
303
304/// Pushes an empty clip region onto the stack so nothing will be clipped
305pub fn push_no_clip() {
306    unsafe { Fl_push_no_clip() }
307}
308
309/// Returns whether the rectangle intersect with the current clip region
310pub fn not_clipped(x: i32, y: i32, w: i32, h: i32) -> bool {
311    unsafe { Fl_not_clipped(x, y, w, h) != 0 }
312}
313
314/// Restores the clip region
315pub fn restore_clip() {
316    unsafe { Fl_restore_clip() }
317}
318
319/// Transforms coordinate using the current transformation matrix
320pub fn transform_x(x: f64, y: f64) -> f64 {
321    unsafe { Fl_transform_x(x, y) }
322}
323
324/// Transforms coordinate using the current transformation matrix
325pub fn transform_y(x: f64, y: f64) -> f64 {
326    unsafe { Fl_transform_y(x, y) }
327}
328
329/// Transforms distance using current transformation matrix
330pub fn transform_dx(x: f64, y: f64) -> f64 {
331    unsafe { Fl_transform_dx(x, y) }
332}
333
334/// Transforms distance using current transformation matrix
335pub fn transform_dy(x: f64, y: f64) -> f64 {
336    unsafe { Fl_transform_dy(x, y) }
337}
338
339/// Adds coordinate pair to the vertex list without further transformations
340pub fn transformed_vertex(xf: f64, yf: f64) {
341    unsafe { Fl_transformed_vertex(xf, yf) }
342}
343
344/// Draws a filled rectangle
345pub fn draw_rectf(x: i32, y: i32, w: i32, h: i32) {
346    unsafe { Fl_rectf(x, y, w, h) }
347}
348
349/// Draws a filled rectangle with specified RGB color
350pub fn draw_rectf_with_rgb(
351    x: i32,
352    y: i32,
353    width: i32,
354    height: i32,
355    color_r: u8,
356    color_g: u8,
357    color_b: u8,
358) {
359    unsafe { Fl_rectf_with_rgb(x, y, width, height, color_r, color_g, color_b) }
360}
361
362/// Fills a 3-sided polygon. The polygon must be convex
363pub fn draw_polygon(x: i32, y: i32, x1: i32, y1: i32, x2: i32, y2: i32) {
364    unsafe { Fl_polygon(x, y, x1, y1, x2, y2) }
365}
366
367/// Fills a 3-sided polygon. The polygon must be convex
368pub fn draw_polygon2(pos1: Coord<i32>, pos2: Coord<i32>, pos3: Coord<i32>) {
369    unsafe { Fl_polygon(pos1.0, pos1.1, pos2.0, pos2.1, pos3.0, pos3.1) }
370}
371
372/// Fills a 4-sided polygon. The polygon must be convex
373pub fn draw_polygon3(pos1: Coord<i32>, pos2: Coord<i32>, pos3: Coord<i32>, pos4: Coord<i32>) {
374    unsafe {
375        Fl_polygon2(
376            pos1.0, pos1.1, pos2.0, pos2.1, pos3.0, pos3.1, pos4.0, pos4.1,
377        )
378    }
379}
380
381/// Adds a series of points on a Bezier curve to the path
382pub fn draw_curve(pos1: Coord<f64>, pos2: Coord<f64>, pos3: Coord<f64>, pos4: Coord<f64>) {
383    unsafe {
384        Fl_curve(
385            pos1.0, pos1.1, pos2.0, pos2.1, pos3.0, pos3.1, pos4.0, pos4.1,
386        )
387    }
388}
389
390/// Draws a horizontal line from (x,y) to (x1,y)
391pub fn draw_xyline(x: i32, y: i32, x1: i32) {
392    unsafe { Fl_xyline(x, y, x1) }
393}
394
395/// Draws a horizontal line from (x,y) to (x1,y), then vertical from (x1,y) to (x1,y2)
396pub fn draw_xyline2(x: i32, y: i32, x1: i32, y2: i32) {
397    unsafe { Fl_xyline2(x, y, x1, y2) }
398}
399
400/// Draws a horizontal line from (x,y) to (x1,y), then a vertical from (x1,y) to (x1,y2)
401/// and then another horizontal from (x1,y2) to (x3,y2)
402pub fn draw_xyline3(x: i32, y: i32, x1: i32, y2: i32, x3: i32) {
403    unsafe { Fl_xyline3(x, y, x1, y2, x3) }
404}
405
406/// Draws a vertical line from (x,y) to (x,y1)
407pub fn draw_yxline(x: i32, y: i32, y1: i32) {
408    unsafe { Fl_yxline(x, y, y1) }
409}
410
411/// Draws a vertical line from (x,y) to (x,y1), then a horizontal from (x,y1) to (x2,y1)
412pub fn draw_yxline2(x: i32, y: i32, y1: i32, x2: i32) {
413    unsafe { Fl_yxline2(x, y, y1, x2) }
414}
415
416/// Draws a vertical line from (x,y) to (x,y1) then a horizontal from (x,y1)
417/// to (x2,y1), then another vertical from (x2,y1) to (x2,y3)
418pub fn draw_yxline3(x: i32, y: i32, y1: i32, x2: i32, y3: i32) {
419    unsafe { Fl_yxline3(x, y, y1, x2, y3) }
420}
421
422/// Saves the current transformation matrix on the stack
423pub fn push_matrix() {
424    unsafe { Fl_push_matrix() }
425}
426
427/// Pops the current transformation matrix from the stack
428pub fn pop_matrix() {
429    unsafe { Fl_pop_matrix() }
430}
431
432/// Concatenates scaling transformation onto the current one
433pub fn scale_xy(x: f64, y: f64) {
434    unsafe { Fl_scale(x, y) }
435}
436
437/// Concatenates scaling transformation onto the current one for both x & y
438pub fn scale(val: f64) {
439    unsafe { Fl_scale2(val) }
440}
441
442/// Concatenates translation transformation onto the current one
443pub fn translate(x: f64, y: f64) {
444    unsafe { Fl_translate(x, y) }
445}
446
447/// Concatenates rotation transformation onto the current one
448pub fn rotate(d: f64) {
449    unsafe { Fl_rotate(d) }
450}
451
452/// Concatenates another transformation onto the current one
453pub fn mult_matrix(val_a: f64, val_b: f64, val_c: f64, val_d: f64, x: f64, y: f64) {
454    unsafe { Fl_mult_matrix(val_a, val_b, val_c, val_d, x, y) }
455}
456
457/// Starts drawing a list of points. Points are added to the list with `fl_vertex()`
458pub fn begin_points() {
459    unsafe { Fl_begin_points() }
460}
461
462/// Starts drawing a list of lines
463pub fn begin_line() {
464    unsafe { Fl_begin_line() }
465}
466
467/// Starts drawing a closed sequence of lines
468pub fn begin_loop() {
469    unsafe { Fl_begin_loop() }
470}
471
472/// Starts drawing a convex filled polygon
473pub fn begin_polygon() {
474    unsafe { Fl_begin_polygon() }
475}
476
477/// Adds a single vertex to the current path
478pub fn vertex(x: f64, y: f64) {
479    unsafe { Fl_vertex(x, y) }
480}
481
482/// Ends list of points, and draws
483pub fn end_points() {
484    unsafe { Fl_end_points() }
485}
486
487/// Ends list of lines, and draws
488pub fn end_line() {
489    unsafe { Fl_end_line() }
490}
491
492/// Ends closed sequence of lines, and draws
493pub fn end_loop() {
494    unsafe { Fl_end_loop() }
495}
496
497/// Ends closed sequence of lines, and draws
498pub fn end_polygon() {
499    unsafe { Fl_end_polygon() }
500}
501
502/// Starts drawing a complex filled polygon
503pub fn begin_complex_polygon() {
504    unsafe { Fl_begin_complex_polygon() }
505}
506
507/// Call gap() to separate loops of the path
508pub fn gap() {
509    unsafe { Fl_gap() }
510}
511
512/// Ends complex filled polygon, and draws
513pub fn end_complex_polygon() {
514    unsafe { Fl_end_complex_polygon() }
515}
516
517/// Sets the current font, which is then used in various drawing routines
518pub fn set_font(face: Font, fsize: i32) {
519    unsafe { Fl_set_draw_font(face.bits(), fsize) }
520}
521
522/// Gets the current font, which is used in various drawing routines
523pub fn font() -> Font {
524    unsafe { mem::transmute(Fl_font()) }
525}
526
527/// Gets the current font size, which is used in various drawing routines
528pub fn size() -> i32 {
529    unsafe { Fl_size() }
530}
531
532/// Returns the recommended minimum line spacing for the current font
533pub fn height() -> i32 {
534    unsafe { Fl_height() }
535}
536
537/// Sets the line spacing for the current font
538pub fn set_height(font: Font, size: i32) {
539    unsafe {
540        Fl_set_height(font.bits(), size);
541    }
542}
543
544/// Returns the recommended distance above the bottom of a height() tall box to
545/// draw the text at so it looks centered vertically in that box
546pub fn descent() -> i32 {
547    unsafe { Fl_descent() }
548}
549
550/// Returns the typographical width of a string
551pub fn width(txt: &str) -> f64 {
552    let txt = CString::safe_new(txt);
553    unsafe { Fl_width(txt.as_ptr()) }
554}
555
556/// Returns the typographical width of a sequence of n characters
557pub fn width2(txt: &str, n: i32) -> f64 {
558    let txt = CString::safe_new(txt);
559    unsafe { Fl_width2(txt.as_ptr(), n) }
560}
561
562/// Measure the width and height of a text
563pub fn measure(txt: &str, draw_symbols: bool) -> (i32, i32) {
564    let txt = CString::safe_new(txt);
565    let (mut x, mut y) = (0, 0);
566    unsafe {
567        Fl_measure(txt.as_ptr(), &mut x, &mut y, draw_symbols as i32);
568    }
569    (x, y)
570}
571
572/// Measure the width and height of a text
573///
574/// If `width` is non-zero, it will wrap to that width
575pub fn wrap_measure(txt: &str, width: i32, draw_symbols: bool) -> (i32, i32) {
576    let txt = CString::safe_new(txt);
577    let (mut x, mut y) = (width, 0);
578    unsafe {
579        Fl_measure(txt.as_ptr(), &mut x, &mut y, draw_symbols as i32);
580    }
581    (x, y)
582}
583
584/// Measure the coordinates and size of the text where a bounding box using the
585/// returned data would fit the text
586pub fn text_extents(txt: &str) -> (i32, i32, i32, i32) {
587    let txt = CString::safe_new(txt);
588    let (mut x, mut y, mut w, mut h) = (0, 0, 0, 0);
589    unsafe {
590        Fl_text_extents(txt.as_ptr(), &mut x, &mut y, &mut w, &mut h);
591    }
592    (x, y, w, h)
593}
594
595/// Returns the typographical width of a single character
596pub fn char_width(c: char) -> f64 {
597    unsafe { Fl_width3(c as u32) }
598}
599
600/// Converts text from Windows/X11 latin1 character set to local encoding
601pub fn latin1_to_local(txt: &str, n: i32) -> String {
602    let txt = CString::safe_new(txt);
603    unsafe {
604        let x = Fl_latin1_to_local(txt.as_ptr(), n);
605        assert!(!x.is_null());
606        CStr::from_ptr(x as *mut raw::c_char)
607            .to_string_lossy()
608            .to_string()
609    }
610}
611
612/// Converts text from local encoding to Windowx/X11 latin1 character set
613pub fn local_to_latin1(txt: &str, n: i32) -> String {
614    let txt = CString::safe_new(txt);
615    unsafe {
616        let x = Fl_local_to_latin1(txt.as_ptr(), n);
617        assert!(!x.is_null());
618        CStr::from_ptr(x as *mut raw::c_char)
619            .to_string_lossy()
620            .to_string()
621    }
622}
623
624/// Draws a string starting at the given x, y location
625pub fn draw_text(txt: &str, x: i32, y: i32) {
626    if size() == -1 && txt.len() == 1 {
627        return;
628    }
629    let txt = CString::safe_new(txt);
630    unsafe { Fl_draw(txt.as_ptr(), x, y) }
631}
632
633/// Draws a string starting at the given x, y location with width and height and alignment
634pub fn draw_text2(string: &str, x: i32, y: i32, width: i32, height: i32, align: Align) {
635    if size() == -1 && string.len() == 1 {
636        return;
637    }
638    let s = CString::safe_new(string);
639    unsafe { Fl_draw_text2(s.as_ptr(), x, y, width, height, align.bits()) }
640}
641
642/// Draws a string starting at the given x, y location, rotated to an angle
643pub fn draw_text_angled(angle: i32, txt: &str, x: i32, y: i32) {
644    if size() == -1 && txt.len() == 1 {
645        return;
646    }
647    let txt = CString::safe_new(txt);
648    unsafe { Fl_draw2(angle, txt.as_ptr(), x, y) }
649}
650
651/// Draws a UTF-8 string right to left starting at the given x, y location
652pub fn rtl_draw(txt: &str, x: i32, y: i32) {
653    if size() == -1 && txt.len() == 1 {
654        return;
655    }
656    let len = txt.len() as i32;
657    let txt = CString::safe_new(txt);
658    unsafe { Fl_rtl_draw(txt.as_ptr(), len, x, y) }
659}
660
661/// Draws a series of line segments around the given box.
662///
663/// The string must contain groups of 4 letters which specify one of 24 standard
664/// grayscale values, where 'A' is black and 'X' is white.
665/// The order of each set of 4 characters is: top, left, bottom, right.
666pub fn draw_frame(string: &str, x: i32, y: i32, width: i32, height: i32) {
667    assert!(string.len() % 4 == 0);
668    let s = CString::safe_new(string);
669    unsafe { Fl_frame(s.as_ptr(), x, y, width, height) }
670}
671
672/// Draws a series of line segments around the given box
673///
674/// Differs from frame() by the order of the line segments which is bottom, right, top, left.
675pub fn draw_frame2(string: &str, x: i32, y: i32, width: i32, height: i32) {
676    assert!(string.len() % 4 == 0);
677    let s = CString::safe_new(string);
678    unsafe { Fl_frame2(s.as_ptr(), x, y, width, height) }
679}
680
681/// Draws a box given the box type, size, position and color
682pub fn draw_box(box_type: FrameType, x: i32, y: i32, w: i32, h: i32, color: Color) {
683    unsafe { Fl_draw_box(box_type.as_i32(), x, y, w, h, color.bits()) }
684}
685
686/// Checks whether platform supports true alpha blending for RGBA images
687pub fn can_do_alpha_blending() -> bool {
688    unsafe { Fl_can_do_alpha_blending() != 0 }
689}
690
691/// Get a human-readable string from a shortcut value
692pub fn shortcut_label(shortcut: Shortcut) -> String {
693    unsafe {
694        let x = Fl_shortcut_label(shortcut.bits() as u32);
695        assert!(!x.is_null());
696        CStr::from_ptr(x as *mut raw::c_char)
697            .to_string_lossy()
698            .to_string()
699    }
700}
701
702/// Draws a selection rectangle, erasing a previous one by XOR'ing it first.
703pub fn overlay_rect(x: i32, y: i32, w: i32, h: i32) {
704    unsafe { Fl_overlay_rect(x, y, w, h) }
705}
706
707/// Erase a selection rectangle without drawing a new one
708pub fn overlay_clear() {
709    unsafe { Fl_overlay_clear() }
710}
711
712/// Sets the cursor style
713pub fn set_cursor(cursor: Cursor) {
714    unsafe { Fl_set_cursor(cursor as i32) }
715}
716
717/// Sets the cursor style
718pub fn set_cursor_with_color(cursor: Cursor, fg: Color, bg: Color) {
719    unsafe { Fl_set_cursor2(cursor as i32, fg.bits() as i32, bg.bits() as i32) }
720}
721
722/// Sets the status
723pub fn set_status(x: i32, y: i32, w: i32, h: i32) {
724    unsafe { Fl_set_status(x, y, w, h) }
725}
726
727/// Sets spot within the window
728pub fn set_spot<Win: WindowExt>(font: Font, size: i32, x: i32, y: i32, w: i32, h: i32, win: &Win) {
729    unsafe {
730        Fl_set_spot(
731            font.bits(),
732            size,
733            x,
734            y,
735            w,
736            h,
737            win.as_widget_ptr() as *mut raw::c_void,
738        )
739    }
740}
741
742/// Resets the spot within the window
743pub fn reset_spot() {
744    unsafe { Fl_reset_spot() }
745}
746
747/**
748    Captures the window and returns raw data.
749    Example usage:
750    ```rust,no_run
751    use fltk::{prelude::*, *};
752    let mut win = window::Window::default();
753    let image = draw::capture_window(&mut win).unwrap();
754    ```
755    # Errors
756    The api can fail to capture the window as an image
757*/
758pub fn capture_window<Win: WindowExt>(win: &mut Win) -> Result<RgbImage, FltkError> {
759    let cp = win.width() * win.height() * 3;
760    win.show();
761    unsafe {
762        let x = Fl_read_image(std::ptr::null_mut(), 0, 0, win.width(), win.height(), 0);
763        if x.is_null() {
764            Err(FltkError::Internal(FltkErrorKind::FailedOperation))
765        } else {
766            let x = std::slice::from_raw_parts(x, cp as usize);
767            Ok(RgbImage::new(
768                x,
769                win.width(),
770                win.height(),
771                ColorDepth::Rgb8,
772            )?)
773        }
774    }
775}
776
777/**
778    Captures part of the window and returns raw data.
779    Example usage:
780    ```rust,no_run
781    use fltk::{prelude::*, *};
782    let mut win = window::Window::default();
783    let image = draw::capture_window(&mut win).unwrap();
784    ```
785    # Errors
786    The api can fail to capture the window as an image
787*/
788pub fn capture_window_part<Win: WindowExt>(
789    win: &mut Win,
790    x: i32,
791    y: i32,
792    w: i32,
793    h: i32,
794) -> Result<RgbImage, FltkError> {
795    let cp = win.width() * win.height() * 3;
796    win.show();
797    unsafe {
798        let x = Fl_capture_window_part(win.as_widget_ptr() as _, x, y, w, h);
799        if x.is_null() {
800            Err(FltkError::Internal(FltkErrorKind::FailedOperation))
801        } else {
802            let x = std::slice::from_raw_parts(x, cp as usize);
803            Ok(RgbImage::new(x, w, h, ColorDepth::Rgb8)?)
804        }
805    }
806}
807
808/**
809    Captures the offscreen and returns raw data.
810    Example usage:
811    ```rust,no_run
812    use fltk::{prelude::*, *};
813    let mut offs = draw::Offscreen::new(100, 100).unwrap();
814    let image = draw::capture_offscreen(&mut offs, 100, 100).unwrap();
815    ```
816    # Errors
817    The api can fail to capture the offscreen object as an image
818*/
819pub fn capture_offscreen(offs: &mut Offscreen, w: i32, h: i32) -> Result<RgbImage, FltkError> {
820    let cp = w * h * 3;
821    unsafe {
822        offs.begin();
823        let x = Fl_read_image(std::ptr::null_mut(), 0, 0, w, h, 0);
824        offs.end();
825        if x.is_null() {
826            Err(FltkError::Internal(FltkErrorKind::FailedOperation))
827        } else {
828            let x = std::slice::from_raw_parts(x, cp as usize);
829            Ok(RgbImage::new(x, w, h, ColorDepth::Rgb8)?)
830        }
831    }
832}
833
834/**
835    Captures the image surface object and returns raw data.
836    Example usage:
837    ```rust,no_run
838    use fltk::{prelude::*, *};
839    let mut surface = surface::ImageSurface::new(100, 100, false);
840    let image = draw::capture_surface(&mut surface, 100, 100).unwrap();
841    ```
842    # Errors
843    The api can fail to capture the image surface as an image
844*/
845pub fn capture_surface(surface: &ImageSurface, w: i32, h: i32) -> Result<RgbImage, FltkError> {
846    let cp = w * h * 3;
847    unsafe {
848        ImageSurface::push_current(surface);
849        let x = Fl_read_image(std::ptr::null_mut(), 0, 0, w, h, 0);
850        ImageSurface::pop_current();
851        if x.is_null() {
852            Err(FltkError::Internal(FltkErrorKind::FailedOperation))
853        } else {
854            let x = std::slice::from_raw_parts(x, cp as usize);
855            Ok(RgbImage::new(x, w, h, ColorDepth::Rgb8)?)
856        }
857    }
858}
859
860/// Draw a framebuffer (rgba) into a widget
861/// # Errors
862/// Errors on invalid or unsupported image formats
863pub fn draw_rgba<'a, T: WidgetBase>(wid: &'a mut T, fb: &'a [u8]) -> Result<(), FltkError> {
864    let width = wid.width();
865    let height = wid.height();
866    let mut img = crate::image::RgbImage::new(fb, width, height, ColorDepth::Rgba8)?;
867    wid.draw(move |s| {
868        let x = s.x();
869        let y = s.y();
870        let w = s.width();
871        let h = s.height();
872        img.scale(w, h, false, true);
873        img.draw(x, y, w, h);
874    });
875    Ok(())
876}
877
878/// Draw a framebuffer (rgba) into a widget
879/// # Safety
880/// The data passed should be valid and outlive the widget
881pub unsafe fn draw_rgba_nocopy<T: WidgetBase>(wid: &mut T, fb: &[u8]) {
882    let ptr = fb.as_ptr();
883    let len = fb.len();
884    let width = wid.width();
885    let height = wid.height();
886    wid.draw(move |s| {
887        let x = s.x();
888        let y = s.y();
889        let w = s.width();
890        let h = s.height();
891        if let Ok(mut img) = crate::image::RgbImage::from_data(
892            std::slice::from_raw_parts(ptr, len),
893            width,
894            height,
895            ColorDepth::Rgba8,
896        ) {
897            img.scale(w, h, false, true);
898            img.draw(x, y, w, h);
899        }
900    });
901}
902
903/// Draw a framebuffer (rgba) into a widget
904/// # Errors
905/// Errors on invalid or unsupported image formats
906pub fn draw_rgb<'a, T: WidgetBase>(wid: &'a mut T, fb: &'a [u8]) -> Result<(), FltkError> {
907    let width = wid.width();
908    let height = wid.height();
909    let mut img = crate::image::RgbImage::new(fb, width, height, ColorDepth::Rgb8)?;
910    wid.draw(move |s| {
911        let x = s.x();
912        let y = s.y();
913        let w = s.width();
914        let h = s.height();
915        img.scale(w, h, false, true);
916        img.draw(x, y, w, h);
917    });
918    Ok(())
919}
920
921/// Draw a framebuffer (rgba) into a widget
922/// # Safety
923/// The data passed should be valid and outlive the widget
924pub unsafe fn draw_rgb_nocopy<T: WidgetBase>(wid: &mut T, fb: &[u8]) {
925    let ptr = fb.as_ptr();
926    let len = fb.len();
927    let width = wid.width();
928    let height = wid.height();
929    wid.draw(move |s| {
930        let x = s.x();
931        let y = s.y();
932        let w = s.width();
933        let h = s.height();
934        if let Ok(mut img) = crate::image::RgbImage::from_data(
935            std::slice::from_raw_parts(ptr, len),
936            width,
937            height,
938            ColorDepth::Rgb8,
939        ) {
940            img.scale(w, h, false, true);
941            img.draw(x, y, w, h);
942        }
943    });
944}
945
946/// Draw an image into a widget.
947/// Requires a call to [`app::set_visual(Mode::Rgb8).unwrap()`](`crate::app::set_visual`).
948/// Doesn't support transparency, for that you would have to use RgbImage.
949/// # Errors
950/// Errors on invalid or unsupported image formats
951pub fn draw_image(
952    data: &[u8],
953    x: i32,
954    y: i32,
955    w: i32,
956    h: i32,
957    depth: ColorDepth,
958) -> Result<(), FltkError> {
959    let sz = (w * h * depth as i32) as usize;
960    if sz > data.len() {
961        return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
962    }
963    unsafe {
964        Fl_draw_image(data.as_ptr(), x, y, w, h, depth as i32, 0);
965    }
966    Ok(())
967}
968
969/// Draw a check mark
970pub fn draw_check(x: i32, y: i32, w: i32, h: i32, col: Color) {
971    unsafe {
972        Fl_draw_check(x, y, w, h, col.bits());
973    }
974}
975
976/// Draw an image into a widget.
977/// Requires a call to [`app::set_visual(Mode::Rgb8).unwrap()`](`crate::app::set_visual`).
978/// A negative depth flips the image horizontally,
979/// while a negative line data flips it vertically.
980/// Allows passing a line-data parameter
981/// # Errors
982/// Errors on invalid or unsupported image formats
983/// # Safety
984/// Passing wrong line data can read to over or underflow
985pub unsafe fn draw_image2(data: &[u8], x: i32, y: i32, w: i32, h: i32, depth: i32, line_data: i32) {
986    Fl_draw_image(data.as_ptr(), x, y, w, h, depth, line_data);
987}
988
989/// Draws a rounded box
990pub fn draw_rbox(x: i32, y: i32, w: i32, h: i32, max_radius: i32, fill: bool, col: Color) {
991    let max_radius = if max_radius < 0 { 0 } else { max_radius };
992    let offset: [f64; 5] = [0.0, 0.07612, 0.29289, 0.61732, 1.0];
993    let mut rs = w * 2 / 5;
994    let rsy = h * 2 / 5;
995    if rs > rsy {
996        rs = rsy;
997    }
998    if rs > max_radius {
999        rs = max_radius;
1000    }
1001    if rs == 5 {
1002        rs = 4;
1003    }
1004    if rs == 7 {
1005        rs = 8;
1006    }
1007
1008    let rs = rs as f64;
1009    let x = x as f64;
1010    let y = y as f64;
1011    let w = w as f64;
1012    let h = h as f64;
1013    let old_col = get_color();
1014    let len = offset.len();
1015
1016    set_draw_color(col);
1017    if fill {
1018        begin_polygon();
1019    } else {
1020        begin_loop();
1021    }
1022    unsafe {
1023        for i in 0..len {
1024            vertex(
1025                0.5 + x + offset.get_unchecked(len - i - 1) * rs,
1026                0.5 + y + offset.get_unchecked(i) * rs,
1027            );
1028        }
1029        for i in 0..len {
1030            vertex(
1031                0.5 + x + offset.get_unchecked(i) * rs,
1032                0.5 + y + h - 1.0 - offset.get_unchecked(len - i - 1) * rs,
1033            );
1034        }
1035        for i in 0..len {
1036            vertex(
1037                0.5 + x + w - 1.0 - offset.get_unchecked(len - i - 1) * rs,
1038                0.5 + y + h - 1.0 - offset.get_unchecked(i) * rs,
1039            );
1040        }
1041        for i in 0..len {
1042            vertex(
1043                0.5 + x + w - 1.0 - offset.get_unchecked(i) * rs,
1044                0.5 + y + offset.get_unchecked(len - i - 1) * rs,
1045            );
1046        }
1047    }
1048    if fill {
1049        end_polygon();
1050    } else {
1051        end_loop();
1052    }
1053    set_draw_color(old_col);
1054}
1055
1056#[cfg(feature = "enable-glwindow")]
1057/// Start drawing using OpenGL functions inside a widget's draw routine
1058/// # Safety
1059/// Requires OpenGL support, Only works with SingleWindow
1060pub unsafe fn gl_start() {
1061    fltk_sys::window::Fl_gl_start();
1062}
1063
1064#[cfg(feature = "enable-glwindow")]
1065/// Finish drawing using OpenGL functions inside a widget's draw routine
1066/// # Safety
1067/// Requires OpenGL support, Only works with SingleWindow
1068pub unsafe fn gl_finish() {
1069    fltk_sys::window::Fl_gl_finish();
1070}
1071
1072/// Draws a rounded rectangle
1073pub fn draw_rounded_rect(x: i32, y: i32, w: i32, h: i32, r: i32) {
1074    unsafe { Fl_rounded_rect(x, y, w, h, r) }
1075}
1076
1077/// Draws a filled rounded rectangle
1078pub fn draw_rounded_rectf(x: i32, y: i32, w: i32, h: i32, r: i32) {
1079    unsafe { Fl_rounded_rectf(x, y, w, h, r) }
1080}
1081
1082/// Draws a filled circle
1083pub fn draw_circle_fill(x: i32, y: i32, d: i32, c: Color) {
1084    unsafe {
1085        Fl_draw_circle(x, y, d, c.bits());
1086    }
1087}
1088
1089/// Like draw_text, however uses FLTK's `fl_draw` which takes the length of the string, so it doesn't need to allocate
1090pub fn draw_text_n(string: &str, x: i32, y: i32) {
1091    let len = string.len();
1092    if size() == -1 && len == 1 {
1093        return;
1094    }
1095    unsafe { Fl_draw3(string.as_ptr() as _, len as _, x, y) }
1096}
1097
1098/// Override the drawing scale
1099pub fn override_scale() -> f32 {
1100    unsafe { Fl_override_scale() }
1101}
1102
1103/// Restore the drawing scale
1104pub fn restore_scale(s: f32) {
1105    unsafe { Fl_restore_scale(s) }
1106}