1#[doc(hidden)]
2#[macro_export]
3macro_rules! impl_browser_ext {
5 ($name:tt, $flname:tt) => {
6 paste::paste! {
7 unsafe impl BrowserExt for $name {
8 fn remove(&mut self, line: i32) {
9 unsafe {
10 if line > 0 && line <= self.size() + 1 {
11 [<$flname _remove>](self.inner.widget() as _, line as i32)
12 }
13 }
14 }
15
16 fn add(&mut self, item: &str) {
17 let item = CString::safe_new(item);
18 unsafe { [<$flname _add>](self.inner.widget() as _, item.as_ptr()) }
19 }
20
21 fn add_with_data<T: Clone + 'static>(&mut self, item: &str, data: T) {
22 self.add(item);
23 self.set_data(self.size(), data);
24 }
25
26 fn insert(&mut self, line: i32, item: &str) {
27 let item = CString::safe_new(item);
28 unsafe { [<$flname _insert>](self.inner.widget() as _, line as i32, item.as_ptr()) }
29 }
30
31 fn insert_with_data<T: Clone + 'static>(&mut self, line: i32, item: &str, data: T) {
32 self.insert(line, item);
33 self.set_data(line, data);
34 }
35
36 fn move_item(&mut self, to: i32, from: i32) {
37 if to > 0 && to <= self.size() + 1 && from > 0 && from <= self.size() + 1 {
38 unsafe { [<$flname _move>](self.inner.widget() as _, to as i32, from as i32) }
39 }
40 }
41
42 fn swap(&mut self, a: i32, b: i32) {
43 if a > 0 && a <= self.size() + 1 && b > 0 && b <= self.size() + 1 {
44 unsafe { [<$flname _swap>](self.inner.widget() as _, a as i32, b as i32) }
45 }
46 }
47
48 fn clear(&mut self) {
49 unsafe {
50 [<$flname _clear>](self.inner.widget() as _)
51 }
52 }
53
54 fn size(&self) -> i32 {
55 unsafe {
56 [<$flname _size>](self.inner.widget() as _) as i32
57 }
58 }
59
60 fn select(&mut self, line: i32) {
61 if line > 0 && line <= self.size() + 1 {
62 unsafe {
63 [<$flname _select>](self.inner.widget() as _, line as i32);
64 }
65 }
66 }
67
68 fn deselect(&mut self, line: i32) {
69 if line > 0 && line <= self.size() + 1 {
70 unsafe {
71 [<$flname _select_ext>](self.inner.widget() as _, line as i32, 0);
72 }
73 }
74 }
75
76 fn selected(&self, line: i32) -> bool {
77 if line > 0 && line <= self.size() + 1 {
78 unsafe {
79 [<$flname _selected>](self.inner.widget() as _, line as i32) != 0
80 }
81 } else {
82 false
83 }
84 }
85
86 fn text(&self, line: i32) -> Option<String> {
87 if line > 0 && line <= self.size() + 1 {
88 unsafe {
89 let text = [<$flname _text>](self.inner.widget() as _, line as i32);
90 if text.is_null() {
91 None
92 } else {
93 Some(
94 CStr::from_ptr(text as *mut raw::c_char)
95 .to_string_lossy()
96 .to_string(),
97 )
98 }
99 }
100 } else {
101 None
102 }
103 }
104
105 fn selected_text(&self) -> Option<String> {
106 self.text(self.value())
107 }
108
109 fn set_text(&mut self, line: i32, txt: &str) {
110 if line > 0 && line <= self.size() + 1 {
111 let txt = CString::safe_new(txt);
112 unsafe { [<$flname _set_text>](self.inner.widget() as _, line as i32, txt.as_ptr()) }
113 }
114 }
115
116 fn load<P: AsRef<std::path::Path>>(&mut self, path: P) -> Result<(), FltkError> {
117 if !$crate::utils::images_registered() {
118 $crate::utils::register_images();
119 }
120 if !path.as_ref().exists() {
121 return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
122 }
123 let path = path
124 .as_ref()
125 .to_str()
126 .ok_or(FltkError::Unknown(String::from(
127 "Failed to convert path to string",
128 )))?;
129 let path = CString::new(path)?;
130 unsafe {
131 [<$flname _load_file>](self.inner.widget() as _, path.as_ptr());
132 Ok(())
133 }
134 }
135
136 fn text_size(&self) -> i32 {
137 unsafe { [<$flname _text_size>](self.inner.widget() as _) as i32 }
138 }
139
140 fn set_text_size(&mut self, c: i32) {
141 unsafe {
142 [<$flname _set_text_size>](self.inner.widget() as _, c as i32)
143 }
144 }
145
146 fn set_icon<Img: ImageExt>(&mut self, line: i32, image: Option<Img>) {
147 if line > 0 && line <= self.size() + 1 {
148 if let Some(image) = image {
149 assert!(!image.was_deleted());
150 unsafe {
151 [<$flname _set_icon>](
152 self.inner.widget() as _,
153 line as i32,
154 image.as_image_ptr() as *mut _,
155 )
156 }
157 } else {
158 unsafe {
159 [<$flname _set_icon>](
160 self.inner.widget() as _,
161 line as i32,
162 std::ptr::null_mut() as *mut raw::c_void,
163 )
164 }
165 }
166 }
167 }
168
169 fn icon(&self, line: i32) -> Option<Box<dyn ImageExt>> {
170 unsafe {
171 if line > 0 && line <= self.size() + 1 {
172 let image_ptr = [<$flname _icon>](self.inner.widget() as _, line as i32);
173 if image_ptr.is_null() {
174 None
175 } else {
176 let img =
177 $crate::image::Image::from_image_ptr(image_ptr as *mut fltk_sys::image::Fl_Image);
178 Some(Box::new(img))
179 }
180 } else {
181 None
182 }
183 }
184 }
185
186 fn remove_icon(&mut self, line: i32) {
187 unsafe {
188 if line > 0 && line <= self.size() + 1 {
189 [<$flname _remove_icon>](self.inner.widget() as _, line as i32)
190 }
191 }
192 }
193
194 fn top_line(&mut self, line: i32) {
195 if line > 0 && line <= self.size() + 1 {
196 unsafe { [<$flname _topline>](self.inner.widget() as _, line as i32) }
197 }
198 }
199
200 fn bottom_line(&mut self, line: i32) {
201 if line > 0 && line <= self.size() + 1 {
202 unsafe { [<$flname _bottomline>](self.inner.widget() as _, line as i32) }
203 }
204 }
205
206 fn middle_line(&mut self, line: i32) {
207 if line > 0 && line <= self.size() + 1 {
208 unsafe { [<$flname _middleline>](self.inner.widget() as _, line as i32) }
209 }
210 }
211
212 fn format_char(&self) -> char {
213 unsafe { [<$flname _format_char>](self.inner.widget() as _) as u8 as char }
214 }
215
216 fn set_format_char(&mut self, c: char) {
217 debug_assert!(c != 0 as char);
218 let c = if c as i32 > 128 { 128 as char } else { c };
219 unsafe { [<$flname _set_format_char>](self.inner.widget() as _, c as raw::c_char) }
220 }
221
222 fn column_char(&self) -> char {
223 unsafe { [<$flname _column_char>](self.inner.widget() as _) as u8 as char }
224 }
225
226 fn set_column_char(&mut self, c: char) {
227 debug_assert!(c != 0 as char);
228 let c = if c as i32 > 128 { 128 as char } else { c };
229 unsafe { [<$flname _set_column_char>](self.inner.widget() as _, c as raw::c_char) }
230 }
231
232 fn column_widths(&self) -> Vec<i32> {
233 unsafe {
234 let widths = [<$flname _column_widths>](self.inner.widget() as _);
235 assert!(!widths.is_null());
237 let mut v: Vec<i32> = vec![];
238 let mut i = 0;
239 while (*widths.offset(i) != 0) {
240 v.push(*widths.offset(i));
241 i += 1;
242 }
243 v
244 }
245 }
246
247 fn set_column_widths(&mut self, arr: &[i32]) {
248 debug_assert!(!arr.contains(&0), "FLTK uses 0 as a sentinel value for the array/slice. To hide a column, use -1!");
249 unsafe {
250 let old = [<$flname _column_widths>](self.inner.widget() as _);
251 let mut v = arr.to_vec();
252 v.push(0);
253 let v = v.into_boxed_slice();
254 [<$flname _set_column_widths>](self.inner.widget() as _, Box::into_raw(v) as _);
255 if !old.is_null() && *old.offset(0) != 0 {
256 let _ = Box::from_raw(old as *mut i32);
257 }
258 }
259 }
260
261 fn displayed(&self, line: i32) -> bool {
262 if line > 0 && line <= self.size() + 1 {
263 unsafe { [<$flname _displayed>](self.inner.widget() as _, line as i32) != 0 }
264 } else {
265 false
266 }
267 }
268
269 fn make_visible(&mut self, line: i32) {
270 if line > 0 && line <= self.size() + 1 {
271 unsafe { [<$flname _make_visible>](self.inner.widget() as _, line as i32) }
272 }
273 }
274
275 fn vposition(&self) -> i32 {
276 unsafe { [<$flname _position>](self.inner.widget() as _) as i32 }
277 }
278
279 fn set_vposition(&mut self, pos: i32) {
280 unsafe { [<$flname _set_position>](self.inner.widget() as _, pos as i32) }
281 }
282
283 fn hposition(&self) -> i32 {
284 unsafe { [<$flname _hposition>](self.inner.widget() as _) as i32 }
285 }
286
287 fn set_hposition(&mut self, pos: i32) {
288 unsafe { [<$flname _set_hposition>](self.inner.widget() as _, pos as i32) }
289 }
290
291 fn has_scrollbar(&self) -> $crate::browser::BrowserScrollbar {
292 unsafe { std::mem::transmute([<$flname _has_scrollbar>](self.inner.widget() as _)) }
293 }
294
295 fn set_has_scrollbar(&mut self, mode: $crate::browser::BrowserScrollbar) {
296 unsafe {
297 [<$flname _set_has_scrollbar>](self.inner.widget() as _, mode as raw::c_uchar)
298 }
299 }
300
301 fn scrollbar_size(&self) -> i32 {
302 unsafe { [<$flname _scrollbar_size>](self.inner.widget() as _) as i32 }
303 }
304
305 fn set_scrollbar_size(&mut self, new_size: i32) {
306 unsafe { [<$flname _set_scrollbar_size>](self.inner.widget() as _, new_size as i32) }
307 }
308
309 fn sort(&mut self) {
310 unsafe { [<$flname _sort>](self.inner.widget() as _) }
311 }
312
313 fn scrollbar(&self) -> $crate::valuator::Scrollbar {
314 unsafe {
315 let ptr = [<$flname _scrollbar>](self.inner.widget() as _);
316 assert!(!ptr.is_null());
317 $crate::valuator::Scrollbar::from_widget_ptr(
318 ptr as *mut fltk_sys::widget::Fl_Widget,
319 )
320 }
321 }
322
323 fn hscrollbar(&self) -> $crate::valuator::Scrollbar {
324 unsafe {
325 let ptr = [<$flname _hscrollbar>](self.inner.widget() as _);
326 assert!(!ptr.is_null());
327 $crate::valuator::Scrollbar::from_widget_ptr(
328 ptr as *mut fltk_sys::widget::Fl_Widget,
329 )
330 }
331 }
332
333 fn value(&self) -> i32 {
334 unsafe { [<$flname _value>](self.inner.widget() as _) as i32 }
335 }
336
337 fn set_data<T: Clone + 'static>(&mut self, line: i32, data: T) {
338 if line > 0 && line <= self.size() + 1 {
339 unsafe {
340 [<$flname _set_data>](self.inner.widget() as _, line, Box::into_raw(Box::from(data)) as _);
341 }
342 }
343 }
344
345 unsafe fn data<T: Clone + 'static>(&self, line: i32) -> Option<T> { unsafe {
346 if line > 0 && line <= self.size() + 1 {
347 let ptr = [<$flname _data>](self.inner.widget() as _, line);
348 if ptr.is_null() {
349 None
350 } else {
351 let data = ptr as *const _ as *mut T;
352 Some((*data).clone())
353 }
354 } else {
355 None
356 }
357 }}
358
359 fn hide_line(&mut self, line: i32) {
360 if line > 0 && line <= self.size() + 1 {
361 unsafe { [<$flname _hide_line>](self.inner.widget() as _, line); }
362 }
363 }
364
365 fn selected_items(&self) -> Vec<i32> {
366 let mut temp = vec![];
367 if self.value() > 0 {
368 for i in 1..self.size() + 1 {
369 if self.selected(i) {
370 temp.push(i);
371 }
372 }
373 }
374 temp
375 }
376 }
377 }
378 };
379}
380
381pub use impl_browser_ext;