1use fltk_sys::utils::*;
2use std::ffi::{CStr, CString};
3use std::os::raw;
4use std::sync::atomic::{AtomicBool, Ordering};
5
6use crate::enums::ColorDepth;
7use crate::prelude::FltkError;
8use crate::prelude::FltkErrorKind;
9use crate::prelude::ImageExt;
10
11#[doc(hidden)]
12pub trait FlString {
14 fn safe_new(s: &str) -> CString;
16}
17
18impl FlString for CString {
19 fn safe_new(s: &str) -> CString {
20 match CString::new(s) {
21 Ok(v) => v,
22 Err(r) => {
23 let i = r.nul_position();
24 CString::new(&r.into_vec()[0..i]).unwrap()
25 }
26 }
27 }
28}
29
30pub const fn rgb2hex(r: u8, g: u8, b: u8) -> u32 {
39 let r = r as u32;
40 let g = g as u32;
41 let b = b as u32;
42 ((r & 0xff) << 16) + ((g & 0xff) << 8) + (b & 0xff)
43}
44
45pub const fn rgba2hex(r: u8, g: u8, b: u8, a: u8) -> u32 {
54 let r = r as u32;
55 let g = g as u32;
56 let b = b as u32;
57 let a = a as u32;
58 ((r & 0xff) << 24) + ((g & 0xff) << 16) + ((b & 0xff) << 8) + (a & 0xff)
59}
60
61pub const fn hex2rgb(val: u32) -> (u8, u8, u8) {
70 let r = ((val >> 16) & 0xff) as u8;
71 let g = ((val >> 8) & 0xff) as u8;
72 let b = (val & 0xff) as u8;
73 (r, g, b)
74}
75
76pub const fn hex2rgba(val: u32) -> (u8, u8, u8, u8) {
85 let r = ((val >> 24) & 0xff) as u8;
86 let g = ((val >> 16) & 0xff) as u8;
87 let b = ((val >> 8) & 0xff) as u8;
88 let a = (val & 0xff) as u8;
89 (r, g, b, a)
90}
91
92pub fn filename_expand(path: &str) -> Result<String, FltkError> {
94 assert!(path.len() <= 2048);
95 let mut out: Vec<u8> = vec![0u8; 2048];
96 let path = CString::safe_new(path);
97 unsafe {
98 let ret = Fl_filename_expand(
99 out.as_mut_ptr() as *mut raw::c_char,
100 2048,
101 path.as_ptr() as _,
102 );
103 if ret == 0 {
104 Err(FltkError::Internal(FltkErrorKind::FailedOperation))
105 } else {
106 let val = out.iter().position(|&x| x == 0).unwrap();
107 let out = out.split_at(val);
108 match String::from_utf8(out.0.to_vec()) {
109 Ok(s) => Ok(s),
110 Err(err) => Err(FltkError::Utf8Error(err)),
111 }
112 }
113 }
114}
115
116pub fn open_uri(s: &str) -> Result<String, FltkError> {
118 let s = CString::safe_new(s);
119 let mut v: Vec<u8> = vec![0u8; 255];
120 unsafe {
121 let ret = Fl_open_uri(s.as_ptr(), v.as_mut_ptr() as _, 255);
122 let v: Vec<u8> = v.into_iter().partition(|x| *x == 0).1;
123 let s = String::from_utf8(v)?;
124 if ret == 1 {
125 Ok(s)
126 } else {
127 Err(FltkError::Unknown(s))
128 }
129 }
130}
131
132pub fn decode_uri(s: &str) -> String {
134 let mut s = s.as_bytes().to_vec();
135 s.push(0);
136 unsafe {
137 Fl_decode_uri(s.as_mut_ptr() as _);
138 CStr::from_ptr(s.as_ptr() as _)
139 .to_string_lossy()
140 .to_string()
141 }
142}
143
144pub fn char_len(c: char) -> usize {
146 unsafe extern "C" {
147 pub fn strlen(s: *const std::os::raw::c_char) -> usize;
148 }
149 let s = CString::new(c.to_string()).unwrap();
150 unsafe { strlen(s.as_ptr() as _) }
151}
152
153#[cfg(target_os = "macos")]
154pub fn content_view<W: crate::prelude::WindowExt>(w: &W) -> *const raw::c_void {
156 unsafe extern "C" {
157 pub fn cfltk_getContentView(xid: *mut raw::c_void) -> *mut raw::c_void;
158 }
159 unsafe { cfltk_getContentView(w.raw_handle() as _) as _ }
160}
161
162pub fn is<W: crate::prelude::WidgetBase>(w: &W) -> bool {
164 W::from_dyn_widget(w).is_some()
165}
166
167pub fn is_ptr_of<W: crate::prelude::WidgetBase>(w: *mut fltk_sys::widget::Fl_Widget) -> bool {
169 W::from_dyn_widget_ptr(w).is_some()
170}
171
172pub fn type_name<W: crate::prelude::WidgetExt>(w: &W) -> String {
175 unsafe {
176 let p = Fl_type_name(w.as_widget_ptr() as _);
177 CStr::from_ptr(p as *mut raw::c_char)
178 .to_string_lossy()
179 .to_string()
180 }
181}
182
183#[cfg(target_os = "emscripten")]
184unsafe extern "C" {
185 fn fl_read_to_string(empath: *const raw::c_char) -> *mut raw::c_char;
186 fn fl_read_to_binary(empath: *const raw::c_char, len: *mut i32) -> *mut u8;
187 fn fl_write_to_file(empath: *const raw::c_char, data: *const u8, len: i32) -> i32;
188 fn free(data: *mut raw::c_void);
189}
190
191#[cfg(target_os = "emscripten")]
193pub fn em_file_read_to_string<S: AsRef<str>>(path: S) -> Result<String, FltkError> {
194 unsafe {
195 let path = CString::safe_new(path.as_ref());
196 let ptr = fl_read_to_string(path.as_ptr());
197 if ptr.is_null() {
198 Err(FltkError::Unknown(String::from("Failed to read from file")))
199 } else {
200 let s = CStr::from_ptr(ptr).to_string_lossy().to_string();
201 free(ptr as _);
202 Ok(s)
203 }
204 }
205}
206
207#[cfg(target_os = "emscripten")]
209pub fn em_file_read_to_binary(path: &str) -> Result<Vec<u8>, FltkError> {
210 unsafe {
211 let path = CString::safe_new(path);
212 let mut len = 0;
213 let ptr = fl_read_to_binary(path.as_ptr(), &mut len as _);
214 if ptr.is_null() {
215 Err(FltkError::Unknown(String::from("Failed to read from file")))
216 } else {
217 Ok(std::slice::from_raw_parts(ptr, len as _).to_vec())
218 }
219 }
220}
221
222#[cfg(target_os = "emscripten")]
224pub fn em_write_to_file(path: &str, data: &[u8]) -> Result<(), FltkError> {
225 unsafe {
226 let path = CString::safe_new(path);
227 let ret = fl_write_to_file(path.as_ptr(), data.as_ptr(), data.len() as _);
228 if ret == -1 {
229 Err(FltkError::Unknown(String::from("Failed to write to file")))
230 } else {
231 Ok(())
232 }
233 }
234}
235
236pub fn blit_rgba<'a, T: crate::prelude::WidgetBase>(
240 wid: &'a mut T,
241 fb: &'a [u8],
242) -> Result<(), FltkError> {
243 let width = wid.w();
244 let height = wid.h();
245 let mut img = crate::image::RgbImage::new(fb, width, height, ColorDepth::Rgba8)?;
246 wid.draw(move |s| {
247 let x = s.x();
248 let y = s.y();
249 let w = s.w();
250 let h = s.h();
251 img.scale(w, h, false, true);
252 img.draw(x, y, w, h);
253 });
254 Ok(())
255}
256
257pub unsafe fn blit_rgba_nocopy<T: crate::prelude::WidgetBase>(wid: &mut T, fb: &[u8]) {
261 unsafe {
262 let ptr = fb.as_ptr();
263 let len = fb.len();
264 let width = wid.w();
265 let height = wid.h();
266 wid.draw(move |s| {
267 let x = s.x();
268 let y = s.y();
269 let w = s.w();
270 let h = s.h();
271 if let Ok(mut img) = crate::image::RgbImage::from_data(
272 std::slice::from_raw_parts(ptr, len),
273 width,
274 height,
275 ColorDepth::Rgba8,
276 ) {
277 img.scale(w, h, false, true);
278 img.draw(x, y, w, h);
279 }
280 });
281 }
282}
283
284pub fn blit_rgb<'a, T: crate::prelude::WidgetBase>(
288 wid: &'a mut T,
289 fb: &'a [u8],
290) -> Result<(), FltkError> {
291 let width = wid.w();
292 let height = wid.h();
293 let mut img = crate::image::RgbImage::new(fb, width, height, ColorDepth::Rgb8)?;
294 wid.draw(move |s| {
295 let x = s.x();
296 let y = s.y();
297 let w = s.w();
298 let h = s.h();
299 img.scale(w, h, false, true);
300 img.draw(x, y, w, h);
301 });
302 Ok(())
303}
304
305pub unsafe fn blit_rgb_nocopy<T: crate::prelude::WidgetBase>(wid: &mut T, fb: &[u8]) {
309 unsafe {
310 let ptr = fb.as_ptr();
311 let len = fb.len();
312 let width = wid.w();
313 let height = wid.h();
314 wid.draw(move |s| {
315 let x = s.x();
316 let y = s.y();
317 let w = s.w();
318 let h = s.h();
319 if let Ok(mut img) = crate::image::RgbImage::from_data(
320 std::slice::from_raw_parts(ptr, len),
321 width,
322 height,
323 ColorDepth::Rgb8,
324 ) {
325 img.scale(w, h, false, true);
326 img.draw(x, y, w, h);
327 }
328 });
329 }
330}
331
332#[allow(dead_code)]
334pub(crate) static IMAGES_REGISTERED: AtomicBool = AtomicBool::new(false);
335
336#[allow(dead_code)]
338pub(crate) fn images_registered() -> bool {
339 IMAGES_REGISTERED.load(Ordering::Relaxed)
340}
341
342#[allow(dead_code)]
344pub(crate) fn register_images() {
345 #[cfg(feature = "use-images")]
346 unsafe {
347 fltk_sys::image::Fl_register_images();
348 fltk_sys::fl::Fl_load_system_icons();
349 }
350}