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