fltk/app/
visual.rs

1use crate::enums::{Color, FrameType, Mode};
2use crate::prelude::*;
3use crate::utils::FlString;
4use fltk_sys::fl;
5use std::{ffi::CString, mem, os::raw};
6
7/// Set the app scheme
8#[derive(Debug, Copy, Clone, PartialEq, Eq)]
9#[non_exhaustive]
10pub enum Scheme {
11    /// Base fltk scheming
12    Base,
13    /// inspired by the Aqua user interface on Mac OS X
14    Plastic,
15    /// inspired by the GTK+ theme
16    Gtk,
17    /// inspired by the Clearlooks Glossy scheme
18    Gleam,
19    /// Subset of Dmitrij K's oxy scheme
20    Oxy,
21}
22
23/// sets the scheme of the application
24pub fn set_scheme(scheme: Scheme) {
25    let name_str = match scheme {
26        Scheme::Base => "base",
27        Scheme::Gtk => "gtk+",
28        Scheme::Gleam => "gleam",
29        Scheme::Plastic => "plastic",
30        Scheme::Oxy => "oxy",
31    };
32    let name_str = CString::safe_new(name_str);
33    unsafe {
34        fl::Fl_set_scheme(name_str.as_ptr());
35    }
36}
37
38/// Gets the scheme of the application
39pub fn scheme() -> Scheme {
40    unsafe {
41        use Scheme::{Base, Gleam, Gtk, Oxy, Plastic};
42        match fl::Fl_scheme() {
43            0 => Base,
44            1 => Gtk,
45            2 => Gleam,
46            3 => Plastic,
47            4 => Oxy,
48            _ => unreachable!(),
49        }
50    }
51}
52
53/// Alias Scheme to `AppScheme`
54pub type AppScheme = Scheme;
55
56/// Set the application's scrollbar size
57pub fn set_scrollbar_size(sz: i32) {
58    unsafe { fl::Fl_set_scrollbar_size(sz) }
59}
60
61/// Get the app's scrollbar size
62pub fn scrollbar_size() -> i32 {
63    unsafe { fl::Fl_scrollbar_size() }
64}
65
66/// Return whether visible focus is shown
67pub fn visible_focus() -> bool {
68    unsafe { fl::Fl_visible_focus() != 0 }
69}
70
71/// Show focus around widgets
72pub fn set_visible_focus(flag: bool) {
73    unsafe { fl::Fl_set_visible_focus(i32::from(flag)) }
74}
75
76/// Set the app's default frame type without storing the old type
77pub fn set_frame_type(old_frame: FrameType, new_frame: FrameType) {
78    unsafe {
79        fl::Fl_set_box_type(old_frame.as_i32(), new_frame.as_i32());
80    }
81}
82
83/// Set the app's default frame type
84pub fn set_frame_type_cb(
85    old_frame: FrameType,
86    cb: fn(x: i32, y: i32, w: i32, h: i32, c: Color),
87    x: i32,
88    y: i32,
89    w: i32,
90    h: i32,
91) {
92    unsafe {
93        fl::Fl_set_box_type_cb(old_frame.as_i32(), Some(mem::transmute(cb)), x, y, w, h);
94    }
95}
96
97/// Get the shadow width for frames types with shadows
98pub fn frame_shadow_width() -> i32 {
99    unsafe { fl::Fl_box_shadow_width() }
100}
101
102/// Set the shadow width for frames types with shadows
103pub fn set_frame_shadow_width(width: i32) {
104    unsafe { fl::Fl_set_box_shadow_width(width) }
105}
106
107/// Get the max border radius for frame types
108pub fn frame_border_radius_max() -> i32 {
109    unsafe { fl::Fl_box_border_radius_max() }
110}
111
112/// Set the max border radius for frame types
113pub fn set_frame_border_radius_max(radius: i32) {
114    unsafe { fl::Fl_set_box_border_radius_max(radius) }
115}
116
117/// Makes FLTK use its own colormap. This may make FLTK display better
118pub fn own_colormap() {
119    unsafe { fl::Fl_own_colormap() }
120}
121
122/// Set the foreground color
123pub fn foreground(r: u8, g: u8, b: u8) {
124    unsafe { fl::Fl_foreground(r, g, b) }
125}
126
127/// Set the background color
128pub fn background(r: u8, g: u8, b: u8) {
129    unsafe { fl::Fl_background(r, g, b) }
130}
131
132/// Set the background color for input and text widgets
133pub fn background2(r: u8, g: u8, b: u8) {
134    unsafe { fl::Fl_background2(r, g, b) }
135}
136
137/// Set the foreground color
138pub fn set_foreground_color(r: u8, g: u8, b: u8) {
139    unsafe { fl::Fl_foreground(r, g, b) }
140}
141
142/// Set the background color
143pub fn set_background_color(r: u8, g: u8, b: u8) {
144    unsafe { fl::Fl_background(r, g, b) }
145}
146
147/// Set the background color for input and text widgets
148pub fn set_background2_color(r: u8, g: u8, b: u8) {
149    unsafe { fl::Fl_background2(r, g, b) }
150}
151
152/// Sets the app's default selection color
153pub fn set_selection_color(r: u8, g: u8, b: u8) {
154    unsafe { fl::Fl_selection_color(r, g, b) }
155}
156
157/// Sets the app's default selection color
158pub fn set_inactive_color(r: u8, g: u8, b: u8) {
159    unsafe { fl::Fl_inactive_color(r, g, b) }
160}
161
162/// Swap a color with a custom RGB value
163pub fn set_color(old: Color, r: u8, g: u8, b: u8) {
164    unsafe { fl::Fl_set_color(old.bits(), r, g, b) }
165}
166
167#[cfg(any(feature = "enable-glwindow", feature = "cairoext"))]
168/// Swap a color with a custom RGBA value
169pub fn set_color_with_alpha(old: Color, r: u8, g: u8, b: u8, a: u8) {
170    unsafe { fl::Fl_set_color_with_alpha(old.bits(), r, g, b, a) }
171}
172
173/// Gets the system colors
174pub fn get_system_colors() {
175    unsafe { fl::Fl_get_system_colors() }
176}
177
178/// Reload the app scheme
179pub fn reload_scheme() -> Result<(), FltkError> {
180    unsafe {
181        match fl::Fl_reload_scheme() {
182            1 => Ok(()),
183            _ => Err(FltkError::Internal(FltkErrorKind::FailedOperation)),
184        }
185    }
186}
187
188/// Get the default menu line-spacing
189pub fn menu_linespacing() -> i32 {
190    unsafe { fl::Fl_menu_linespacing() }
191}
192
193/// Set the menu line-spacing
194pub fn set_menu_linespacing(val: i32) {
195    unsafe { fl::Fl_set_menu_linespacing(val) }
196}
197
198/// Sets the visual mode of the application
199/// # Errors
200/// Returns Err(FailedOperation) if FLTK failed to set the visual mode
201pub fn set_visual(mode: Mode) -> Result<(), FltkError> {
202    unsafe {
203        match fl::Fl_visual(mode.bits()) {
204            0 => Err(FltkError::Internal(FltkErrorKind::FailedOperation)),
205            _ => Ok(()),
206        }
207    }
208}
209
210#[cfg(feature = "enable-glwindow")]
211/// Sets the OpenGL visual mode of the application
212/// # Errors
213/// Returns Err(FailedOperation) if FLTK failed to set the visual mode
214pub fn set_gl_visual(mode: Mode) -> Result<(), FltkError> {
215    unsafe {
216        match fl::Fl_gl_visual(mode.bits()) {
217            0 => Err(FltkError::Internal(FltkErrorKind::FailedOperation)),
218            _ => Ok(()),
219        }
220    }
221}
222
223/// The current graphics context of the app, `fl_gc`.
224/// `*mut c_void` to `HDC` on Windows, `CGContextRef` on macOS, `_XGC` on X11
225pub type GraphicsContext = *mut raw::c_void;
226
227/// Get the graphics context, `fl_gc`
228pub fn graphics_context() -> GraphicsContext {
229    unsafe {
230        let ctx = fltk_sys::window::Fl_gc();
231        assert!(!ctx.is_null());
232        ctx
233    }
234}
235
236/// Get the graphics context, `fl_gc`
237pub fn cairo_gc() -> *mut raw::c_void {
238    unsafe {
239        let ctx = fltk_sys::window::Fl_cairo_gc();
240        assert!(!ctx.is_null());
241        ctx
242    }
243}
244
245/// The display global variable, `fl_display`.
246/// `_XDisplay` on X11, `HINSTANCE` on Windows.
247pub type Display = *mut raw::c_void;
248
249/// Gets the display global variable, `fl_display`.
250/// `_XDisplay` on X11, `HINSTANCE` on Windows.
251pub fn display() -> Display {
252    unsafe {
253        let disp = fltk_sys::window::Fl_display();
254        assert!(!disp.is_null());
255        disp
256    }
257}
258
259/// Causes all the windows that need it to be redrawn and graphics forced out through the pipes.
260pub fn flush() {
261    assert!(crate::app::is_ui_thread());
262    unsafe { fl::Fl_flush() }
263}
264
265/// Redraws everything
266pub fn redraw() {
267    unsafe { fl::Fl_redraw() }
268}
269
270/// Open the current display
271/// # Safety
272/// A correct visual must be set prior to opening the display
273pub unsafe fn open_display() {
274    unsafe { fl::Fl_open_display() }
275}
276
277/// Close the current display
278/// # Safety
279/// The display shouldn't be closed while a window is shown
280pub unsafe fn close_display() {
281    unsafe { fl::Fl_close_display() }
282}
283
284/// Determines if the currently drawn box is active or inactive
285pub fn draw_frame_active() -> bool {
286    unsafe { fl::Fl_draw_box_active() != 0 }
287}
288
289/// `Fl::box_color`.
290/// Gets the current frame color within box/frame drawing mode
291pub fn frame_color(col: Color) -> Color {
292    unsafe { mem::transmute(fl::Fl_box_color(col.bits())) }
293}
294
295/// `Fl::set_box_color`.
296/// Sets the current frame color within box/frame drawing mode
297pub fn set_frame_color(col: Color) {
298    unsafe { fl::Fl_set_box_color(col.bits()) }
299}
300
301/// Add a new symbol, that can be accessed using the `@` prefix
302pub fn add_symbol(label: &str, scalable: bool, draw_cb: fn(Color)) -> Result<(), FltkError> {
303    unsafe {
304        let label = CString::safe_new(label);
305        let ret = fltk_sys::draw::Fl_add_symbol(
306            label.into_raw() as _,
307            mem::transmute(Some(draw_cb)),
308            scalable.into(),
309        );
310        if ret == 0 {
311            Err(FltkError::Internal(FltkErrorKind::FailedOperation))
312        } else {
313            Ok(())
314        }
315    }
316}
317
318/// Contrast modes supported by FLTK
319#[repr(i32)]
320#[derive(Debug, Copy, Clone, PartialEq, Eq)]
321pub enum ContrastMode {
322    /// always return foreground color
323    None = 0,
324    /// legacy (FLTK 1.3.x) contrast function
325    Legacy,
326    /// new (FLTK 1.4.0) default function
327    Cielab,
328    /// optional custom contrast function  
329    Custom,
330}
331
332/// Set the contrast level
333pub fn set_contrast_level(level: i32) {
334    unsafe { fl::Fl_set_contrast_level(level) }
335}
336
337/// Get the contrast level
338pub fn contrast_level() -> i32 {
339    unsafe { fl::Fl_contrast_level() }
340}
341
342/// Set the contrast mode
343pub fn set_contrast_mode(mode: ContrastMode) {
344    unsafe { fl::Fl_set_contrast_mode(mode as i32) }
345}
346
347/// Get the contrast mode
348pub fn contrast_mode() -> ContrastMode {
349    unsafe { mem::transmute(fl::Fl_contrast_mode()) }
350}
351
352/// Set the contrast function, for use in `set_contrast_mode(ContrastMode::Custom)`
353pub fn set_contrast_function(f: fn(fg: Color, bg: Color, fontsize: i32, ctx: i32) -> Color) {
354    unsafe { fl::Fl_set_contrast_function(mem::transmute(f)) }
355}
356
357#[allow(dead_code)]
358/// Check whether we're using wayland
359pub(crate) fn using_wayland() -> bool {
360    unsafe { fl::Fl_using_wayland() != 0 }
361}