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 !path.as_ref().exists() {
118 return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
119 }
120 let path = path
121 .as_ref()
122 .to_str()
123 .ok_or(FltkError::Unknown(String::from(
124 "Failed to convert path to string",
125 )))?;
126 let path = CString::new(path)?;
127 unsafe {
128 [<$flname _load_file>](self.inner.widget() as _, path.as_ptr());
129 Ok(())
130 }
131 }
132
133 fn text_size(&self) -> i32 {
134 unsafe { [<$flname _text_size>](self.inner.widget() as _) as i32 }
135 }
136
137 fn set_text_size(&mut self, c: i32) {
138 unsafe {
139 [<$flname _set_text_size>](self.inner.widget() as _, c as i32)
140 }
141 }
142
143 fn set_icon<Img: ImageExt>(&mut self, line: i32, image: Option<Img>) {
144 if line > 0 && line <= self.size() + 1 {
145 if let Some(image) = image {
146 assert!(!image.was_deleted());
147 unsafe {
148 [<$flname _set_icon>](
149 self.inner.widget() as _,
150 line as i32,
151 image.as_image_ptr() as *mut _,
152 )
153 }
154 } else {
155 unsafe {
156 [<$flname _set_icon>](
157 self.inner.widget() as _,
158 line as i32,
159 std::ptr::null_mut() as *mut raw::c_void,
160 )
161 }
162 }
163 }
164 }
165
166 fn icon(&self, line: i32) -> Option<Box<dyn ImageExt>> {
167 unsafe {
168 if line > 0 && line <= self.size() + 1 {
169 let image_ptr = [<$flname _icon>](self.inner.widget() as _, line as i32);
170 if image_ptr.is_null() {
171 None
172 } else {
173 let img =
174 $crate::image::Image::from_image_ptr(image_ptr as *mut fltk_sys::image::Fl_Image);
175 Some(Box::new(img))
176 }
177 } else {
178 None
179 }
180 }
181 }
182
183 fn remove_icon(&mut self, line: i32) {
184 unsafe {
185 if line > 0 && line <= self.size() + 1 {
186 [<$flname _remove_icon>](self.inner.widget() as _, line as i32)
187 }
188 }
189 }
190
191 fn top_line(&mut self, line: i32) {
192 if line > 0 && line <= self.size() + 1 {
193 unsafe { [<$flname _topline>](self.inner.widget() as _, line as i32) }
194 }
195 }
196
197 fn bottom_line(&mut self, line: i32) {
198 if line > 0 && line <= self.size() + 1 {
199 unsafe { [<$flname _bottomline>](self.inner.widget() as _, line as i32) }
200 }
201 }
202
203 fn middle_line(&mut self, line: i32) {
204 if line > 0 && line <= self.size() + 1 {
205 unsafe { [<$flname _middleline>](self.inner.widget() as _, line as i32) }
206 }
207 }
208
209 fn format_char(&self) -> char {
210 unsafe { [<$flname _format_char>](self.inner.widget() as _) as u8 as char }
211 }
212
213 fn set_format_char(&mut self, c: char) {
214 debug_assert!(c != 0 as char);
215 let c = if c as i32 > 128 { 128 as char } else { c };
216 unsafe { [<$flname _set_format_char>](self.inner.widget() as _, c as raw::c_char) }
217 }
218
219 fn column_char(&self) -> char {
220 unsafe { [<$flname _column_char>](self.inner.widget() as _) as u8 as char }
221 }
222
223 fn set_column_char(&mut self, c: char) {
224 debug_assert!(c != 0 as char);
225 let c = if c as i32 > 128 { 128 as char } else { c };
226 unsafe { [<$flname _set_column_char>](self.inner.widget() as _, c as raw::c_char) }
227 }
228
229 fn column_widths(&self) -> Vec<i32> {
230 unsafe {
231 let widths = [<$flname _column_widths>](self.inner.widget() as _);
232 assert!(!widths.is_null());
234 let mut v: Vec<i32> = vec![];
235 let mut i = 0;
236 while (*widths.offset(i) != 0) {
237 v.push(*widths.offset(i));
238 i += 1;
239 }
240 v
241 }
242 }
243
244 fn set_column_widths(&mut self, arr: &[i32]) {
245 debug_assert!(!arr.contains(&0), "FLTK uses 0 as a sentinel value for the array/slice. To hide a column, use -1!");
246 unsafe {
247 let old = [<$flname _column_widths>](self.inner.widget() as _);
248 let mut v = arr.to_vec();
249 v.push(0);
250 let v = v.into_boxed_slice();
251 [<$flname _set_column_widths>](self.inner.widget() as _, Box::into_raw(v) as _);
252 if !old.is_null() && *old.offset(0) != 0 {
253 let _ = Box::from_raw(old as *mut i32);
254 }
255 }
256 }
257
258 fn displayed(&self, line: i32) -> bool {
259 if line > 0 && line <= self.size() + 1 {
260 unsafe { [<$flname _displayed>](self.inner.widget() as _, line as i32) != 0 }
261 } else {
262 false
263 }
264 }
265
266 fn make_visible(&mut self, line: i32) {
267 if line > 0 && line <= self.size() + 1 {
268 unsafe { [<$flname _make_visible>](self.inner.widget() as _, line as i32) }
269 }
270 }
271
272 fn vposition(&self) -> i32 {
273 unsafe { [<$flname _position>](self.inner.widget() as _) as i32 }
274 }
275
276 fn set_vposition(&mut self, pos: i32) {
277 unsafe { [<$flname _set_position>](self.inner.widget() as _, pos as i32) }
278 }
279
280 fn hposition(&self) -> i32 {
281 unsafe { [<$flname _hposition>](self.inner.widget() as _) as i32 }
282 }
283
284 fn set_hposition(&mut self, pos: i32) {
285 unsafe { [<$flname _set_hposition>](self.inner.widget() as _, pos as i32) }
286 }
287
288 fn has_scrollbar(&self) -> $crate::browser::BrowserScrollbar {
289 unsafe { std::mem::transmute([<$flname _has_scrollbar>](self.inner.widget() as _)) }
290 }
291
292 fn set_has_scrollbar(&mut self, mode: $crate::browser::BrowserScrollbar) {
293 unsafe {
294 [<$flname _set_has_scrollbar>](self.inner.widget() as _, mode as raw::c_uchar)
295 }
296 }
297
298 fn scrollbar_size(&self) -> i32 {
299 unsafe { [<$flname _scrollbar_size>](self.inner.widget() as _) as i32 }
300 }
301
302 fn set_scrollbar_size(&mut self, new_size: i32) {
303 unsafe { [<$flname _set_scrollbar_size>](self.inner.widget() as _, new_size as i32) }
304 }
305
306 fn sort(&mut self) {
307 unsafe { [<$flname _sort>](self.inner.widget() as _) }
308 }
309
310 fn scrollbar(&self) -> $crate::valuator::Scrollbar {
311 unsafe {
312 let ptr = [<$flname _scrollbar>](self.inner.widget() as _);
313 assert!(!ptr.is_null());
314 $crate::valuator::Scrollbar::from_widget_ptr(
315 ptr as *mut fltk_sys::widget::Fl_Widget,
316 )
317 }
318 }
319
320 fn hscrollbar(&self) -> $crate::valuator::Scrollbar {
321 unsafe {
322 let ptr = [<$flname _hscrollbar>](self.inner.widget() as _);
323 assert!(!ptr.is_null());
324 $crate::valuator::Scrollbar::from_widget_ptr(
325 ptr as *mut fltk_sys::widget::Fl_Widget,
326 )
327 }
328 }
329
330 fn value(&self) -> i32 {
331 unsafe { [<$flname _value>](self.inner.widget() as _) as i32 }
332 }
333
334 fn set_data<T: Clone + 'static>(&mut self, line: i32, data: T) {
335 if line > 0 && line <= self.size() + 1 {
336 unsafe {
337 [<$flname _set_data>](self.inner.widget() as _, line, Box::into_raw(Box::from(data)) as _);
338 }
339 }
340 }
341
342 unsafe fn data<T: Clone + 'static>(&self, line: i32) -> Option<T> { unsafe {
343 if line > 0 && line <= self.size() + 1 {
344 let ptr = [<$flname _data>](self.inner.widget() as _, line);
345 if ptr.is_null() {
346 None
347 } else {
348 let data = ptr as *const _ as *mut T;
349 Some((*data).clone())
350 }
351 } else {
352 None
353 }
354 }}
355
356 fn hide_line(&mut self, line: i32) {
357 if line > 0 && line <= self.size() + 1 {
358 unsafe { [<$flname _hide_line>](self.inner.widget() as _, line); }
359 }
360 }
361
362 fn selected_items(&self) -> Vec<i32> {
363 let mut temp = vec![];
364 if self.value() > 0 {
365 for i in 1..self.size() + 1 {
366 if self.selected(i) {
367 temp.push(i);
368 }
369 }
370 }
371 temp
372 }
373 }
374 }
375 };
376}
377
378pub use impl_browser_ext;