1#![allow(clippy::too_many_arguments)]
2
3use crate::enums::{Align, Color, ColorDepth, Cursor, Font, FrameType, Shortcut};
4use crate::image::RgbImage;
5use crate::prelude::*;
6use crate::surface::ImageSurface;
7use crate::utils::FlString;
8use fltk_sys::draw::*;
9use std::ffi::{CStr, CString};
10use std::mem;
11use std::os::raw;
12
13bitflags::bitflags! {
14 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16 pub struct LineStyle: i32 {
17 const Solid = 0;
19 const Dash = 1;
21 const Dot = 2;
23 const DashDot = 3;
25 const DashDotDot = 4;
27 const CapFlat = 0x100;
29 const CapRound = 0x200;
31 const CapSquare = 0x300;
33 const JoinMiter = 0x1000;
35 const JoinRound = 0x2000;
37 const JoinBevel = 0x3000;
39 }
40}
41
42pub struct Region(pub(crate) *mut raw::c_void);
44
45pub fn show_colormap(old_color: Color) -> Color {
47 unsafe { mem::transmute(Fl_show_colormap(old_color.bits())) }
48}
49
50pub fn set_color_rgb(r: u8, g: u8, b: u8) {
52 unsafe { Fl_set_color_rgb(r, g, b) }
53}
54
55pub fn get_color() -> Color {
57 unsafe { mem::transmute(Fl_get_color()) }
58}
59
60pub fn draw_line(x1: i32, y1: i32, x2: i32, y2: i32) {
62 unsafe {
63 Fl_line(x1, y1, x2, y2);
64 }
65}
66
67pub fn draw_polyline(x1: i32, y1: i32, x2: i32, y2: i32, x3: i32, y3: i32) {
69 unsafe { Fl_polyline(x1, y1, x2, y2, x3, y3) }
70}
71
72pub fn draw_point(x: i32, y: i32) {
74 unsafe { Fl_point(x, y) }
75}
76
77pub fn draw_rect(x: i32, y: i32, w: i32, h: i32) {
79 unsafe { Fl_rect(x, y, w, h) }
80}
81
82pub fn draw_rect_with_color(x: i32, y: i32, w: i32, h: i32, color: Color) {
84 unsafe { Fl_rect_with_color(x, y, w, h, color.bits()) }
85}
86
87pub fn draw_loop(x1: i32, y1: i32, x2: i32, y2: i32, x3: i32, y3: i32) {
89 unsafe {
90 Fl_loop(x1, y1, x2, y2, x3, y3);
91 }
92}
93
94pub fn draw_loop_4sided(x1: i32, y1: i32, x2: i32, y2: i32, x3: i32, y3: i32, x4: i32, y4: i32) {
96 unsafe {
97 Fl_loop_4sided(x1, y1, x2, y2, x3, y3, x4, y4);
98 }
99}
100
101pub fn draw_rect_fill(x: i32, y: i32, w: i32, h: i32, color: Color) {
103 unsafe { Fl_rectf_with_color(x, y, w, h, color.bits()) }
104}
105
106pub fn draw_focus_rect(x: i32, y: i32, w: i32, h: i32) {
108 unsafe { Fl_focus_rect(x, y, w, h) }
109}
110
111pub fn set_draw_hex_color(color: u32) {
113 unsafe {
114 crate::app::open_display();
115 }
116 let (r, g, b) = crate::utils::hex2rgb(color);
117 unsafe { Fl_set_color_rgb(r, g, b) }
118}
119
120pub fn set_draw_rgb_color(r: u8, g: u8, b: u8) {
122 unsafe {
123 crate::app::open_display();
124 }
125 unsafe { Fl_set_color_rgb(r, g, b) }
126}
127
128pub fn set_draw_color(color: Color) {
130 unsafe {
131 crate::app::open_display();
132 }
133 unsafe { Fl_set_color_int(color.bits()) }
134}
135
136pub fn draw_circle(x: f64, y: f64, r: f64) {
138 unsafe {
139 Fl_circle(x, y, r);
140 }
141}
142
143pub fn draw_arc(x: i32, y: i32, width: i32, height: i32, a: f64, b: f64) {
145 unsafe {
146 Fl_arc(x, y, width, height, a, b);
147 }
148}
149
150pub fn draw_arc_with_radius(x: f64, y: f64, r: f64, start: f64, end: f64) {
152 unsafe { Fl_arc_with_radius(x, y, r, start, end) }
153}
154
155pub fn draw_pie(x: i32, y: i32, width: i32, height: i32, a: f64, b: f64) {
157 unsafe {
158 Fl_pie(x, y, width, height, a, b);
159 }
160}
161
162pub fn set_line_style(style: LineStyle, width: i32) {
169 unsafe {
170 crate::app::open_display();
171 Fl_line_style(
172 style.bits(),
173 width,
174 std::ptr::null_mut() as *mut std::os::raw::c_char,
175 );
176 }
177}
178
179pub fn push_clip(x: i32, y: i32, w: i32, h: i32) {
181 unsafe {
182 Fl_push_clip(x, y, w, h);
183 }
184}
185
186pub fn pop_clip() {
188 unsafe {
189 Fl_pop_clip();
190 }
191}
192
193pub fn set_clip_region(r: &Region) {
195 assert!(!r.0.is_null());
196 unsafe { Fl_set_clip_region(r.0) }
197}
198
199pub fn clip_region() -> Region {
201 unsafe {
202 let ptr = Fl_clip_region();
203 assert!(!ptr.is_null());
204 Region(ptr)
205 }
206}
207
208pub fn push_no_clip() {
210 unsafe { Fl_push_no_clip() }
211}
212
213pub fn not_clipped(x: i32, y: i32, w: i32, h: i32) -> bool {
215 unsafe { Fl_not_clipped(x, y, w, h) != 0 }
216}
217
218pub fn restore_clip() {
220 unsafe { Fl_restore_clip() }
221}
222
223pub fn transform_x(x: f64, y: f64) -> f64 {
225 unsafe { Fl_transform_x(x, y) }
226}
227
228pub fn transform_y(x: f64, y: f64) -> f64 {
230 unsafe { Fl_transform_y(x, y) }
231}
232
233pub fn transform_dx(x: f64, y: f64) -> f64 {
235 unsafe { Fl_transform_dx(x, y) }
236}
237
238pub fn transform_dy(x: f64, y: f64) -> f64 {
240 unsafe { Fl_transform_dy(x, y) }
241}
242
243pub fn transformed_vertex(xf: f64, yf: f64) {
245 unsafe { Fl_transformed_vertex(xf, yf) }
246}
247
248pub fn draw_rectf(x: i32, y: i32, w: i32, h: i32) {
250 unsafe { Fl_rectf(x, y, w, h) }
251}
252
253pub fn draw_rectf_with_rgb(
255 x: i32,
256 y: i32,
257 width: i32,
258 height: i32,
259 color_r: u8,
260 color_g: u8,
261 color_b: u8,
262) {
263 unsafe { Fl_rectf_with_rgb(x, y, width, height, color_r, color_g, color_b) }
264}
265
266pub fn draw_polygon(x: i32, y: i32, x1: i32, y1: i32, x2: i32, y2: i32) {
268 unsafe { Fl_polygon(x, y, x1, y1, x2, y2) }
269}
270
271pub fn draw_polygon_4sided(x1: i32, y1: i32, x2: i32, y2: i32, x3: i32, y3: i32, x4: i32, y4: i32) {
273 unsafe {
274 Fl_polygon_4sided(x1, y1, x2, y2, x3, y3, x4, y4);
275 }
276}
277
278pub fn draw_curve(x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) {
280 unsafe {
281 Fl_curve(x1, y1, x2, y2, x3, y3, x4, y4);
282 }
283}
284
285pub fn draw_hline(x: i32, y: i32, x1: i32) {
287 unsafe { Fl_xyline(x, y, x1) }
288}
289
290pub fn draw_hvline(x: i32, y: i32, x1: i32, y2: i32) {
292 unsafe { Fl_xyline2(x, y, x1, y2) }
293}
294
295pub fn draw_hvhline(x: i32, y: i32, x1: i32, y2: i32, x3: i32) {
298 unsafe { Fl_xyline3(x, y, x1, y2, x3) }
299}
300
301pub fn draw_vline(x: i32, y: i32, y1: i32) {
303 unsafe { Fl_yxline(x, y, y1) }
304}
305
306pub fn draw_vhline(x: i32, y: i32, y1: i32, x2: i32) {
308 unsafe { Fl_yxline2(x, y, y1, x2) }
309}
310
311pub fn draw_vhvline(x: i32, y: i32, y1: i32, x2: i32, y3: i32) {
314 unsafe { Fl_yxline3(x, y, y1, x2, y3) }
315}
316
317pub fn push_matrix() {
319 unsafe { Fl_push_matrix() }
320}
321
322pub fn pop_matrix() {
324 unsafe { Fl_pop_matrix() }
325}
326
327pub fn scale_xy(x: f64, y: f64) {
329 unsafe { Fl_scale_xy(x, y) }
330}
331
332pub fn scale(val: f64) {
334 unsafe { Fl_scale(val) }
335}
336
337pub fn translate(x: f64, y: f64) {
339 unsafe { Fl_translate(x, y) }
340}
341
342pub fn rotate(d: f64) {
344 unsafe { Fl_rotate(d) }
345}
346
347pub fn mult_matrix(val_a: f64, val_b: f64, val_c: f64, val_d: f64, x: f64, y: f64) {
349 unsafe { Fl_mult_matrix(val_a, val_b, val_c, val_d, x, y) }
350}
351
352pub fn begin_points() {
354 unsafe { Fl_begin_points() }
355}
356
357pub fn begin_line() {
359 unsafe { Fl_begin_line() }
360}
361
362pub fn begin_loop() {
364 unsafe { Fl_begin_loop() }
365}
366
367pub fn begin_polygon() {
369 unsafe { Fl_begin_polygon() }
370}
371
372pub fn vertex(x: f64, y: f64) {
374 unsafe { Fl_vertex(x, y) }
375}
376
377pub fn end_points() {
379 unsafe { Fl_end_points() }
380}
381
382pub fn end_line() {
384 unsafe { Fl_end_line() }
385}
386
387pub fn end_loop() {
389 unsafe { Fl_end_loop() }
390}
391
392pub fn end_polygon() {
394 unsafe { Fl_end_polygon() }
395}
396
397pub fn begin_complex_polygon() {
399 unsafe { Fl_begin_complex_polygon() }
400}
401
402pub fn gap() {
404 unsafe { Fl_gap() }
405}
406
407pub fn end_complex_polygon() {
409 unsafe { Fl_end_complex_polygon() }
410}
411
412pub fn set_font(face: Font, fsize: i32) {
414 unsafe { Fl_set_draw_font(face.bits(), fsize) }
415}
416
417pub fn font() -> Font {
419 unsafe { mem::transmute(Fl_font()) }
420}
421
422pub fn size() -> i32 {
424 unsafe { Fl_size() }
425}
426
427pub fn height() -> i32 {
429 unsafe { Fl_height() }
430}
431
432pub fn set_height(font: Font, size: i32) {
434 unsafe {
435 Fl_set_height(font.bits(), size);
436 }
437}
438
439pub fn descent() -> i32 {
442 unsafe { Fl_descent() }
443}
444
445pub fn width(txt: &str) -> f64 {
447 let len = txt.len();
448 let txt = CString::safe_new(txt);
449 unsafe { Fl_width(txt.as_ptr(), len as _) }
450}
451
452pub fn measure(txt: &str, draw_symbols: bool) -> (i32, i32) {
454 let txt = CString::safe_new(txt);
455 let (mut x, mut y) = (0, 0);
456 unsafe {
457 Fl_measure(txt.as_ptr(), &mut x, &mut y, i32::from(draw_symbols));
458 }
459 (x, y)
460}
461
462pub fn wrap_measure(txt: &str, width: i32, draw_symbols: bool) -> (i32, i32) {
466 let txt = CString::safe_new(txt);
467 let (mut x, mut y) = (width, 0);
468 unsafe {
469 Fl_measure(txt.as_ptr(), &mut x, &mut y, i32::from(draw_symbols));
470 }
471 (x, y)
472}
473
474pub fn text_extents(txt: &str) -> (i32, i32, i32, i32) {
477 let txt = CString::safe_new(txt);
478 let (mut x, mut y, mut w, mut h) = (0, 0, 0, 0);
479 unsafe {
480 Fl_text_extents(txt.as_ptr(), &mut x, &mut y, &mut w, &mut h);
481 }
482 (x, y, w, h)
483}
484
485pub fn char_width(c: char) -> f64 {
487 unsafe { Fl_char_width(c as u32) }
488}
489
490pub fn latin1_to_local(txt: &str, n: i32) -> String {
492 let txt = CString::safe_new(txt);
493 unsafe {
494 let x = Fl_latin1_to_local(txt.as_ptr(), n);
495 assert!(!x.is_null());
496 CStr::from_ptr(x as *mut raw::c_char)
497 .to_string_lossy()
498 .to_string()
499 }
500}
501
502pub fn local_to_latin1(txt: &str, n: i32) -> String {
504 let txt = CString::safe_new(txt);
505 unsafe {
506 let x = Fl_local_to_latin1(txt.as_ptr(), n);
507 assert!(!x.is_null());
508 CStr::from_ptr(x as *mut raw::c_char)
509 .to_string_lossy()
510 .to_string()
511 }
512}
513
514pub fn draw_text(txt: &str, x: i32, y: i32) {
516 if size() == -1 && txt.len() == 1 {
517 return;
518 }
519 let txt = CString::safe_new(txt);
520 unsafe { Fl_draw(txt.as_ptr(), x, y) }
521}
522
523pub fn draw_text_boxed(string: &str, x: i32, y: i32, width: i32, height: i32, align: Align) {
525 if size() == -1 && string.len() == 1 {
526 return;
527 }
528 let s = CString::safe_new(string);
529 unsafe { Fl_draw_text_boxed(s.as_ptr(), x, y, width, height, align.bits()) }
530}
531
532pub fn draw_text_angled(angle: i32, txt: &str, x: i32, y: i32) {
534 if size() == -1 && txt.len() == 1 {
535 return;
536 }
537 let txt = CString::safe_new(txt);
538 unsafe { Fl_draw_text_angled(angle, txt.as_ptr(), x, y) }
539}
540
541pub fn rtl_draw(txt: &str, x: i32, y: i32) {
543 if size() == -1 && txt.len() == 1 {
544 return;
545 }
546 let len = txt.len() as i32;
547 let txt = CString::safe_new(txt);
548 unsafe { Fl_rtl_draw(txt.as_ptr(), len, x, y) }
549}
550
551pub fn draw_frame(string: &str, x: i32, y: i32, width: i32, height: i32) {
557 assert!(string.len() % 4 == 0);
558 let s = CString::safe_new(string);
559 unsafe { Fl_frame(s.as_ptr(), x, y, width, height) }
560}
561
562pub fn draw_frame2(string: &str, x: i32, y: i32, width: i32, height: i32) {
566 assert!(string.len() % 4 == 0);
567 let s = CString::safe_new(string);
568 unsafe { Fl_frame2(s.as_ptr(), x, y, width, height) }
569}
570
571pub fn draw_box(box_type: FrameType, x: i32, y: i32, w: i32, h: i32, color: Color) {
573 unsafe { Fl_draw_box(box_type.as_i32(), x, y, w, h, color.bits()) }
574}
575
576pub fn can_do_alpha_blending() -> bool {
578 unsafe { Fl_can_do_alpha_blending() != 0 }
579}
580
581pub fn shortcut_label(shortcut: Shortcut) -> String {
583 unsafe {
584 let x = Fl_shortcut_label(shortcut.bits() as u32);
585 assert!(!x.is_null());
586 CStr::from_ptr(x as *mut raw::c_char)
587 .to_string_lossy()
588 .to_string()
589 }
590}
591
592pub fn overlay_rect(x: i32, y: i32, w: i32, h: i32) {
594 unsafe { Fl_overlay_rect(x, y, w, h) }
595}
596
597pub fn overlay_clear() {
599 unsafe { Fl_overlay_clear() }
600}
601
602pub fn set_cursor(cursor: Cursor) {
604 unsafe { Fl_set_cursor(cursor as i32) }
605}
606
607pub fn set_cursor_with_color(cursor: Cursor, fg: Color, bg: Color) {
609 unsafe { Fl_set_cursor_with_color(cursor as i32, fg.bits() as i32, bg.bits() as i32) }
610}
611
612pub fn set_status(x: i32, y: i32, w: i32, h: i32) {
614 unsafe { Fl_set_status(x, y, w, h) }
615}
616
617pub fn set_spot<Win: WindowExt>(font: Font, size: i32, x: i32, y: i32, w: i32, h: i32, win: &Win) {
619 unsafe {
620 Fl_set_spot(
621 font.bits(),
622 size,
623 x,
624 y,
625 w,
626 h,
627 win.as_widget_ptr() as *mut raw::c_void,
628 );
629 }
630}
631
632pub fn reset_spot() {
634 unsafe { Fl_reset_spot() }
635}
636
637pub fn capture_window<Win: WindowExt>(win: &mut Win) -> Result<RgbImage, FltkError> {
649 let cp = win.w() * win.h() * 3;
650 win.show();
651 unsafe {
652 let x = Fl_read_image(std::ptr::null_mut(), 0, 0, win.w(), win.h(), 0);
653 if x.is_null() {
654 Err(FltkError::Internal(FltkErrorKind::FailedOperation))
655 } else {
656 let x = std::slice::from_raw_parts(x, cp as usize);
657 Ok(RgbImage::new(x, win.w(), win.h(), ColorDepth::Rgb8)?)
658 }
659 }
660}
661
662pub fn capture_window_part<Win: WindowExt>(
674 win: &mut Win,
675 x: i32,
676 y: i32,
677 w: i32,
678 h: i32,
679) -> Result<RgbImage, FltkError> {
680 let cp = win.w() * win.h() * 3;
681 win.show();
682 unsafe {
683 let x = Fl_capture_window_part(win.as_widget_ptr() as _, x, y, w, h);
684 if x.is_null() {
685 Err(FltkError::Internal(FltkErrorKind::FailedOperation))
686 } else {
687 let x = std::slice::from_raw_parts(x, cp as usize);
688 Ok(RgbImage::new(x, w, h, ColorDepth::Rgb8)?)
689 }
690 }
691}
692
693pub fn capture_surface(surface: &ImageSurface, w: i32, h: i32) -> Result<RgbImage, FltkError> {
705 let cp = w * h * 3;
706 unsafe {
707 ImageSurface::push_current(surface);
708 let x = Fl_read_image(std::ptr::null_mut(), 0, 0, w, h, 0);
709 ImageSurface::pop_current();
710 if x.is_null() {
711 Err(FltkError::Internal(FltkErrorKind::FailedOperation))
712 } else {
713 let x = std::slice::from_raw_parts(x, cp as usize);
714 Ok(RgbImage::new(x, w, h, ColorDepth::Rgb8)?)
715 }
716 }
717}
718
719pub fn draw_image(
725 data: &[u8],
726 x: i32,
727 y: i32,
728 w: i32,
729 h: i32,
730 depth: ColorDepth,
731) -> Result<(), FltkError> {
732 let sz = (w * h * depth as i32) as usize;
733 if sz > data.len() {
734 return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
735 }
736 unsafe {
737 Fl_draw_image(data.as_ptr(), x, y, w, h, depth as i32, 0);
738 }
739 Ok(())
740}
741
742pub fn draw_check(x: i32, y: i32, w: i32, h: i32, col: Color) {
744 unsafe {
745 Fl_draw_check(x, y, w, h, col.bits());
746 }
747}
748
749pub unsafe fn draw_image_ext(
759 data: &[u8],
760 x: i32,
761 y: i32,
762 w: i32,
763 h: i32,
764 depth: i32,
765 line_data: i32,
766) {
767 unsafe {
768 Fl_draw_image(data.as_ptr(), x, y, w, h, depth, line_data);
769 }
770}
771
772pub fn draw_rbox(x: i32, y: i32, w: i32, h: i32, max_radius: i32, fill: bool, col: Color) {
774 let max_radius = if max_radius < 0 { 0 } else { max_radius };
775 let offset: [f64; 5] = [0.0, 0.07612, 0.29289, 0.61732, 1.0];
776 let mut rs = w * 2 / 5;
777 let rsy = h * 2 / 5;
778 if rs > rsy {
779 rs = rsy;
780 }
781 if rs > max_radius {
782 rs = max_radius;
783 }
784 if rs == 5 {
785 rs = 4;
786 }
787 if rs == 7 {
788 rs = 8;
789 }
790
791 let rs = f64::from(rs);
792 let x = f64::from(x);
793 let y = f64::from(y);
794 let w = f64::from(w);
795 let h = f64::from(h);
796 let old_col = get_color();
797 let len = offset.len();
798
799 set_draw_color(col);
800 if fill {
801 begin_polygon();
802 } else {
803 begin_loop();
804 }
805 unsafe {
806 for i in 0..len {
807 vertex(
808 0.5 + x + offset.get_unchecked(len - i - 1) * rs,
809 0.5 + y + offset.get_unchecked(i) * rs,
810 );
811 }
812 for i in 0..len {
813 vertex(
814 0.5 + x + offset.get_unchecked(i) * rs,
815 0.5 + y + h - 1.0 - offset.get_unchecked(len - i - 1) * rs,
816 );
817 }
818 for i in 0..len {
819 vertex(
820 0.5 + x + w - 1.0 - offset.get_unchecked(len - i - 1) * rs,
821 0.5 + y + h - 1.0 - offset.get_unchecked(i) * rs,
822 );
823 }
824 for i in 0..len {
825 vertex(
826 0.5 + x + w - 1.0 - offset.get_unchecked(i) * rs,
827 0.5 + y + offset.get_unchecked(len - i - 1) * rs,
828 );
829 }
830 }
831 if fill {
832 end_polygon();
833 } else {
834 end_loop();
835 }
836 set_draw_color(old_col);
837}
838
839#[cfg(feature = "enable-glwindow")]
840pub unsafe fn gl_start() {
844 unsafe {
845 fltk_sys::window::Fl_gl_start();
846 }
847}
848
849#[cfg(feature = "enable-glwindow")]
850pub unsafe fn gl_finish() {
854 unsafe {
855 fltk_sys::window::Fl_gl_finish();
856 }
857}
858
859pub fn draw_rounded_rect(x: i32, y: i32, w: i32, h: i32, r: i32) {
861 unsafe { Fl_rounded_rect(x, y, w, h, r) }
862}
863
864pub fn draw_rounded_rectf(x: i32, y: i32, w: i32, h: i32, r: i32) {
866 unsafe { Fl_rounded_rectf(x, y, w, h, r) }
867}
868
869pub fn draw_circle_fill(x: i32, y: i32, d: i32, c: Color) {
871 unsafe {
872 Fl_draw_circle(x, y, d, c.bits());
873 }
874}
875
876pub fn draw_text_n(string: &str, x: i32, y: i32) {
878 let len = string.len();
879 if size() == -1 && len == 1 {
880 return;
881 }
882 unsafe { Fl_draw_text_n(string.as_ptr() as _, len as _, x, y) }
883}
884
885pub fn override_scale() -> f32 {
887 unsafe { Fl_override_scale() }
888}
889
890pub fn restore_scale(s: f32) {
892 unsafe { Fl_restore_scale(s) }
893}